mirror of
				https://gitlab.nic.cz/turris/reforis/foris-js.git
				synced 2025-11-03 23:00:31 +01:00 
			
		
		
		
	Merge branch 'add-threedotsmenu-component' into 'dev'
Add ThreeDotsMenu component See merge request turris/reforis/foris-js!246
This commit is contained in:
		@@ -33,5 +33,4 @@ To install a specific version:
 | 
				
			|||||||
npm install foris@version
 | 
					npm install foris@version
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<a target="_blank" href="https://www.npmjs.com/package/foris">Check
 | 
					[](https://badge.fury.io/js/foris)
 | 
				
			||||||
on<img width="100px" src="./docs/forisjs-npm.svg"></a>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ All additional `props` are passed to the `<input type="email">` HTML component.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
import { useState } from "react";
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import Button from "./Button";
 | 
				
			||||||
const [email, setEmail] = useState("Wrong email");
 | 
					const [email, setEmail] = useState("Wrong email");
 | 
				
			||||||
<form onSubmit={(e) => e.preventDefault()}>
 | 
					<form onSubmit={(e) => e.preventDefault()}>
 | 
				
			||||||
    <EmailInput
 | 
					    <EmailInput
 | 
				
			||||||
@@ -14,6 +15,6 @@ const [email, setEmail] = useState("Wrong email");
 | 
				
			|||||||
        helpText="Read the small text!"
 | 
					        helpText="Read the small text!"
 | 
				
			||||||
        onChange={(event) => setEmail(event.target.value)}
 | 
					        onChange={(event) => setEmail(event.target.value)}
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <button type="submit">Try to submit</button>
 | 
					    <Button type="submit">Try to submit</Button>
 | 
				
			||||||
</form>;
 | 
					</form>;
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								src/bootstrap/Radio.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/bootstrap/Radio.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2024 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 PropTypes from "prop-types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Radio.propTypes = {
 | 
				
			||||||
 | 
					    label: PropTypes.oneOfType([
 | 
				
			||||||
 | 
					        PropTypes.string,
 | 
				
			||||||
 | 
					        PropTypes.element,
 | 
				
			||||||
 | 
					        PropTypes.node,
 | 
				
			||||||
 | 
					        PropTypes.arrayOf(PropTypes.node),
 | 
				
			||||||
 | 
					    ]).isRequired,
 | 
				
			||||||
 | 
					    id: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					    inline: PropTypes.bool,
 | 
				
			||||||
 | 
					    helpText: PropTypes.string,
 | 
				
			||||||
 | 
					    className: PropTypes.string,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Radio({ label, id, helpText, inline, className, ...props }) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <div
 | 
				
			||||||
 | 
					            className={`${className || "mb-3"} ${inline ? "form-check form-check-inline" : ""}`.trim()}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <input
 | 
				
			||||||
 | 
					                id={id}
 | 
				
			||||||
 | 
					                className="form-check-input me-2"
 | 
				
			||||||
 | 
					                type="radio"
 | 
				
			||||||
 | 
					                {...props}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <label className="form-check-label" htmlFor={id}>
 | 
				
			||||||
 | 
					                {label}
 | 
				
			||||||
 | 
					                {helpText && (
 | 
				
			||||||
 | 
					                    <div className="form-text">
 | 
				
			||||||
 | 
					                        <small>{helpText}</small>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
 | 
					            </label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Radio;
 | 
				
			||||||
@@ -10,6 +10,8 @@ import React from "react";
 | 
				
			|||||||
import PropTypes from "prop-types";
 | 
					import PropTypes from "prop-types";
 | 
				
			||||||
import { useUID } from "react-uid";
 | 
					import { useUID } from "react-uid";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Radio from "./Radio";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RadioSet.propTypes = {
 | 
					RadioSet.propTypes = {
 | 
				
			||||||
    /** Name attribute of the input HTML tag. */
 | 
					    /** Name attribute of the input HTML tag. */
 | 
				
			||||||
    name: PropTypes.string.isRequired,
 | 
					    name: PropTypes.string.isRequired,
 | 
				
			||||||
@@ -73,40 +75,4 @@ function RadioSet({ name, label, choices, value, helpText, inline, ...props }) {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Radio.propTypes = {
 | 
					 | 
				
			||||||
    label: PropTypes.oneOfType([
 | 
					 | 
				
			||||||
        PropTypes.string,
 | 
					 | 
				
			||||||
        PropTypes.element,
 | 
					 | 
				
			||||||
        PropTypes.node,
 | 
					 | 
				
			||||||
        PropTypes.arrayOf(PropTypes.node),
 | 
					 | 
				
			||||||
    ]).isRequired,
 | 
					 | 
				
			||||||
    id: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
    inline: PropTypes.bool,
 | 
					 | 
				
			||||||
    helpText: PropTypes.string,
 | 
					 | 
				
			||||||
    className: PropTypes.string,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function Radio({ label, id, helpText, inline, className, ...props }) {
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
            className={`${className || "mb-3"} ${inline ? "form-check form-check-inline" : ""}`.trim()}
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
            <input
 | 
					 | 
				
			||||||
                id={id}
 | 
					 | 
				
			||||||
                className="form-check-input me-2"
 | 
					 | 
				
			||||||
                type="radio"
 | 
					 | 
				
			||||||
                {...props}
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <label className="form-check-label" htmlFor={id}>
 | 
					 | 
				
			||||||
                {label}
 | 
					 | 
				
			||||||
                {helpText && (
 | 
					 | 
				
			||||||
                    <div className="form-text">
 | 
					 | 
				
			||||||
                        <small>{helpText}</small>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                )}
 | 
					 | 
				
			||||||
            </label>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default RadioSet;
 | 
					export default RadioSet;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										42
									
								
								src/bootstrap/ThreeDotsMenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/bootstrap/ThreeDotsMenu.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2024 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 { faEllipsisVertical } from "@fortawesome/free-solid-svg-icons";
 | 
				
			||||||
 | 
					import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 | 
				
			||||||
 | 
					import PropTypes from "prop-types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Button from "./Button";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ThreeDotsMenu.propTypes = {
 | 
				
			||||||
 | 
					    /** Menu items. */
 | 
				
			||||||
 | 
					    children: PropTypes.arrayOf(PropTypes.node).isRequired,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ThreeDotsMenu({ children }) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <div className="dropdown">
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					                className="btn-sm btn-link text-body"
 | 
				
			||||||
 | 
					                data-bs-toggle="dropdown"
 | 
				
			||||||
 | 
					                aria-expanded="false"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <FontAwesomeIcon icon={faEllipsisVertical} />
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					            <ul className="dropdown-menu">
 | 
				
			||||||
 | 
					                {children.map((child) => (
 | 
				
			||||||
 | 
					                    <li key={child.key || child.props.id || Math.random()}>
 | 
				
			||||||
 | 
					                        {child}
 | 
				
			||||||
 | 
					                    </li>
 | 
				
			||||||
 | 
					                ))}
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ThreeDotsMenu;
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/bootstrap/ThreeDotsMenu.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/bootstrap/ThreeDotsMenu.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					ThreeDotsMenu Bootstrap component is a dropdown menu that appears when the user
 | 
				
			||||||
 | 
					clicks on three dots. It is used to display a list of actions that can be
 | 
				
			||||||
 | 
					performed on a particular item.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```js
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 | 
				
			||||||
 | 
					import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const threeDotsMenuItems = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        text: "Edit",
 | 
				
			||||||
 | 
					        icon: faEdit,
 | 
				
			||||||
 | 
					        onClick: () => {
 | 
				
			||||||
 | 
					            alert("Edit clicked");
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        text: "Delete",
 | 
				
			||||||
 | 
					        icon: faTrash,
 | 
				
			||||||
 | 
					        onClick: () => {
 | 
				
			||||||
 | 
					            alert("Delete clicked");
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<ThreeDotsMenu>
 | 
				
			||||||
 | 
					    {threeDotsMenuItems.map((item, index) => (
 | 
				
			||||||
 | 
					        <button key={index} onClick={item.onClick} className="dropdown-item">
 | 
				
			||||||
 | 
					            <FontAwesomeIcon
 | 
				
			||||||
 | 
					                icon={item.icon}
 | 
				
			||||||
 | 
					                className="me-1"
 | 
				
			||||||
 | 
					                width="1rem"
 | 
				
			||||||
 | 
					                size="sm"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            {item.text}
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					    ))}
 | 
				
			||||||
 | 
					</ThreeDotsMenu>;
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
@@ -28,7 +28,8 @@ export { default as FileInput } from "./bootstrap/FileInput";
 | 
				
			|||||||
export { default as Input } from "./bootstrap/Input";
 | 
					export { default as Input } from "./bootstrap/Input";
 | 
				
			||||||
export { default as NumberInput } from "./bootstrap/NumberInput";
 | 
					export { default as NumberInput } from "./bootstrap/NumberInput";
 | 
				
			||||||
export { default as PasswordInput } from "./bootstrap/PasswordInput";
 | 
					export { default as PasswordInput } from "./bootstrap/PasswordInput";
 | 
				
			||||||
export { default as RadioSet, Radio } from "./bootstrap/RadioSet";
 | 
					export { default as Radio } from "./bootstrap/Radio";
 | 
				
			||||||
 | 
					export { default as RadioSet } from "./bootstrap/RadioSet";
 | 
				
			||||||
export { default as Select } from "./bootstrap/Select";
 | 
					export { default as Select } from "./bootstrap/Select";
 | 
				
			||||||
export { default as TextInput } from "./bootstrap/TextInput";
 | 
					export { default as TextInput } from "./bootstrap/TextInput";
 | 
				
			||||||
export { formFieldsSize, buttonFormFieldsSize } from "./bootstrap/constants";
 | 
					export { formFieldsSize, buttonFormFieldsSize } from "./bootstrap/constants";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,7 +65,7 @@ module.exports = {
 | 
				
			|||||||
            components: "src/bootstrap/*.js",
 | 
					            components: "src/bootstrap/*.js",
 | 
				
			||||||
            exampleMode: "expand",
 | 
					            exampleMode: "expand",
 | 
				
			||||||
            usageMode: "expand",
 | 
					            usageMode: "expand",
 | 
				
			||||||
            ignore: ["src/bootstrap/constants.js"],
 | 
					            ignore: ["src/bootstrap/constants.js", "src/bootstrap/Radio.js"],
 | 
				
			||||||
            sectionDepth: 0,
 | 
					            sectionDepth: 0,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
@@ -79,10 +79,7 @@ module.exports = {
 | 
				
			|||||||
            __dirname,
 | 
					            __dirname,
 | 
				
			||||||
            "node_modules/bootstrap/dist/css/bootstrap.min.css"
 | 
					            "node_modules/bootstrap/dist/css/bootstrap.min.css"
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        path.join(
 | 
					        path.join(__dirname, "node_modules/bootstrap/dist/js/bootstrap.min.js"),
 | 
				
			||||||
            __dirname,
 | 
					 | 
				
			||||||
            "node_modules/@fortawesome/fontawesome-free/css/all.min.css"
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    styleguideComponents: {
 | 
					    styleguideComponents: {
 | 
				
			||||||
        LogoRenderer: path.join(__dirname, "docs/components/Logo"),
 | 
					        LogoRenderer: path.join(__dirname, "docs/components/Logo"),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user