From 1a4ba03ff5e8e83024c0cf5f7b77c66d379b65e5 Mon Sep 17 00:00:00 2001 From: Aleksandr Gumroian Date: Thu, 21 Apr 2022 15:13:35 +0200 Subject: [PATCH 1/2] Wrap Input component with forwardRef In order to pass `ref` to the child DOM element. --- src/bootstrap/Input.js | 88 +++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/bootstrap/Input.js b/src/bootstrap/Input.js index 658522a..171f312 100644 --- a/src/bootstrap/Input.js +++ b/src/bootstrap/Input.js @@ -1,14 +1,60 @@ /* - * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/) + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) * * This is free software, licensed under the GNU General Public License v3. * See /LICENSE for more information. */ -import React from "react"; +import React, { forwardRef } from "react"; import { useUID } from "react-uid"; import PropTypes from "prop-types"; +/** Base bootstrap input component. */ +export const Input = forwardRef( + ( + { + type, + label, + helpText, + error, + className, + children, + labelClassName, + groupClassName, + ...props + }, + ref + ) => { + const uid = useUID(); + + const inputClassName = `form-control ${className || ""} ${ + error ? "is-invalid" : "" + }`.trim(); + + return ( +
+ +
+ + {children} +
+ {error ?
{error}
: null} + {helpText ? ( + {helpText} + ) : null} +
+ ); + } +); + Input.propTypes = { type: PropTypes.string.isRequired, label: PropTypes.string.isRequired, @@ -22,41 +68,3 @@ Input.propTypes = { labelClassName: PropTypes.string, groupClassName: PropTypes.string, }; - -/** Base bootstrap input component. */ -export function Input({ - type, - label, - helpText, - error, - className, - children, - labelClassName, - groupClassName, - ...props -}) { - const uid = useUID(); - const inputClassName = `form-control ${className || ""} ${ - error ? "is-invalid" : "" - }`.trim(); - return ( -
- -
- - {children} -
- {error ?
{error}
: null} - {helpText ? ( - {helpText} - ) : null} -
- ); -} From 46ce6ebbb906a05355956ee132ca24e04eb26bc5 Mon Sep 17 00:00:00 2001 From: Aleksandr Gumroian Date: Wed, 13 Apr 2022 15:50:08 +0200 Subject: [PATCH 2/2] Add CopyInput bootstrap component --- src/bootstrap/CopyInput.js | 60 ++++++++++++++++++++++++++++++++++++++ src/bootstrap/CopyInput.md | 17 +++++++++++ src/index.js | 1 + 3 files changed, 78 insertions(+) create mode 100644 src/bootstrap/CopyInput.js create mode 100644 src/bootstrap/CopyInput.md diff --git a/src/bootstrap/CopyInput.js b/src/bootstrap/CopyInput.js new file mode 100644 index 0000000..c87329b --- /dev/null +++ b/src/bootstrap/CopyInput.js @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React, { useState, useRef } from "react"; +import PropTypes from "prop-types"; +import { Input } from "./Input"; + +CopyInput.propTypes = { + /** Field label. */ + label: PropTypes.string.isRequired, + /** Field value. */ + value: PropTypes.string, + /** Help text message. */ + helpText: PropTypes.string, + /** Disable input field */ + disabled: PropTypes.bool, + /** Readonly input field */ + readOnly: PropTypes.bool, +}; + +export function CopyInput({ value, ...props }) { + const inputTextRef = useRef(); + const [isCopied, setIsCopied] = useState(false); + + const handleCopyClick = async () => { + // Clipboard API works only in a secure (HTTPS) context. + if (navigator.clipboard) { + await navigator.clipboard.writeText(value); + } else { + // Fallback to the "classic" copy to clipboard implementation. + inputTextRef.current.focus(); + inputTextRef.current.select(); + document.execCommand("copy"); + inputTextRef.current.blur(); + } + + setIsCopied(true); + setTimeout(() => { + setIsCopied(false); + }, 1500); + }; + + return ( + +
+ +
+ + ); +} diff --git a/src/bootstrap/CopyInput.md b/src/bootstrap/CopyInput.md new file mode 100644 index 0000000..dcd6b4c --- /dev/null +++ b/src/bootstrap/CopyInput.md @@ -0,0 +1,17 @@ +CopyInput Bootstrap component contains input with a label, predefined sizes, and +structure for use in ForisForm and the "Copy" button (copy to clipboard). It can +be used with `readOnly` and `disabled` parameters, please see an example. + +All additional `props` are passed to the `` HTML component. + +```js +import React, { useState } from "react"; +const [value, setValue] = useState("Text to appear in clipboard."); + +; +``` diff --git a/src/index.js b/src/index.js index ee7edad..c52f1fa 100644 --- a/src/index.js +++ b/src/index.js @@ -20,6 +20,7 @@ export { API_STATE } from "./api/utils"; export { Alert, ALERT_TYPES } from "./bootstrap/Alert"; export { Button } from "./bootstrap/Button"; export { CheckBox } from "./bootstrap/CheckBox"; +export { CopyInput } from "./bootstrap/CopyInput"; export { DownloadButton } from "./bootstrap/DownloadButton"; export { DataTimeInput } from "./bootstrap/DataTimeInput"; export { EmailInput } from "./bootstrap/EmailInput";