From 612af4081bba23c9fcc2f0796dd521108c86a6f7 Mon Sep 17 00:00:00 2001 From: joostdecock Date: Sun, 11 May 2025 17:55:53 +0200 Subject: [PATCH] [react] feat: Added docs for components/Input --- packages/react/components/Account/Apikeys.mjs | 6 +- .../Editor/components/menus/Container.mjs | 6 +- packages/react/components/Input/index.mjs | 841 ++++++++++++------ packages/react/mkdocs.sh | 1 + sites/backend/src/models/flow.mjs | 2 +- .../react/components/input/_examples.js | 152 ++++ .../react/components/input/readme.mdx | 112 ++- 7 files changed, 829 insertions(+), 291 deletions(-) create mode 100644 sites/dev/docs/reference/packages/react/components/input/_examples.js diff --git a/packages/react/components/Account/Apikeys.mjs b/packages/react/components/Account/Apikeys.mjs index 1c1471f261a..77a16f6c87c 100644 --- a/packages/react/components/Account/Apikeys.mjs +++ b/packages/react/components/Account/Apikeys.mjs @@ -27,7 +27,7 @@ import { Uuid } from '@freesewing/react/components/Uuid' import { Popout } from '@freesewing/react/components/Popout' import { ModalWrapper } from '@freesewing/react/components/Modal' import { NumberCircle } from '@freesewing/react/components/Number' -import { StringInput, FormControl, ListInput } from '@freesewing/react/components/Input' +import { StringInput, Fieldset, ListInput } from '@freesewing/react/components/Input' import { DisplayRow } from './shared.mjs' import { CopyToClipboardButton } from '@freesewing/react/components/Button' import { TimeAgo, TimeToGo } from '@freesewing/react/components/Time' @@ -333,7 +333,7 @@ const ExpiryPicker = ({ expires, setExpires }) => { return (
- } @@ -346,7 +346,7 @@ const ExpiryPicker = ({ expires, setExpires }) => { className="tw:daisy-range tw:daisy-range-secondary tw:w-full" onChange={update} /> - +
) } diff --git a/packages/react/components/Editor/components/menus/Container.mjs b/packages/react/components/Editor/components/menus/Container.mjs index 0c7d21f7b70..4a03caa24f2 100644 --- a/packages/react/components/Editor/components/menus/Container.mjs +++ b/packages/react/components/Editor/components/menus/Container.mjs @@ -6,7 +6,7 @@ import React, { useState, useMemo } from 'react' // Components import { SubAccordion } from '../Accordion.mjs' import { EditIcon, GroupIcon, OptionsIcon, ResetIcon } from '@freesewing/react/components/Icon' -import { FormControl } from '@freesewing/react/components/Input' +import { Fieldset } from '@freesewing/react/components/Input' import { MiniTip } from '@freesewing/react/components/Mini' const iconButtonClass = 'tw:daisy-btn tw:daisy-btn-xs tw:daisy-btn-ghost tw:px-0 tw:text-accent' @@ -105,7 +105,7 @@ export const MenuItem = ({ return ( <> - {buttons}} @@ -118,7 +118,7 @@ export const MenuItem = ({ } > - + {config.about ? {config.about} : null} ) diff --git a/packages/react/components/Input/index.mjs b/packages/react/components/Input/index.mjs index b9fbcb83c34..1e322413967 100644 --- a/packages/react/components/Input/index.mjs +++ b/packages/react/components/Input/index.mjs @@ -1,9 +1,11 @@ // Dependencies import { + capitalize, cloudflareImageUrl, measurementAsMm, measurementAsUnits, distanceAsMm, + validateEmail, } from '@freesewing/utils' import { collection } from '@freesewing/collection' import { measurements as measurementsTranslations } from '@freesewing/i18n' @@ -23,24 +25,6 @@ import { Tabs, Tab } from '@freesewing/react/components/Tab' import Markdown from 'react-markdown' /* - * Helper component to display a tab heading - */ -export const _Tab = ({ - id, // The tab ID - label, // A label for the tab, if not set we'll use the ID - activeTab, // Which tab (id) is active - setActiveTab, // Method to set the active tab -}) => ( - -) - -/** * A helper component to render the help link in formcontrol * * @param {string|function| help - The help href of onClick method @@ -66,84 +50,75 @@ const HelpLink = ({ help, Link = false }) => { return null } -/* - * Helper component to wrap a form control with a label +/** + * A component for a fieldset, which wraps form elements and providers labels. + * + * @component + * @param {object} props - All component props + * @param {React.Component} [props.Link = undefined] - A framework specific Link component for client-side routing + * @param {boolean} [props.box = undefined] - Set this to true to render a boxed fieldset + * @param {JSX.Element} props.children - The component children + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {string} [props.forId = ''] - Id of the HTML element we are wrapping + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @returns {JSX.Element} */ -export const FormControl = ({ - label, // the (top-left) label - children, // Children to go inside the form control - labelTR = false, // Optional top-right label - labelBL = false, // Optional bottom-left label - labelBR = false, // Optional bottom-right label - forId = false, // ID of the for element we are wrapping - help = false, // An optional URL/method to link/show help/docs - Link = false, // An optional framework-specific link components -}) => { - if (labelBR && !labelBL) labelBL = - - const topLabelChildren = ( - <> - {label ? ( - - {label} - - ) : ( - - - - )} - {labelTR ? {labelTR} : null} - - ) - const bottomLabelChildren = ( -
- {labelBL ? {labelBL} : null} - {labelBR ? {labelBR} : null} -
- ) - - return ( -
- {forId ? ( - - ) : label ? ( -
{topLabelChildren}
- ) : null} - {children} - {labelBL || labelBR ? ( - forId ? ( - - ) : ( -
{bottomLabelChildren}
- ) - ) : null} -
- ) -} - -/* - * Helper method to wrap content in a button - */ -export const ButtonFrame = ({ - children, // Children of the button - onClick, // onClick handler - active, // Whether or not to render the button as active/selected - accordion = false, // Set this to true to not set a background color when active - dense = false, // Use less padding +export const Fieldset = ({ + Link=false, + box=false, + children, + label=false, + labelBL=false, + labelBR=false, + labelTR=false, + legend=false, + forId='', + help=false, }) => ( +
+ {legend ? ( + + {legend} + + ) : null} +
+ {label ? : null } + {labelTR ? : null } +
+ {children} +
+ {labelBL ? : null } + {labelBR ? : null } +
+
+) + +/** + * A component to wrap content in a button + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.active = false] - Set this to true to render the button as active/selected + * @param {JSX.Element} props.children - The component children + * @param {boolean} [props.dense = false] - Set this to render a more compact variant + * @param {boolean} [props.noBg = false] - Set this to true to not use a background color in active state + * @param {function} props.onClick - The button's onClick handler + * @returns {JSX.Element} + */ +export const ButtonFrame = ({ active, children, dense, noBg, onClick }) => ( ) -/* - * Input for integers +/** + * A component to handle input of numbers + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.inputMode = 'decimal'] - The inputMode of the input + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} [props.max = 225] - The maximum value + * @param {number} [props.min = 0] - The minimum value + * @param {number} props.original - The original value, which detects whether it was changed + * @param {string} props.placeholder - The placeholder text + * @param {number} [props.step = 1] - The input step + * @param {function} props.update - The onChange handler + * @param {function} props.valid - A function that should return whether the value is valid or not + * @returns {JSX.Element} */ export const NumberInput = ({ - label, // Label to use - update, // onChange handler - valid, // Method that should return whether the value is valid or not - current, // The current value - original, // The original value - placeholder, // The placeholder text - id = '', // An id to tie the input to the label - labelBL = false, // Bottom-Left label - labelBR = false, // Bottom-Right label - max = 0, - min = 220, + box = false, + current, + help=false, + inputMode = 'decimal', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + id = '', + legend = false, + max = 225, + min = 0, + original, + placeholder, step = 1, + update, + valid, }) => ( - +
update(evt.target.value)} @@ -185,24 +186,45 @@ export const NumberInput = ({ }`} {...{ max, min, step }} /> - +
) -/* - * Input for strings +/** + * A component to handle input of strings (single-line text) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} props.original - The original value, which detects whether it was changed + * @param {string} props.placeholder - The placeholder text + * @param {function} props.update - The onChange handler + * @param {function} [props.valid = () => true] - A function that should return whether the value is valid or not + * @returns {JSX.Element} */ export const StringInput = ({ - label, // Label to use - update, // onChange handler - valid, // Method that should return whether the value is valid or not - current, // The current value - original, // The original value - placeholder, // The placeholder text - id = '', // An id to tie the input to the label - labelBL = false, // Bottom-Left label - labelBR = false, // Bottom-Right label + box = false, + current, + help=false, + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + id = '', + legend = false, + original, + placeholder, + update, + valid = () => true, }) => ( - +
- +
) -/* - * Input for MFA code +/** + * A component to handle input of MFA codes. Essentially a NumberInput with some default props set. + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.id = 'mfa'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.inputMode = 'numeric'] - The input mode of the input + * @param {string} [props.legend = false] - The fieldset legend + * @param {string} [props.placeholder = 'MFA Code'] - The placeholder text + * @param {function} props.update - The onChange handler + * @param {function} props.valid - A function that should return whether the value is valid or not + * @returns {JSX.Element} */ export const MfaInput = ({ - update, // onChange handler - current, // The current value - id = 'mfa', // An id to tie the input to the label -}) => { - return ( - val.length > 4} - {...{ update, current, id }} - placeholder="MFA Code" - /> - ) -} + box = false, + current, + help=false, + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + id = 'mfa', + inputMode = 'numeric', + legend = false, + placeholder="MFA Code", + update, + valid = (val) => val.length > 4, +}) => ( + +) -/* - * Input for passwords +/** + * A component to handle input of passwords + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.id = 'password'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.legend = false] - The fieldset legend + * @param {string} [placeholder = '¯\\_(ツ)_/¯' - The placeholder text + * @param {function} props.update - The onChange handler + * @param {function} [props.valid = () => true] - A function that should return whether the value is valid or not + * @param {function} [props.onKeyDown = false] - An optional handler to capture keypresses (like enter) + * @returns {JSX.Element} */ export const PasswordInput = ({ - label, // Label to use - update, // onChange handler - valid, // Method that should return whether the value is valid or not - current, // The current value - placeholder = '¯\\_(ツ)_/¯', // The placeholder text - id = '', // An id to tie the input to the label - onKeyDown = false, // Optionall capture certain keys (like enter) + box = false, + current, + help=false, + label = false, + labelBL = false, + labelTR = false, + id = 'password', + legend = false, + placeholder = '¯\\_(ツ)_/¯', + update, + valid = () => true, + onKeyDown = false, }) => { const [reveal, setReveal] = useState(false) const extraProps = onKeyDown ? { onKeyDown } : {} return ( - setReveal(!reveal)} > {reveal ? 'Hide Password' : 'Reveal Password'} @@ -278,26 +344,46 @@ export const PasswordInput = ({ }`} {...extraProps} /> - + ) } -/* - * Input for email addresses +/** + * A component to handle input of email addresses + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} [props.original = ''] - The original value, which detects whether it was changed + * @param {string} [props.placeholder = 'Email Address'] - The placeholder text + * @param {function} props.update - The onChange handler + * @param {function} [props.valid = @freesewing/utils.validateEmail] - A function that should return whether the value is valid or not + * @returns {JSX.Element} */ export const EmailInput = ({ - label, // Label to use - update, // onChange handler - valid, // Method that should return whether the value is valid or not - current, // The current value - original, // The original value - placeholder, // The placeholder text - id = '', // An id to tie the input to the label - labelTR = false, // Top-Right label - labelBL = false, // Bottom-Left label - labelBR = false, // Bottom-Right label + box = false, + current, + help = false, + id = 'email', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + legend = false, + original = '', + update, + placeholder = 'Email Address', + valid = validateEmail, }) => ( - +
- +
) -/* - * Input for designs +/** + * A component to handle input of a design name (a select) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string} [props.firstOption = false] - An optional first option to add to the select + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = 'design'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {function} props.update - The onChange handler + * @returns {JSX.Element} */ export const DesignInput = ({ - label, // Label to use - update, // onChange handler - current, // The current value - firstOption = null, // Any first option to add in addition to designs - id = '', // An id to tie the input to the label -}) => { - return ( - - - - ) -} + box = false, + current, + firstOption = false, + help = false, + id = 'design', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + legend = false, + update, +}) => ( +
+ +
+) -/* - * Input for an image +/** + * A component to handle input of an image + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.active = false] - Set this to true to automatically upload the image + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = 'image'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.imgType = 'showcase'] - The type of image. One of 'showcase' or 'blog' + * @param {string} props.imgSlug - The slug of the image, which is the foldername holding the blog or showcase post + * @param {string} props.imgSubid - Set this id to upload non-main images, should be unique per post (1,2,3,...) + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} props.original - The original value, which allows a reset + * @param {function} props.update - The onChange handler + * @returns {JSX.Element} */ export const ImageInput = ({ - label, // The label - update, // The onChange handler - current, // The current value - original, // The original value - active = false, // Whether or not to upload images - imgType = 'showcase', // The image type - imgSubid, // The image sub-id - imgSlug, // The image slug or other unique identifier to use in the image ID - id = '', // An id to tie the input to the label + active = false, + box = false, + current, + help = false, + id = 'image', + imgSlug, + imgSubid, + imgType = 'showcase', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + legend = false, + update, + original, }) => { const backend = useBackend() const { setLoadingStatus } = useContext(LoadingStatusContext) @@ -372,11 +502,11 @@ export const ImageInput = ({ } if (fromUrl) data.url = img else data.img = img - const result = await backend.uploadAnonImage(data) + const [status, body] = await backend.uploadImageAnon(data) setLoadingStatus([true, 'allDone', true, true]) - if (result.success) { - update(result.data.imgId) - setUploadedId(result.data.imgId) + if (status === 200 && body.result === 'success') { + update(body.imgId) + setUploadedId(body.imgId) } else setLoadingStatus([true, 'backendError', true, false]) } @@ -396,7 +526,7 @@ export const ImageInput = ({ if (current) return ( - +
- +
) return ( - +
)}
- +
) } -/* - * Input for an image that is active (it does upload the image) +/** + * A component to handle input of an image and upload it (active) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = 'image'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.imgType = 'showcase'] - The type of image. One of 'showcase' or 'blog' + * @param {string} props.imgSlug - The slug of the image, which is the foldername holding the blog or showcase post + * @param {string} props.imgSubid - Set this id to upload non-main images, should be unique per post (1,2,3,...) + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} props.original - The original value, which allows a reset + * @param {function} props.update - The onChange handler + * @returns {JSX.Element} */ export const ActiveImageInput = (props) => -/* - * Input for an image that is passive (it does not upload the image) +/** + * A component to handle input of an image and not upload it (inactive) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = 'image'] - Id of the HTML element to link the fieldset labels + * @param {string} [props.imgType = 'showcase'] - The type of image. One of 'showcase' or 'blog' + * @param {string} props.imgSlug - The slug of the image, which is the foldername holding the blog or showcase post + * @param {string} props.imgSubid - Set this id to upload non-main images, should be unique per post (1,2,3,...) + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {number} props.original - The original value, which allows a reset + * @param {function} props.update - The onChange handler + * @returns {JSX.Element} */ export const PassiveImageInput = (props) => -/* - * Input for a list of things to pick from +/** + * A component to handle input of list of items to pick from + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {array} props.list - An array of { val, label, desc } objects to populate the list + * @param {function} props.update - The onChange handler + * @returns {JSX.Element} */ export const ListInput = ({ - update, // the onChange handler - label, // The label - list, // The list of items to present { val, label, desc } - current, // The (value of the) current item + box = false, + current, + help = false, + id = '', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + legend = false, + list, + update, }) => ( - +
{list.map((item, i) => ( update(item.val)}>
@@ -492,26 +680,41 @@ export const ListInput = ({
))} - +
) -/* - * Input for markdown content +/** + * A component to handle input of markdown content + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The (top-left) label + * @param {string} [props.labelBL = 'This field supports markdown'] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {function} props.update - The onChange handler + * @param {string} [props.placeholder = ''] - The placeholder text + * @returns {JSX.Element} */ export const MarkdownInput = ({ - label, // The label - current, // The current value (markdown) - update, // The onChange handler - placeholder, // The placeholder content - id = '', // An id to tie the input to the label - labelBL = false, // Bottom-Left label - labelBR = false, // Bottom-Right label + box = false, + current, + help = false, + id = '', + label = false, + labelBL = 'This field supports markdown', + labelBR = false, + labelTR = false, + legend = false, + update, + placeholder='', }) => ( - +
@@ -531,17 +734,41 @@ export const MarkdownInput = ({
- +
) +/** + * A component to handle input of markdown content + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {string|function} [props.props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {boolean} [props.imperial = false] - Set this to true to render imperial units + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {string} props.m - The measurement ID (name) + * @param {function} props.update - The onChange handler + * @param {number} props.original - The original value, which allows a reset + * @param {string} [props.placeholder = ''] - The placeholder text + * @returns {JSX.Element} + */ export const MeasurementInput = ({ - imperial, // True for imperial, False for metric - m, // The measurement name - original, // The original value - update, // The onChange handler - placeholder, // The placeholder content - id = '', // An id to tie the input to the label - helpProvider = false, // a function that provides a url or an action to display help for a measurement + box = false, + current, + help = false, + id = '', + imperial = false, + labelBR = false, + labelTR = false, + legend = false, + m, + update, + original, + placeholder='', }) => { const isDegree = isDegreeMeasurement(m) const units = imperial ? 'imperial' : 'metric' @@ -602,14 +829,14 @@ export const MeasurementInput = ({ * See: https://github.com/facebook/react/issues/16554 */ return ( - - + ) } +/** + * A component to handle input of file (upload) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {number} [props.dropzoneConfig = {}] - The configuration for react-dropzone + * @param {string|function} [props.props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {string} [props.legend = false] - The fieldset legend + * @param {function} props.update - The onChange handler + * @param {number} props.original - The original value, which allows a reset + * @param {function} [props.valid = () => true] - A function that should return whether the value is valid or not + * @returns {JSX.Element} + */ export const FileInput = ({ - label, // The label - valid = () => true, // Method that should return whether the value is valid or not - update, // The onChange handler - current, // The current value - original, // The original value - id = '', // An id to tie the input to the label - dropzoneConfig = {}, // Configuration for react-dropzone + box = false, + current, + dropzoneConfig = {}, + help = false, + id = '', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + legend = false, + update, + original, + valid = () => true, }) => { /* * Ondrop handler @@ -663,7 +916,7 @@ export const FileInput = ({ */ if (current) return ( - +
- +
) /* * Return upload form */ return ( - +
- +
) } /* * Input for booleans */ +/** + * A component to handle input of booleans (yes/no or on/off) + * + * @component + * @param {object} props - All component props + * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset + * @param {number} props.current - The current value, to manage the state of this input + * @param {boolean} [props.disabled = false] - Set this to true to render a disabled input + * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs + * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels + * @param {string} [props.label = false] - The label + * @param {string} [props.labelBL = false] - The bottom-left) label + * @param {string} [props.labelBR = false] - The bottom-right) label + * @param {string} [props.labelTR = false] - The top-right label + * @param {array} [props.labels = ['Yes', 'No'] - An array of labels for the values + * @param {string} [props.legend = false] - The fieldset legend + * @param {array} [props.list = [true, false] - An array of values to choose between + * @param {function} props.update - The onChange handler + * @param {any} [props.on = true] - The value that should show the toggle in the 'on' state + * @param {number} props.original - The original value, which allows a reset + * @param {function} [props.valid = () => true] - A function that should return whether the value is valid or not + * @returns {JSX.Element} + */ export const ToggleInput = ({ - label, // Label to use - update, // onChange handler - current, // The current value - disabled = false, // Allows rendering a disabled view - list = [true, false], // The values to chose between - labels = ['Yes', 'No'], // The labels for the values - on = true, // The value that should show the toggle in the 'on' state - id = '', // An id to tie the input to the label - labelTR = false, // Top-Right label - labelBL = false, // Bottom-Left label - labelBR = false, // Bottom-Right label + box = false, + current, + disabled = false, + help = false, + id = '', + label = false, + labelBL = false, + labelBR = false, + labelTR = false, + labels = ['Yes', 'No'], + legend = false, + list = [true, false], + update, + on = true, + original, + valid = () => true, }) => ( - + + } + + ) diff --git a/packages/react/mkdocs.sh b/packages/react/mkdocs.sh index 3fd34b05c51..ebda60e8f09 100755 --- a/packages/react/mkdocs.sh +++ b/packages/react/mkdocs.sh @@ -14,3 +14,4 @@ jsdoc -c jsdoc.json components/Editor/* > ../../sites/dev/prebuild/jsdoc/react/c jsdoc -c jsdoc.json components/Heading/* > ../../sites/dev/prebuild/jsdoc/react/components/heading.json jsdoc -c jsdoc.json components/Highlight/* > ../../sites/dev/prebuild/jsdoc/react/components/highlight.json jsdoc -c jsdoc.json components/Icon/* > ../../sites/dev/prebuild/jsdoc/react/components/icon.json +jsdoc -c jsdoc.json components/Input/* > ../../sites/dev/prebuild/jsdoc/react/components/input.json diff --git a/sites/backend/src/models/flow.mjs b/sites/backend/src/models/flow.mjs index 791f5f501b6..229df00fdbf 100644 --- a/sites/backend/src/models/flow.mjs +++ b/sites/backend/src/models/flow.mjs @@ -150,7 +150,7 @@ FlowModel.prototype.uploadImage = async function ({ body, user }, anon = false) * Is type set and valid? */ if (!body.type) return this.setResponse(400, 'typeMissing') - if (!['blog', 'showcase', 'support'].includes(body.type)) + if (!['blog', 'showcase'].includes(body.type)) return this.setResponse(400, 'typeInvalid') /* diff --git a/sites/dev/docs/reference/packages/react/components/input/_examples.js b/sites/dev/docs/reference/packages/react/components/input/_examples.js new file mode 100644 index 00000000000..b7ec202dd57 --- /dev/null +++ b/sites/dev/docs/reference/packages/react/components/input/_examples.js @@ -0,0 +1,152 @@ +import React, { useState } from 'react' +import { validateEmail } from '@freesewing/utils' +import { + ActiveImageInput, + ButtonFrame, + DesignInput, + EmailInput, + Fieldset, + FileInput, + ImageInput, + ListInput, + MarkdownInput, + MeasurementInput, + MfaInput, + NumberInput, + PassiveImageInput, + PasswordInput, + StringInput, + ToggleInput, +} from '@freesewing/react/components/Input' + +/* + * A nonsensical update function + */ +const update = (...params) => console.log('Update method received', params) + +export const Docs = () => ( +
+  {Object.keys(components).map(c => `${c}\n`)}
+  
+) + +export const ActiveImageInputExample = () => ( + +) +export const ButtonFrameExample = () => ( + +

This is inside the ButtonFrame

+
+) +export const DesignInputExample = () => ( + +) +export const EmailInputExample = () => { + const [email, setEmail] = useState('') + + return setEmail(val)} current={email} /> +} +export const FieldsetExample = () => ( + <> +

Regular Fieldset:

+
+ +
+

Box Fieldset:

+
+ +
+

No legend:

+
+ +
+ +) +export const FileInputExample = () => ( + +) +export const ImageInputExample = () => ( + +) +export const ListInputExample = () => { + const list = [ + { val: 'bananas', label: 'Bananas', desc: 'A type of fruit' }, + { val: 'bandanas', label: 'Bandanas', desc: 'Something to wear on your head' }, + ] + return ( + <> +

Regular:

+ +

Without desc inside a fieldset with legend:

+ ({ ...item, desc: undefined }))} box legend="Legend here"/> + + ) +} +export const MarkdownInputExample = () => { + const [md, setMd] = useState('') + return setMd(val)} /> +} +export const MeasurementInputExample = () => ( + +) +export const MfaInputExample = () => ( + +) +export const NumberInputExample = () => ( + +) +export const PassiveImageInputExample = () => ( + +) +export const PasswordInputExample = () => { + const [pwd, setPwd] = useState('') + return setPwd(val)} /> +} +export const StringInputExample = () => { + const [pwd, setPwd] = useState('') + return setPwd(val)} /> +} +export const ToggleInputExample = () => { + const [val, setVal] = useState(false) + return setVal(v)} labels={['Enabled', 'Disabled']} legend="Toggle" /> +} + + diff --git a/sites/dev/docs/reference/packages/react/components/input/readme.mdx b/sites/dev/docs/reference/packages/react/components/input/readme.mdx index 09683ee3cb6..152283ab398 100644 --- a/sites/dev/docs/reference/packages/react/components/input/readme.mdx +++ b/sites/dev/docs/reference/packages/react/components/input/readme.mdx @@ -2,6 +2,112 @@ title: Input --- -:::note -This page is yet to be created -::: +import { DocusaurusDoc } from '@freesewing/react/components/Docusaurus' +import { ComponentDocs } from '@site/src/components/component-docs.js' +import { + jsdocActiveImageInput, + jsdocButtonFrame, + jsdocDesignInput, + jsdocEmailInput, + jsdocFieldset, + jsdocFileInput, + jsdocImageInput, + jsdocListInput, + jsdocMarkdownInput, + jsdocMeasurementInput, + jsdocMfaInput, + jsdocNumberInput, + jsdocPassiveImageInput, + jsdocPasswordInput, + jsdocStringInput, + jsdocToggleInput, +} from '@site/prebuild/jsdoc/components.input.mjs' +import { + ActiveImageInputExample, + ButtonFrameExample, + DesignInputExample, + EmailInputExample, + FieldsetExample, + FileInputExample, + ImageInputExample, + ListInputExample, + MarkdownInputExample, + MeasurementInputExample, + MfaInputExample, + NumberInputExample, + PassiveImageInputExample, + PasswordInputExample, + StringInputExample, + ToggleInputExample, +} from './_examples.js' + + + +The **Input** component family provides the following components: + +- [ActiveImageInput](#activeimageinput) +- [ButtonFrame](#buttonframe) +- [DesignInput](#designinput) +- [EmailInput](#emailinput) +- [Fieldset](#fieldset) +- [FileInput](#fileinput) +- [ImageInput](#imageinput) +- [ListInput](#listinput) +- [MarkdownInput](#markdowninput) +- [MeasurementInput](#measurementinput) +- [MfaInput](#mfainput) +- [NumberInput](#numberinput) +- [PassiveImageInput](#passiveimageinput) +- [PasswordInput](#passwordinput) +- [StringInput](#stringinput) +- [ToggleInput](#toggleinput) + +## ActiveImageInput + + +## ButtonFrame + + +## DesignInput + + +## EmailInput + + +## Fieldset + + +## FileInput + + +## ImageInput + + +## ListInput + + +## MarkdownInput + + +## MeasurementInput + + +## MfaInput + + +## NumberInput + + +## PassiveImageInput + + +## PasswordInput + + +## StringInput + + +## ToggleInput + + +