mirror of
https://gitlab.nic.cz/turris/reforis/foris-js.git
synced 2025-06-16 13:46:16 +02:00
Format all files with Prettier
This commit is contained in:
@ -35,12 +35,16 @@ Alert.defaultProps = {
|
||||
type: ALERT_TYPES.DANGER,
|
||||
};
|
||||
|
||||
export function Alert({
|
||||
type, onDismiss, children,
|
||||
}) {
|
||||
export function Alert({ type, onDismiss, children }) {
|
||||
return (
|
||||
<div className={`alert alert-dismissible alert-${type}`}>
|
||||
{onDismiss ? <button type="button" className="close" onClick={onDismiss}>×</button> : false}
|
||||
{onDismiss ? (
|
||||
<button type="button" className="close" onClick={onDismiss}>
|
||||
×
|
||||
</button>
|
||||
) : (
|
||||
false
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,21 +1,21 @@
|
||||
Bootstrap alert component.
|
||||
|
||||
```jsx
|
||||
import {useState} from 'react';
|
||||
import { useState } from "react";
|
||||
|
||||
function AlertExample(){
|
||||
function AlertExample() {
|
||||
const [alert, setAlert] = useState(true);
|
||||
if (alert)
|
||||
return <Alert
|
||||
type='warning'
|
||||
onDismiss={()=>setAlert(false)}
|
||||
>
|
||||
Some warning out there!
|
||||
</Alert>;
|
||||
return <button
|
||||
className='btn btn-secondary'
|
||||
onClick={()=>setAlert(true)}
|
||||
>Show alert again</button>;
|
||||
};
|
||||
<AlertExample/>
|
||||
return (
|
||||
<Alert type="warning" onDismiss={() => setAlert(false)}>
|
||||
Some warning out there!
|
||||
</Alert>
|
||||
);
|
||||
return (
|
||||
<button className="btn btn-secondary" onClick={() => setAlert(true)}>
|
||||
Show alert again
|
||||
</button>
|
||||
);
|
||||
}
|
||||
<AlertExample />;
|
||||
```
|
||||
|
@ -25,22 +25,29 @@ Button.propTypes = {
|
||||
};
|
||||
|
||||
export function Button({
|
||||
className, loading, forisFormSize, children, ...props
|
||||
className,
|
||||
loading,
|
||||
forisFormSize,
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
let buttonClass = className ? `btn ${className}` : "btn btn-primary ";
|
||||
if (forisFormSize) {
|
||||
buttonClass = `${buttonClass} col-sm-12 col-md-3 col-lg-2`;
|
||||
}
|
||||
|
||||
const span = loading
|
||||
? <span className="spinner-border spinner-border-sm" role="status" aria-hidden="true" /> : null;
|
||||
const span = loading ? (
|
||||
<span
|
||||
className="spinner-border spinner-border-sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<button type="button" className={buttonClass} {...props}>
|
||||
{span}
|
||||
{" "}
|
||||
{span ? " " : null}
|
||||
{" "}
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
@ -11,5 +11,7 @@ Can be used without parameters:
|
||||
Using loading spinner:
|
||||
|
||||
```jsx
|
||||
<Button loading disabled>Loading...</Button>
|
||||
<Button loading disabled>
|
||||
Loading...
|
||||
</Button>
|
||||
```
|
||||
|
@ -22,9 +22,7 @@ CheckBox.defaultProps = {
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export function CheckBox({
|
||||
label, helpText, disabled, ...props
|
||||
}) {
|
||||
export function CheckBox({ label, helpText, disabled, ...props }) {
|
||||
const uid = useUID();
|
||||
return (
|
||||
<div className="form-group">
|
||||
@ -34,12 +32,15 @@ export function CheckBox({
|
||||
type="checkbox"
|
||||
id={uid}
|
||||
disabled={disabled}
|
||||
|
||||
{...props}
|
||||
/>
|
||||
<label className="custom-control-label" htmlFor={uid}>
|
||||
{label}
|
||||
{helpText && <small className="form-text text-muted">{helpText}</small>}
|
||||
{helpText && (
|
||||
<small className="form-text text-muted">
|
||||
{helpText}
|
||||
</small>
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,16 +1,17 @@
|
||||
Checkbox with label Bootstrap component with predefined sizes and structure for using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="checkbox">` HTML component.
|
||||
Checkbox with label Bootstrap component with predefined sizes and structure for
|
||||
using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="checkbox">` HTML
|
||||
component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
import { useState } from "react";
|
||||
const [value, setValue] = useState(false);
|
||||
|
||||
<CheckBox
|
||||
value={value}
|
||||
label="Some label"
|
||||
label="Some label"
|
||||
helpText="Read the small text!"
|
||||
onChange={event =>setValue(event.target.value)}
|
||||
/>
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>;
|
||||
```
|
||||
|
@ -38,14 +38,17 @@ const DEFAULT_DATE_FORMAT = "YYYY-MM-DD";
|
||||
const DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
export function DataTimeInput({
|
||||
value, onChange, isValidDate, dateFormat, timeFormat, children, ...props
|
||||
value,
|
||||
onChange,
|
||||
isValidDate,
|
||||
dateFormat,
|
||||
timeFormat,
|
||||
children,
|
||||
...props
|
||||
}) {
|
||||
function renderInput(datetimeProps) {
|
||||
return (
|
||||
<Input
|
||||
{...props}
|
||||
{...datetimeProps}
|
||||
>
|
||||
<Input {...props} {...datetimeProps}>
|
||||
{children}
|
||||
</Input>
|
||||
);
|
||||
@ -54,8 +57,12 @@ export function DataTimeInput({
|
||||
return (
|
||||
<Datetime
|
||||
locale={ForisTranslations.locale}
|
||||
dateFormat={dateFormat !== undefined ? dateFormat : DEFAULT_DATE_FORMAT}
|
||||
timeFormat={timeFormat !== undefined ? timeFormat : DEFAULT_TIME_FORMAT}
|
||||
dateFormat={
|
||||
dateFormat !== undefined ? dateFormat : DEFAULT_DATE_FORMAT
|
||||
}
|
||||
timeFormat={
|
||||
timeFormat !== undefined ? timeFormat : DEFAULT_TIME_FORMAT
|
||||
}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
isValidDate={isValidDate}
|
||||
|
@ -1,25 +1,26 @@
|
||||
Adopted from `react-datetime/DateTime` datatime picker component.
|
||||
It uses `momentjs` see example.
|
||||
Adopted from `react-datetime/DateTime` datatime picker component. It uses
|
||||
`momentjs` see example.
|
||||
|
||||
It requires `ForisTranslations.locale` to be defined in order to use right locale.
|
||||
It requires `ForisTranslations.locale` to be defined in order to use right
|
||||
locale.
|
||||
|
||||
```js
|
||||
ForisTranslations={locale:'en'};
|
||||
ForisTranslations = { locale: "en" };
|
||||
|
||||
import {useState, useEffect} from 'react';
|
||||
import moment from 'moment/moment';
|
||||
import { useState, useEffect } from "react";
|
||||
import moment from "moment/moment";
|
||||
|
||||
const [dataTime, setDataTime] = useState(moment());
|
||||
const [error, setError] = useState();
|
||||
useEffect(()=>{
|
||||
dataTime.isValid() ? setError(null) : setError('Invalid value!');
|
||||
},[dataTime]);
|
||||
|
||||
useEffect(() => {
|
||||
dataTime.isValid() ? setError(null) : setError("Invalid value!");
|
||||
}, [dataTime]);
|
||||
|
||||
<DataTimeInput
|
||||
label='Time to sleep'
|
||||
label="Time to sleep"
|
||||
value={dataTime}
|
||||
error={error}
|
||||
helpText='Example helptext...'
|
||||
onChange={value => setDataTime(value)}
|
||||
/>
|
||||
helpText="Example helptext..."
|
||||
onChange={(value) => setDataTime(value)}
|
||||
/>;
|
||||
```
|
||||
|
@ -23,11 +23,7 @@ DownloadButton.defaultProps = {
|
||||
|
||||
export function DownloadButton({ href, className, children }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className={`btn ${className}`.trim()}
|
||||
download
|
||||
>
|
||||
<a href={href} className={`btn ${className}`.trim()} download>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
@ -1,6 +1,9 @@
|
||||
Hyperlink with apperance of a button.
|
||||
|
||||
It has `download` attribute, which prevents closing WebSocket connection on Firefox. See [related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more details.
|
||||
It has `download` attribute, which prevents closing WebSocket connection on
|
||||
Firefox. See
|
||||
[related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more
|
||||
details.
|
||||
|
||||
```js
|
||||
<DownloadButton href="example.zip">Download</DownloadButton>
|
||||
|
@ -1,18 +1,19 @@
|
||||
Bootstrap component of email input with label with predefined sizes and structure for using in foris forms.
|
||||
It use built-in browser email address checking. It's only meaningful using inside `<form>`.
|
||||
Bootstrap component of email input with label with predefined sizes and
|
||||
structure for using in foris forms. It use built-in browser email address
|
||||
checking. It's only meaningful using inside `<form>`.
|
||||
|
||||
All additional `props` are passed to the `<input type="email">` HTML component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
const [email, setEmail] = useState('Wrong email');
|
||||
<form onSubmit={e=>e.preventDefault()}>
|
||||
import { useState } from "react";
|
||||
const [email, setEmail] = useState("Wrong email");
|
||||
<form onSubmit={(e) => e.preventDefault()}>
|
||||
<EmailInput
|
||||
value={email}
|
||||
label="Some label"
|
||||
label="Some label"
|
||||
helpText="Read the small text!"
|
||||
onChange={event =>setEmail(event.target.value)}
|
||||
onChange={(event) => setEmail(event.target.value)}
|
||||
/>
|
||||
<button type="submit">Try to submit</button>
|
||||
</form>
|
||||
</form>;
|
||||
```
|
||||
|
@ -1,9 +1,10 @@
|
||||
Bootstrap component for file input. Includes label and has predefined sizes and structure for using in foris forms.
|
||||
Bootstrap component for file input. Includes label and has predefined sizes and
|
||||
structure for using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="file">` HTML component.
|
||||
|
||||
```js
|
||||
import { useState } from 'react';
|
||||
import { useState } from "react";
|
||||
|
||||
const [files, setFiles] = useState([]);
|
||||
|
||||
@ -15,27 +16,33 @@ const label = files.length === 1 ? files[0].name : "Choose file";
|
||||
files={files}
|
||||
label={label}
|
||||
helpText="Will be uploaded"
|
||||
onChange={event=>setFiles(event.target.files)}
|
||||
onChange={(event) => setFiles(event.target.files)}
|
||||
/>
|
||||
</form>
|
||||
</form>;
|
||||
```
|
||||
|
||||
### FileInput with multiple files
|
||||
|
||||
```js
|
||||
import { useState } from 'react';
|
||||
import { useState } from "react";
|
||||
|
||||
const [files, setFiles] = useState([]);
|
||||
|
||||
// Note that files is not an array but FileList.
|
||||
const label = files.length > 0 ? Array.from(files).map(file=>file.name).join(", ") : "Choose files";
|
||||
const label =
|
||||
files.length > 0
|
||||
? Array.from(files)
|
||||
.map((file) => file.name)
|
||||
.join(", ")
|
||||
: "Choose files";
|
||||
|
||||
<form className="col">
|
||||
<FileInput
|
||||
files={files}
|
||||
label={label}
|
||||
helpText="Will be uploaded"
|
||||
onChange={event=>setFiles(event.target.files)}
|
||||
onChange={(event) => setFiles(event.target.files)}
|
||||
multiple
|
||||
/>
|
||||
</form>
|
||||
</form>;
|
||||
```
|
||||
|
@ -25,25 +25,38 @@ Input.propTypes = {
|
||||
|
||||
/** Base bootstrap input component. */
|
||||
export function Input({
|
||||
type, label, helpText, error, className, children, labelClassName, groupClassName, ...props
|
||||
type,
|
||||
label,
|
||||
helpText,
|
||||
error,
|
||||
className,
|
||||
children,
|
||||
labelClassName,
|
||||
groupClassName,
|
||||
...props
|
||||
}) {
|
||||
const uid = useUID();
|
||||
const inputClassName = `form-control ${className || ""} ${(error ? "is-invalid" : "")}`.trim();
|
||||
const inputClassName = `form-control ${className || ""} ${
|
||||
error ? "is-invalid" : ""
|
||||
}`.trim();
|
||||
return (
|
||||
<div className="form-group">
|
||||
<label className={labelClassName} htmlFor={uid}>{label}</label>
|
||||
<label className={labelClassName} htmlFor={uid}>
|
||||
{label}
|
||||
</label>
|
||||
<div className={`input-group ${groupClassName || ""}`.trim()}>
|
||||
<input
|
||||
className={inputClassName}
|
||||
type={type}
|
||||
id={uid}
|
||||
|
||||
{...props}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
{error ? <div className="invalid-feedback">{error}</div> : null}
|
||||
{helpText ? <small className="form-text text-muted">{helpText}</small> : null}
|
||||
{helpText ? (
|
||||
<small className="form-text text-muted">{helpText}</small>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -10,6 +10,6 @@
|
||||
.modal.show {
|
||||
display: block;
|
||||
animation-name: modalFade;
|
||||
animation-duration: .3s;
|
||||
animation-duration: 0.3s;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
@ -26,9 +26,7 @@ Modal.propTypes = {
|
||||
]).isRequired,
|
||||
};
|
||||
|
||||
export function Modal({
|
||||
shown, setShown, scrollable, children,
|
||||
}) {
|
||||
export function Modal({ shown, setShown, scrollable, children }) {
|
||||
const dialogRef = useRef();
|
||||
|
||||
useClickOutside(dialogRef, () => setShown(false));
|
||||
@ -38,12 +36,12 @@ export function Modal({
|
||||
<div className={`modal fade ${shown ? "show" : ""}`} role="dialog">
|
||||
<div
|
||||
ref={dialogRef}
|
||||
className={`modal-dialog modal-dialog-centered${scrollable ? " modal-dialog-scrollable" : ""}`}
|
||||
className={`modal-dialog modal-dialog-centered${
|
||||
scrollable ? " modal-dialog-scrollable" : ""
|
||||
}`}
|
||||
role="document"
|
||||
>
|
||||
<div className="modal-content">
|
||||
{children}
|
||||
</div>
|
||||
<div className="modal-content">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Portal>
|
||||
@ -59,7 +57,11 @@ export function ModalHeader({ setShown, title }) {
|
||||
return (
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title">{title}</h5>
|
||||
<button type="button" className="close" onClick={() => setShown(false)}>
|
||||
<button
|
||||
type="button"
|
||||
className="close"
|
||||
onClick={() => setShown(false)}
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -85,9 +87,5 @@ ModalFooter.propTypes = {
|
||||
};
|
||||
|
||||
export function ModalFooter({ children }) {
|
||||
return (
|
||||
<div className="modal-footer">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
return <div className="modal-footer">{children}</div>;
|
||||
}
|
||||
|
@ -1,31 +1,36 @@
|
||||
Bootstrap modal component.
|
||||
|
||||
it's required to have an element `<div id={"modal-container"}/>` somewhere on the page since modals are rendered in portals.
|
||||
it's required to have an element `<div id={"modal-container"}/>` somewhere on
|
||||
the page since modals are rendered in portals.
|
||||
|
||||
```js
|
||||
<div id="modal-container"/>
|
||||
<div id="modal-container" />
|
||||
```
|
||||
|
||||
```js
|
||||
import {ModalHeader, ModalBody, ModalFooter} from './Modal';
|
||||
import { ModalHeader, ModalBody, ModalFooter } from "./Modal";
|
||||
|
||||
import {useState} from 'react';
|
||||
import { useState } from "react";
|
||||
const [shown, setShown] = useState(false);
|
||||
|
||||
<>
|
||||
<Modal setShown={setShown} shown={shown}>
|
||||
<ModalHeader setShown={setShown} title='Warning!'/>
|
||||
<ModalBody><p>Bla bla bla...</p></ModalBody>
|
||||
<ModalHeader setShown={setShown} title="Warning!" />
|
||||
<ModalBody>
|
||||
<p>Bla bla bla...</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<button
|
||||
className='btn btn-secondary'
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
onClick={() => setShown(false)}
|
||||
>Skip it</button>
|
||||
>
|
||||
Skip it
|
||||
</button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
||||
<button className='btn btn-secondary' onClick={()=>setShown(true)}>
|
||||
|
||||
<button className="btn btn-secondary" onClick={() => setShown(true)}>
|
||||
Show modal
|
||||
</button>
|
||||
</>
|
||||
</>;
|
||||
```
|
||||
|
@ -4,7 +4,7 @@ input[type="number"] {
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
@ -20,10 +20,7 @@ NumberInput.propTypes = {
|
||||
/** Help text message. */
|
||||
helpText: PropTypes.string,
|
||||
/** Number value. */
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]),
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
/** Function called when value changes. */
|
||||
onChange: PropTypes.func.isRequired,
|
||||
/** Additional description dispaled to the right of input value. */
|
||||
@ -34,15 +31,21 @@ NumberInput.defaultProps = {
|
||||
value: 0,
|
||||
};
|
||||
|
||||
export function NumberInput({
|
||||
onChange, inlineText, value, ...props
|
||||
}) {
|
||||
export function NumberInput({ onChange, inlineText, value, ...props }) {
|
||||
function updateValue(initialValue, difference) {
|
||||
onChange({ target: { value: initialValue + difference } });
|
||||
}
|
||||
|
||||
const enableIncrease = useConditionalTimeout({ callback: updateValue }, value, 1);
|
||||
const enableDecrease = useConditionalTimeout({ callback: updateValue }, value, -1);
|
||||
const enableIncrease = useConditionalTimeout(
|
||||
{ callback: updateValue },
|
||||
value,
|
||||
1
|
||||
);
|
||||
const enableDecrease = useConditionalTimeout(
|
||||
{ callback: updateValue },
|
||||
value,
|
||||
-1
|
||||
);
|
||||
|
||||
return (
|
||||
<Input type="number" onChange={onChange} value={value} {...props}>
|
||||
|
@ -1,17 +1,18 @@
|
||||
Bootstrap component of number input with label with predefined sizes and structure for using in foris forms.
|
||||
Bootstrap component of number input with label with predefined sizes and
|
||||
structure for using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="number">` HTML component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
import { useState } from "react";
|
||||
const [value, setValue] = useState(42);
|
||||
|
||||
<NumberInput
|
||||
value={value}
|
||||
label="Some number"
|
||||
label="Some number"
|
||||
helpText="Read the small text!"
|
||||
min='33'
|
||||
max='54'
|
||||
onChange={event =>setValue(event.target.value)}
|
||||
/>
|
||||
min="33"
|
||||
max="54"
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>;
|
||||
```
|
||||
|
@ -31,22 +31,24 @@ export function PasswordInput({ withEye, ...props }) {
|
||||
autoComplete={isHidden ? "new-password" : null}
|
||||
{...props}
|
||||
>
|
||||
{withEye
|
||||
? (
|
||||
<div className="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
className="input-group-text"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setHidden((shouldBeHidden) => !shouldBeHidden);
|
||||
}}
|
||||
>
|
||||
<i className={`fa ${isHidden ? "fa-eye" : "fa-eye-slash"}`} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
: null}
|
||||
{withEye ? (
|
||||
<div className="input-group-append">
|
||||
<button
|
||||
type="button"
|
||||
className="input-group-text"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setHidden((shouldBeHidden) => !shouldBeHidden);
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className={`fa ${
|
||||
isHidden ? "fa-eye" : "fa-eye-slash"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</Input>
|
||||
);
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
Password Bootstrap component input with label and predefined sizes and structure for using in foris forms.
|
||||
Can be used with "eye" button, see example.
|
||||
Password Bootstrap component input with label and predefined sizes and structure
|
||||
for using in foris forms. Can be used with "eye" button, see example.
|
||||
|
||||
All additional `props` are passed to the `<input type="password">` HTML component.
|
||||
All additional `props` are passed to the `<input type="password">` HTML
|
||||
component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
const [value, setValue] = useState('secret');
|
||||
import { useState } from "react";
|
||||
const [value, setValue] = useState("secret");
|
||||
|
||||
<PasswordInput
|
||||
withEye
|
||||
value={value}
|
||||
label="Some password"
|
||||
label="Some password"
|
||||
helpText="Read the small text!"
|
||||
onChange={event =>setValue(event.target.value)}
|
||||
/>
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>;
|
||||
```
|
||||
|
@ -15,26 +15,27 @@ RadioSet.propTypes = {
|
||||
/** RadioSet label . */
|
||||
label: PropTypes.string,
|
||||
/** Choices . */
|
||||
choices: PropTypes.arrayOf(PropTypes.shape({
|
||||
/** Choice lable . */
|
||||
label: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.element,
|
||||
PropTypes.node,
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
]).isRequired,
|
||||
/** Choice value . */
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
})).isRequired,
|
||||
choices: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
/** Choice lable . */
|
||||
label: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.element,
|
||||
PropTypes.node,
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
]).isRequired,
|
||||
/** Choice value . */
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
.isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
/** Initial value . */
|
||||
value: PropTypes.string,
|
||||
/** Help text message . */
|
||||
helpText: PropTypes.string,
|
||||
};
|
||||
|
||||
export function RadioSet({
|
||||
name, label, choices, value, helpText, ...props
|
||||
}) {
|
||||
export function RadioSet({ name, label, choices, value, helpText, ...props }) {
|
||||
const uid = useUID();
|
||||
const radios = choices.map((choice, key) => {
|
||||
const id = `${name}-${key}`;
|
||||
@ -47,7 +48,6 @@ export function RadioSet({
|
||||
value={choice.value}
|
||||
helpText={choice.helpText}
|
||||
checked={choice.value === value}
|
||||
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@ -55,9 +55,15 @@ export function RadioSet({
|
||||
|
||||
return (
|
||||
<div className="form-group">
|
||||
{label && <label htmlFor={uid} className="d-block">{label}</label>}
|
||||
{label && (
|
||||
<label htmlFor={uid} className="d-block">
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
{radios}
|
||||
{helpText && <small className="form-text text-muted">{helpText}</small>}
|
||||
{helpText && (
|
||||
<small className="form-text text-muted">{helpText}</small>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -73,21 +79,28 @@ Radio.propTypes = {
|
||||
helpText: PropTypes.string,
|
||||
};
|
||||
|
||||
export function Radio({
|
||||
label, id, helpText, ...props
|
||||
}) {
|
||||
export function Radio({ label, id, helpText, ...props }) {
|
||||
return (
|
||||
<>
|
||||
<div className={`custom-control custom-radio ${!helpText ? "custom-control-inline" : ""}`.trim()}>
|
||||
<div
|
||||
className={`custom-control custom-radio ${
|
||||
!helpText ? "custom-control-inline" : ""
|
||||
}`.trim()}
|
||||
>
|
||||
<input
|
||||
id={id}
|
||||
className="custom-control-input"
|
||||
type="radio"
|
||||
|
||||
{...props}
|
||||
/>
|
||||
<label className="custom-control-label" htmlFor={id}>{label}</label>
|
||||
{helpText && <small className="form-text text-muted mt-0 mb-3">{helpText}</small>}
|
||||
<label className="custom-control-label" htmlFor={id}>
|
||||
{label}
|
||||
</label>
|
||||
{helpText && (
|
||||
<small className="form-text text-muted mt-0 mb-3">
|
||||
{helpText}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -1,15 +1,16 @@
|
||||
Set of radio Bootstrap component input with label and predefined sizes and structure for using in foris forms.
|
||||
Set of radio Bootstrap component input with label and predefined sizes and
|
||||
structure for using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="number">` HTML component.
|
||||
|
||||
Unless `helpText` is set for one of the options they are displayed inline.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
const CHOICES=[
|
||||
{value:'one',label:'1'},
|
||||
{value:'two',label:'2'},
|
||||
{value:'three',label:'3'},
|
||||
import { useState } from "react";
|
||||
const CHOICES = [
|
||||
{ value: "one", label: "1" },
|
||||
{ value: "two", label: "2" },
|
||||
{ value: "three", label: "3" },
|
||||
];
|
||||
const [value, setValue] = useState(CHOICES[0].value);
|
||||
|
||||
@ -17,10 +18,10 @@ const [value, setValue] = useState(CHOICES[0].value);
|
||||
{/*Yeah, it gets event, not value!*/}
|
||||
<RadioSet
|
||||
value={value}
|
||||
name='some-radio'
|
||||
name="some-radio"
|
||||
choices={CHOICES}
|
||||
onChange={event =>setValue(event.target.value)}
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
<p>Selected value: {value}</p>
|
||||
</>
|
||||
</>;
|
||||
```
|
||||
|
@ -15,35 +15,30 @@ Select.propTypes = {
|
||||
/** Choices if form of {value : "Label",...}. */
|
||||
choices: PropTypes.object.isRequired,
|
||||
/** Current value. */
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]).isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
/** Help text message. */
|
||||
helpText: PropTypes.string,
|
||||
};
|
||||
|
||||
export function Select({
|
||||
label, choices, helpText, ...props
|
||||
}) {
|
||||
export function Select({ label, choices, helpText, ...props }) {
|
||||
const uid = useUID();
|
||||
|
||||
const options = Object.keys(choices).sort(
|
||||
(a, b) => a - b || a.toString().localeCompare(b.toString()),
|
||||
).map(
|
||||
(key) => <option key={key} value={key}>{choices[key]}</option>,
|
||||
);
|
||||
const options = Object.keys(choices)
|
||||
.sort((a, b) => a - b || a.toString().localeCompare(b.toString()))
|
||||
.map((key) => (
|
||||
<option key={key} value={key}>
|
||||
{choices[key]}
|
||||
</option>
|
||||
));
|
||||
return (
|
||||
<div className="form-group">
|
||||
<label htmlFor={uid}>{label}</label>
|
||||
<select
|
||||
className="custom-select"
|
||||
id={uid}
|
||||
{...props}
|
||||
>
|
||||
<select className="custom-select" id={uid} {...props}>
|
||||
{options}
|
||||
</select>
|
||||
{helpText ? <small className="form-text text-muted">{helpText}</small> : null}
|
||||
{helpText ? (
|
||||
<small className="form-text text-muted">{helpText}</small>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
Select with options Bootstrap component input with label and predefined sizes and structure for using in foris forms.
|
||||
Select with options Bootstrap component input with label and predefined sizes
|
||||
and structure for using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<select>` HTML component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
const CHOICES={
|
||||
apple:'Apple',
|
||||
banana:'Banana',
|
||||
peach:'Peach',
|
||||
import { useState } from "react";
|
||||
const CHOICES = {
|
||||
apple: "Apple",
|
||||
banana: "Banana",
|
||||
peach: "Peach",
|
||||
};
|
||||
const [value, setValue] = useState(Object.keys(CHOICES)[0]);
|
||||
|
||||
@ -17,9 +18,9 @@ const [value, setValue] = useState(Object.keys(CHOICES)[0]);
|
||||
label="Fruit"
|
||||
value={value}
|
||||
choices={CHOICES}
|
||||
onChange={event=>setValue(event.target.value)}
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>
|
||||
<p>Selected choice label: {CHOICES[value]}</p>
|
||||
<p>Selected choice value: {value}</p>
|
||||
</>
|
||||
</>;
|
||||
```
|
||||
|
@ -5,7 +5,7 @@
|
||||
}
|
||||
|
||||
.spinner-fs-background {
|
||||
background-color: rgba(2, 2, 2, .5);
|
||||
background-color: rgba(2, 2, 2, 0.5);
|
||||
color: rgb(230, 230, 230);
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
|
@ -25,12 +25,12 @@ Spinner.defaultProps = {
|
||||
fullScreen: false,
|
||||
};
|
||||
|
||||
export function Spinner({
|
||||
fullScreen, children, className,
|
||||
}) {
|
||||
export function Spinner({ fullScreen, children, className }) {
|
||||
if (!fullScreen) {
|
||||
return (
|
||||
<div className={`spinner-wrapper ${className || "my-3 text-center"}`}>
|
||||
<div
|
||||
className={`spinner-wrapper ${className || "my-3 text-center"}`}
|
||||
>
|
||||
<SpinnerElement>{children}</SpinnerElement>
|
||||
</div>
|
||||
);
|
||||
@ -61,7 +61,9 @@ export function SpinnerElement({ small, className, children }) {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`spinner-border ${small ? "spinner-border-sm" : ""} ${className || ""}`.trim()}
|
||||
className={`spinner-border ${
|
||||
small ? "spinner-border-sm" : ""
|
||||
} ${className || ""}`.trim()}
|
||||
role="status"
|
||||
>
|
||||
<span className="sr-only" />
|
||||
|
@ -16,29 +16,33 @@ Switch.propTypes = {
|
||||
PropTypes.node,
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
]).isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
helpText: PropTypes.string,
|
||||
switchHeading: PropTypes.string,
|
||||
switchHeading: PropTypes.bool,
|
||||
};
|
||||
|
||||
export function Switch({
|
||||
label, id, helpText, switchHeading, ...props
|
||||
}) {
|
||||
export function Switch({ label, helpText, switchHeading, ...props }) {
|
||||
const uid = useUID();
|
||||
return (
|
||||
<div className="form-group">
|
||||
<div className={`custom-control custom-switch ${!helpText ? "custom-control-inline" : ""} ${switchHeading ? "switch-heading" : ""}`.trim()}>
|
||||
<div
|
||||
className={`custom-control custom-switch ${
|
||||
!helpText ? "custom-control-inline" : ""
|
||||
} ${switchHeading ? "switch-heading" : ""}`.trim()}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
className="custom-control-input"
|
||||
id={uid}
|
||||
|
||||
{...props}
|
||||
/>
|
||||
<label className="custom-control-label" htmlFor={uid}>
|
||||
{label}
|
||||
</label>
|
||||
{helpText && <small className="form-text text-muted mt-0 mb-3">{helpText}</small>}
|
||||
{helpText && (
|
||||
<small className="form-text text-muted mt-0 mb-3">
|
||||
{helpText}
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,15 +1,16 @@
|
||||
Text Bootstrap component input with label and predefined sizes and structure for using in foris forms.
|
||||
Text Bootstrap component input with label and predefined sizes and structure for
|
||||
using in foris forms.
|
||||
|
||||
All additional `props` are passed to the `<input type="text">` HTML component.
|
||||
|
||||
```js
|
||||
import {useState} from 'react';
|
||||
const [value, setValue] = useState('Bla bla');
|
||||
import { useState } from "react";
|
||||
const [value, setValue] = useState("Bla bla");
|
||||
|
||||
<TextInput
|
||||
value={value}
|
||||
label="Some text"
|
||||
label="Some text"
|
||||
helpText="Read the small text!"
|
||||
onChange={event =>setValue(event.target.value)}
|
||||
/>
|
||||
onChange={(event) => setValue(event.target.value)}
|
||||
/>;
|
||||
```
|
||||
|
@ -14,19 +14,18 @@ import { Button } from "../Button";
|
||||
describe("<Button />", () => {
|
||||
it("Render button correctly", () => {
|
||||
const { container } = render(<Button>Test Button</Button>);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Render button with custom classes", () => {
|
||||
const { container } = render(<Button className="one two three">Test Button</Button>);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
const { container } = render(
|
||||
<Button className="one two three">Test Button</Button>
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Render button with spinner", () => {
|
||||
const { container } = render(<Button loading>Test Button</Button>);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -18,22 +18,16 @@ describe("<Checkbox/>", () => {
|
||||
label="Test label"
|
||||
checked
|
||||
helpText="Some help text"
|
||||
onChange={() => {
|
||||
}}
|
||||
/>,
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Render uncheked checkbox", () => {
|
||||
const { container } = render(
|
||||
<CheckBox
|
||||
label="Test label"
|
||||
helpText="Some help text"
|
||||
/>,
|
||||
<CheckBox label="Test label" helpText="Some help text" />
|
||||
);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,11 @@ import { DownloadButton } from "../DownloadButton";
|
||||
|
||||
describe("<DownloadButton />", () => {
|
||||
it("should have download attribute", () => {
|
||||
const { container } = render(<DownloadButton href="http://example.com">Test Button</DownloadButton>);
|
||||
const { container } = render(
|
||||
<DownloadButton href="http://example.com">
|
||||
Test Button
|
||||
</DownloadButton>
|
||||
);
|
||||
expect(container.firstChild.getAttribute("download")).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
@ -7,9 +7,7 @@
|
||||
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
render, fireEvent, getByLabelText, wait,
|
||||
} from "customTestRender";
|
||||
import { render, fireEvent, getByLabelText, wait } from "customTestRender";
|
||||
|
||||
import { NumberInput } from "../NumberInput";
|
||||
|
||||
@ -24,7 +22,7 @@ describe("<NumberInput/>", () => {
|
||||
helpText="Some help text"
|
||||
value={1}
|
||||
onChange={onChangeMock}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
componentContainer = container;
|
||||
});
|
||||
@ -36,12 +34,16 @@ describe("<NumberInput/>", () => {
|
||||
it("Increase number with button", async () => {
|
||||
const increaseButton = getByLabelText(componentContainer, "Increase");
|
||||
fireEvent.mouseDown(increaseButton);
|
||||
await wait(() => expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 2 } }));
|
||||
await wait(() =>
|
||||
expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 2 } })
|
||||
);
|
||||
});
|
||||
|
||||
it("Decrease number with button", async () => {
|
||||
const decreaseButton = getByLabelText(componentContainer, "Decrease");
|
||||
fireEvent.mouseDown(decreaseButton);
|
||||
await wait(() => expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 0 } }));
|
||||
await wait(() =>
|
||||
expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 0 } })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -18,11 +18,9 @@ describe("<PasswordInput/>", () => {
|
||||
label="Test label"
|
||||
helpText="Some help text"
|
||||
value="Some password"
|
||||
onChange={() => {
|
||||
}}
|
||||
/>,
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -35,11 +35,9 @@ describe("<RadioSet/>", () => {
|
||||
value="value"
|
||||
choices={TEST_CHOICES}
|
||||
helpText="Some help text"
|
||||
onChange={() => {
|
||||
}}
|
||||
/>,
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -8,7 +8,10 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
fireEvent, getByDisplayValue, getByText, render,
|
||||
fireEvent,
|
||||
getByDisplayValue,
|
||||
getByText,
|
||||
render,
|
||||
} from "customTestRender";
|
||||
|
||||
import { Select } from "../Select";
|
||||
@ -29,29 +32,24 @@ describe("<Select/>", () => {
|
||||
value="1"
|
||||
choices={TEST_CHOICES}
|
||||
helpText="Help text"
|
||||
|
||||
onChange={onChangeHandler}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
selectContainer = container;
|
||||
});
|
||||
|
||||
it("Test with snapshot.", () => {
|
||||
expect(selectContainer)
|
||||
.toMatchSnapshot();
|
||||
expect(selectContainer).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Test onChange handling.", () => {
|
||||
const select = getByDisplayValue(selectContainer, "one");
|
||||
expect(select.value)
|
||||
.toBe("1");
|
||||
expect(select.value).toBe("1");
|
||||
fireEvent.change(select, { target: { value: "2" } });
|
||||
|
||||
const option = getByText(selectContainer, "two");
|
||||
expect(onChangeHandler)
|
||||
.toBeCalled();
|
||||
expect(onChangeHandler).toBeCalled();
|
||||
|
||||
expect(option.value)
|
||||
.toBe("2");
|
||||
expect(option.value).toBe("2");
|
||||
});
|
||||
});
|
||||
|
@ -18,11 +18,9 @@ describe("<TextInput/>", () => {
|
||||
label="Test label"
|
||||
helpText="Some help text"
|
||||
value="Some text"
|
||||
onChange={() => {
|
||||
}}
|
||||
/>,
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(container.firstChild)
|
||||
.toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -5,8 +5,6 @@ exports[`<Button /> Render button correctly 1`] = `
|
||||
class="btn btn-primary "
|
||||
type="button"
|
||||
>
|
||||
|
||||
|
||||
Test Button
|
||||
</button>
|
||||
`;
|
||||
@ -16,8 +14,6 @@ exports[`<Button /> Render button with custom classes 1`] = `
|
||||
class="btn one two three"
|
||||
type="button"
|
||||
>
|
||||
|
||||
|
||||
Test Button
|
||||
</button>
|
||||
`;
|
||||
@ -33,8 +29,6 @@ exports[`<Button /> Render button with spinner 1`] = `
|
||||
role="status"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
Test Button
|
||||
</button>
|
||||
`;
|
||||
|
Reference in New Issue
Block a user