mirror of
https://gitlab.nic.cz/turris/reforis/foris-js.git
synced 2024-12-25 00:11:36 +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:
commit
1fb83e08ea
|
@ -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
|
[![npm version](https://badge.fury.io/js/foris.svg)](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"),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user