@trackunit/react-form-components 1.11.18 → 1.11.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +832 -45
- package/index.esm.js +834 -47
- package/package.json +7 -7
- package/src/components/Checkbox/Checkbox.d.ts +46 -2
- package/src/components/ColorField/ColorField.d.ts +34 -2
- package/src/components/DateField/DateField.d.ts +44 -3
- package/src/components/DropZone/DropZone.d.ts +56 -1
- package/src/components/EmailField/EmailField.d.ts +46 -2
- package/src/components/MultiSelectField/MultiSelectField.d.ts +56 -2
- package/src/components/NumberField/NumberField.d.ts +46 -2
- package/src/components/PasswordField/PasswordField.d.ts +52 -3
- package/src/components/PhoneField/PhoneField.d.ts +45 -12
- package/src/components/RadioGroup/RadioGroup.d.ts +49 -2
- package/src/components/SelectField/SelectField.d.ts +62 -1
- package/src/components/TextAreaField/TextAreaField.d.ts +45 -3
- package/src/components/TextField/TextField.d.ts +55 -0
- package/src/components/ToggleSwitch/ToggleSwitch.d.ts +47 -3
- package/src/components/ToggleSwitchOption/ToggleSwitchOption.d.ts +56 -4
- package/src/components/UploadField/UploadField.d.ts +47 -1
- package/src/components/UrlField/UrlField.d.ts +46 -2
package/index.cjs.js
CHANGED
|
@@ -1036,10 +1036,54 @@ const IndeterminateIcon = ({ className }) => (jsxRuntime.jsx("svg", { className:
|
|
|
1036
1036
|
*
|
|
1037
1037
|
* Checkboxes are used for multiple choices, not for mutually exclusive choices. Each checkbox works independently from other checkboxes in the list, therefore checking an additional box does not affect any other selections.
|
|
1038
1038
|
*
|
|
1039
|
-
*
|
|
1039
|
+
* ### When to use
|
|
1040
|
+
* Use checkboxes to allow selection in a form, for filtering, terms and conditions to indicate agreement, and bulk actions in lists or tables.
|
|
1040
1041
|
*
|
|
1041
|
-
*
|
|
1042
|
+
* ### When not to use
|
|
1043
|
+
* Do not use checkboxes if the user can only select one option from a list. Use RadioGroup instead.
|
|
1042
1044
|
*
|
|
1045
|
+
* @example Basic checkbox
|
|
1046
|
+
* ```tsx
|
|
1047
|
+
* import { Checkbox } from "@trackunit/react-form-components";
|
|
1048
|
+
* import { useState } from "react";
|
|
1049
|
+
*
|
|
1050
|
+
* const MyForm = () => {
|
|
1051
|
+
* const [accepted, setAccepted] = useState(false);
|
|
1052
|
+
*
|
|
1053
|
+
* return (
|
|
1054
|
+
* <Checkbox
|
|
1055
|
+
* label="I accept the terms and conditions"
|
|
1056
|
+
* checked={accepted}
|
|
1057
|
+
* onChange={(e) => setAccepted(e.target.checked)}
|
|
1058
|
+
* />
|
|
1059
|
+
* );
|
|
1060
|
+
* };
|
|
1061
|
+
* ```
|
|
1062
|
+
* @example Checkbox group for multiple selections
|
|
1063
|
+
* ```tsx
|
|
1064
|
+
* import { Checkbox } from "@trackunit/react-form-components";
|
|
1065
|
+
* import { useState } from "react";
|
|
1066
|
+
*
|
|
1067
|
+
* const NotificationSettings = () => {
|
|
1068
|
+
* const [notifications, setNotifications] = useState({
|
|
1069
|
+
* email: true,
|
|
1070
|
+
* sms: false,
|
|
1071
|
+
* push: true,
|
|
1072
|
+
* });
|
|
1073
|
+
*
|
|
1074
|
+
* const handleChange = (key: keyof typeof notifications) => (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
1075
|
+
* setNotifications((prev) => ({ ...prev, [key]: e.target.checked }));
|
|
1076
|
+
* };
|
|
1077
|
+
*
|
|
1078
|
+
* return (
|
|
1079
|
+
* <div className="flex flex-col gap-2">
|
|
1080
|
+
* <Checkbox label="Email notifications" checked={notifications.email} onChange={handleChange("email")} />
|
|
1081
|
+
* <Checkbox label="SMS notifications" checked={notifications.sms} onChange={handleChange("sms")} />
|
|
1082
|
+
* <Checkbox label="Push notifications" checked={notifications.push} onChange={handleChange("push")} />
|
|
1083
|
+
* </div>
|
|
1084
|
+
* );
|
|
1085
|
+
* };
|
|
1086
|
+
* ```
|
|
1043
1087
|
* @description A reference to the input element is provided as the `ref` prop.
|
|
1044
1088
|
* @augments props from [React.InputHTMLAttributes](https://reactjs.org/docs/dom-elements.html#input)
|
|
1045
1089
|
* @param {CheckboxProps} props - The props for the Checkbox component
|
|
@@ -2096,9 +2140,41 @@ const isValidHEXColor = (value) => {
|
|
|
2096
2140
|
return hexRegex.test(value);
|
|
2097
2141
|
};
|
|
2098
2142
|
/**
|
|
2099
|
-
* The ColorField component is used to enter
|
|
2100
|
-
*
|
|
2143
|
+
* The `<ColorField>` component is used to select and enter colors.
|
|
2144
|
+
* It provides both a color picker and a text input for hex color codes,
|
|
2145
|
+
* with validation ensuring valid hex format (#RRGGBB).
|
|
2146
|
+
*
|
|
2147
|
+
* ### When to use
|
|
2148
|
+
* - Color selection in theming or customization forms
|
|
2149
|
+
* - Brand color configuration
|
|
2150
|
+
* - Any input requiring a valid hex color value
|
|
2151
|
+
*
|
|
2152
|
+
* ### When not to use
|
|
2153
|
+
* - When you need a full color palette with named colors
|
|
2154
|
+
* - When opacity/alpha channel is required (only supports 6-digit hex)
|
|
2155
|
+
*
|
|
2156
|
+
* @example Basic usage
|
|
2157
|
+
* ```tsx
|
|
2158
|
+
* import { ColorField } from "@trackunit/react-form-components";
|
|
2159
|
+
*
|
|
2160
|
+
* const [color, setColor] = useState("#3B82F6");
|
|
2161
|
+
*
|
|
2162
|
+
* <ColorField
|
|
2163
|
+
* label="Brand Color"
|
|
2164
|
+
* value={color}
|
|
2165
|
+
* onChange={(e) => setColor(e.target.value)}
|
|
2166
|
+
* />
|
|
2167
|
+
* ```
|
|
2168
|
+
* @example With validation
|
|
2169
|
+
* ```tsx
|
|
2170
|
+
* import { ColorField } from "@trackunit/react-form-components";
|
|
2101
2171
|
*
|
|
2172
|
+
* <ColorField
|
|
2173
|
+
* label="Primary Color"
|
|
2174
|
+
* helpText="Enter a valid hex color (e.g., #FF5500)"
|
|
2175
|
+
* required
|
|
2176
|
+
* />
|
|
2177
|
+
* ```
|
|
2102
2178
|
*/
|
|
2103
2179
|
const ColorField = react.forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, "data-testid": dataTestId, value: propValue, onChange, isInvalid, onBlur, fieldSize = "medium", style, disabled, readOnly, isWarning, inputClassName, ...inputProps }, ref) => {
|
|
2104
2180
|
const renderAsDisabled = Boolean(disabled);
|
|
@@ -2157,11 +2233,52 @@ const ColorField = react.forwardRef(({ label, id, tip, helpText, errorMessage, h
|
|
|
2157
2233
|
ColorField.displayName = "ColorField";
|
|
2158
2234
|
|
|
2159
2235
|
/**
|
|
2160
|
-
* The date field component is used for entering date values.
|
|
2236
|
+
* The date field component is used for entering date values with a native date picker.
|
|
2161
2237
|
*
|
|
2162
|
-
*
|
|
2238
|
+
* ### When to use
|
|
2239
|
+
* Use DateField for selecting calendar dates such as birthdates, deadlines, or scheduling.
|
|
2163
2240
|
*
|
|
2164
|
-
*
|
|
2241
|
+
* ### When not to use
|
|
2242
|
+
* Do not use DateField for non-serialized dates or free-form date text input. Use TextField instead.
|
|
2243
|
+
*
|
|
2244
|
+
* @example Basic date field
|
|
2245
|
+
* ```tsx
|
|
2246
|
+
* import { DateField } from "@trackunit/react-form-components";
|
|
2247
|
+
* import { useState } from "react";
|
|
2248
|
+
*
|
|
2249
|
+
* const MyForm = () => {
|
|
2250
|
+
* const [date, setDate] = useState("");
|
|
2251
|
+
*
|
|
2252
|
+
* return (
|
|
2253
|
+
* <DateField
|
|
2254
|
+
* label="Start Date"
|
|
2255
|
+
* value={date}
|
|
2256
|
+
* onChange={(e) => setDate(e.target.value)}
|
|
2257
|
+
* />
|
|
2258
|
+
* );
|
|
2259
|
+
* };
|
|
2260
|
+
* ```
|
|
2261
|
+
* @example Date field with constraints
|
|
2262
|
+
* ```tsx
|
|
2263
|
+
* import { DateField } from "@trackunit/react-form-components";
|
|
2264
|
+
* import { useState } from "react";
|
|
2265
|
+
*
|
|
2266
|
+
* const BookingForm = () => {
|
|
2267
|
+
* const [checkIn, setCheckIn] = useState("");
|
|
2268
|
+
* const today = new Date().toISOString().split("T")[0];
|
|
2269
|
+
*
|
|
2270
|
+
* return (
|
|
2271
|
+
* <DateField
|
|
2272
|
+
* label="Check-in Date"
|
|
2273
|
+
* value={checkIn}
|
|
2274
|
+
* onChange={(e) => setCheckIn(e.target.value)}
|
|
2275
|
+
* min={today}
|
|
2276
|
+
* helpText="Select a date from today onwards"
|
|
2277
|
+
* required
|
|
2278
|
+
* />
|
|
2279
|
+
* );
|
|
2280
|
+
* };
|
|
2281
|
+
* ```
|
|
2165
2282
|
*/
|
|
2166
2283
|
const DateField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, className, defaultValue, "data-testid": dataTestId, ref, ...rest }) => {
|
|
2167
2284
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
@@ -2229,8 +2346,63 @@ const DropZoneDefaultLabel = () => (jsxRuntime.jsx(Trans, { components: {
|
|
|
2229
2346
|
}, i18nKey: "dropzone.label.default", values: {} }));
|
|
2230
2347
|
|
|
2231
2348
|
/**
|
|
2232
|
-
* The
|
|
2349
|
+
* The `<DropZone>` component provides a drag-and-drop area for file uploads.
|
|
2350
|
+
* Users can either drag files onto the zone or click to browse the file system.
|
|
2351
|
+
*
|
|
2352
|
+
* ### When to use
|
|
2353
|
+
* - Drag-and-drop file upload experience
|
|
2354
|
+
* - Batch file uploads
|
|
2355
|
+
* - When visual feedback during drag is important
|
|
2356
|
+
*
|
|
2357
|
+
* ### When not to use
|
|
2358
|
+
* - Simple single file uploads - use `UploadField` instead
|
|
2359
|
+
* - When form field styling (label, help text) is needed - use `UploadField`
|
|
2360
|
+
*
|
|
2361
|
+
* @example Basic usage
|
|
2362
|
+
* ```tsx
|
|
2363
|
+
* import { DropZone } from "@trackunit/react-form-components";
|
|
2364
|
+
*
|
|
2365
|
+
* <DropZone
|
|
2366
|
+
* filesSelected={(files) => handleFiles(files)}
|
|
2367
|
+
* accept="image/*"
|
|
2368
|
+
* />
|
|
2369
|
+
* ```
|
|
2370
|
+
* @example With custom label
|
|
2371
|
+
* ```tsx
|
|
2372
|
+
* import { DropZone } from "@trackunit/react-form-components";
|
|
2233
2373
|
*
|
|
2374
|
+
* <DropZone
|
|
2375
|
+
* filesSelected={(files) => handleFiles(files)}
|
|
2376
|
+
* label={
|
|
2377
|
+
* <span>
|
|
2378
|
+
* <strong>Drop files here</strong> or click to browse
|
|
2379
|
+
* </span>
|
|
2380
|
+
* }
|
|
2381
|
+
* accept=".pdf,.doc,.docx"
|
|
2382
|
+
* />
|
|
2383
|
+
* ```
|
|
2384
|
+
* @example Multiple files with size options
|
|
2385
|
+
* ```tsx
|
|
2386
|
+
* import { DropZone } from "@trackunit/react-form-components";
|
|
2387
|
+
*
|
|
2388
|
+
* <DropZone
|
|
2389
|
+
* filesSelected={(files) => {
|
|
2390
|
+
* Array.from(files).forEach(file => uploadFile(file));
|
|
2391
|
+
* }}
|
|
2392
|
+
* multiple
|
|
2393
|
+
* size="medium"
|
|
2394
|
+
* accept="image/png,image/jpeg"
|
|
2395
|
+
* />
|
|
2396
|
+
* ```
|
|
2397
|
+
* @example Disabled state
|
|
2398
|
+
* ```tsx
|
|
2399
|
+
* import { DropZone } from "@trackunit/react-form-components";
|
|
2400
|
+
*
|
|
2401
|
+
* <DropZone
|
|
2402
|
+
* filesSelected={(files) => handleFiles(files)}
|
|
2403
|
+
* disabled={isUploading}
|
|
2404
|
+
* />
|
|
2405
|
+
* ```
|
|
2234
2406
|
* @param {DropZoneProps} props - The props for the DropZone component
|
|
2235
2407
|
* @returns {ReactElement} DropZone component
|
|
2236
2408
|
*/
|
|
@@ -2342,9 +2514,53 @@ const EmailBaseInput = ({ fieldSize = "medium", disabled = false, "data-testid":
|
|
|
2342
2514
|
};
|
|
2343
2515
|
|
|
2344
2516
|
/**
|
|
2345
|
-
* The EmailField component is used to enter email.
|
|
2346
|
-
*
|
|
2517
|
+
* The `<EmailField>` component is used to enter and validate email addresses.
|
|
2518
|
+
* It automatically validates the format on blur and displays appropriate error messages.
|
|
2519
|
+
*
|
|
2520
|
+
* ### When to use
|
|
2521
|
+
* - Collecting user email addresses in forms
|
|
2522
|
+
* - Contact forms that require email validation
|
|
2523
|
+
* - Any input that must be a valid email format
|
|
2524
|
+
*
|
|
2525
|
+
* ### When not to use
|
|
2526
|
+
* - For general text input - use `TextField` instead
|
|
2527
|
+
* - For URLs - use `UrlField` instead
|
|
2528
|
+
* - For phone numbers - use `PhoneField` instead
|
|
2529
|
+
*
|
|
2530
|
+
* @example Basic usage
|
|
2531
|
+
* ```tsx
|
|
2532
|
+
* import { EmailField } from "@trackunit/react-form-components";
|
|
2533
|
+
*
|
|
2534
|
+
* const [email, setEmail] = useState("");
|
|
2535
|
+
*
|
|
2536
|
+
* <EmailField
|
|
2537
|
+
* label="Email Address"
|
|
2538
|
+
* value={email}
|
|
2539
|
+
* onChange={(e) => setEmail(e.target.value)}
|
|
2540
|
+
* required
|
|
2541
|
+
* />
|
|
2542
|
+
* ```
|
|
2543
|
+
* @example With help text
|
|
2544
|
+
* ```tsx
|
|
2545
|
+
* import { EmailField } from "@trackunit/react-form-components";
|
|
2546
|
+
*
|
|
2547
|
+
* <EmailField
|
|
2548
|
+
* label="Work Email"
|
|
2549
|
+
* helpText="We'll use this to send notifications"
|
|
2550
|
+
* placeholder="name@company.com"
|
|
2551
|
+
* />
|
|
2552
|
+
* ```
|
|
2553
|
+
* @example With custom error message
|
|
2554
|
+
* ```tsx
|
|
2555
|
+
* import { EmailField } from "@trackunit/react-form-components";
|
|
2347
2556
|
*
|
|
2557
|
+
* <EmailField
|
|
2558
|
+
* label="Email"
|
|
2559
|
+
* value={email}
|
|
2560
|
+
* onChange={(e) => setEmail(e.target.value)}
|
|
2561
|
+
* errorMessage={isEmailTaken ? "This email is already registered" : undefined}
|
|
2562
|
+
* />
|
|
2563
|
+
* ```
|
|
2348
2564
|
*/
|
|
2349
2565
|
const EmailField = ({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, "data-testid": dataTestId, value, onChange, onBlur, isInvalid = false, ref, ...rest }) => {
|
|
2350
2566
|
const htmlForId = id ? id : "emailField-" + sharedUtils.uuidv4();
|
|
@@ -2453,9 +2669,63 @@ const FormFieldSelectAdapterMulti = (props) => {
|
|
|
2453
2669
|
};
|
|
2454
2670
|
|
|
2455
2671
|
/**
|
|
2456
|
-
* MultiSelectField
|
|
2457
|
-
*
|
|
2672
|
+
* The `<MultiSelectField>` component allows selecting multiple options from a dropdown list.
|
|
2673
|
+
* It wraps the select input with FormGroup for consistent form styling including label,
|
|
2674
|
+
* help text, and validation.
|
|
2675
|
+
*
|
|
2676
|
+
* ### When to use
|
|
2677
|
+
* - Selecting multiple items from a predefined list (tags, categories, permissions)
|
|
2678
|
+
* - When users need to see and manage all selected items
|
|
2679
|
+
* - Filtering by multiple criteria
|
|
2680
|
+
*
|
|
2681
|
+
* ### When not to use
|
|
2682
|
+
* - Single selection - use `SelectField` instead
|
|
2683
|
+
* - Very long lists - consider a searchable/async variant
|
|
2684
|
+
* - Binary choices - use `Checkbox` or `ToggleSwitchOption` instead
|
|
2685
|
+
*
|
|
2686
|
+
* @example Basic usage
|
|
2687
|
+
* ```tsx
|
|
2688
|
+
* import { MultiSelectField } from "@trackunit/react-form-components";
|
|
2689
|
+
*
|
|
2690
|
+
* const options = [
|
|
2691
|
+
* { value: "read", label: "Read" },
|
|
2692
|
+
* { value: "write", label: "Write" },
|
|
2693
|
+
* { value: "delete", label: "Delete" },
|
|
2694
|
+
* ];
|
|
2695
|
+
*
|
|
2696
|
+
* <MultiSelectField
|
|
2697
|
+
* label="Permissions"
|
|
2698
|
+
* options={options}
|
|
2699
|
+
* value={selectedPermissions}
|
|
2700
|
+
* onChange={(selected) => setSelectedPermissions(selected)}
|
|
2701
|
+
* />
|
|
2702
|
+
* ```
|
|
2703
|
+
* @example With placeholder and help text
|
|
2704
|
+
* ```tsx
|
|
2705
|
+
* import { MultiSelectField } from "@trackunit/react-form-components";
|
|
2706
|
+
*
|
|
2707
|
+
* <MultiSelectField
|
|
2708
|
+
* label="Categories"
|
|
2709
|
+
* options={categoryOptions}
|
|
2710
|
+
* value={selectedCategories}
|
|
2711
|
+
* onChange={(selected) => setSelectedCategories(selected)}
|
|
2712
|
+
* placeholder="Select categories..."
|
|
2713
|
+
* helpText="Select all that apply"
|
|
2714
|
+
* />
|
|
2715
|
+
* ```
|
|
2716
|
+
* @example With validation
|
|
2717
|
+
* ```tsx
|
|
2718
|
+
* import { MultiSelectField } from "@trackunit/react-form-components";
|
|
2458
2719
|
*
|
|
2720
|
+
* <MultiSelectField
|
|
2721
|
+
* label="Required Tags"
|
|
2722
|
+
* options={tagOptions}
|
|
2723
|
+
* value={selectedTags}
|
|
2724
|
+
* onChange={(selected) => setSelectedTags(selected)}
|
|
2725
|
+
* required
|
|
2726
|
+
* errorMessage={selectedTags.length === 0 ? "Select at least one tag" : undefined}
|
|
2727
|
+
* />
|
|
2728
|
+
* ```
|
|
2459
2729
|
* @param {MultiSelectFieldProps} props - The props for the MultiSelectField component
|
|
2460
2730
|
* @returns {ReactElement} MultiSelectField component
|
|
2461
2731
|
*/
|
|
@@ -2517,9 +2787,53 @@ const validateNumber = (number, required = false, min, max) => {
|
|
|
2517
2787
|
/**
|
|
2518
2788
|
* The number field component is used for entering numeric values and includes controls for incrementally increasing or decreasing the value.
|
|
2519
2789
|
*
|
|
2520
|
-
*
|
|
2790
|
+
* ### When to use
|
|
2791
|
+
* Use NumberField when the controls to incrementally increase or decrease makes the task easier for the user, such as quantity selectors or numeric settings.
|
|
2521
2792
|
*
|
|
2522
|
-
*
|
|
2793
|
+
* ### When not to use
|
|
2794
|
+
* Do not use NumberField for non-serialized numbers or IDs. Use TextField instead.
|
|
2795
|
+
*
|
|
2796
|
+
* @example Basic number field
|
|
2797
|
+
* ```tsx
|
|
2798
|
+
* import { NumberField } from "@trackunit/react-form-components";
|
|
2799
|
+
* import { useState } from "react";
|
|
2800
|
+
*
|
|
2801
|
+
* const MyForm = () => {
|
|
2802
|
+
* const [quantity, setQuantity] = useState(1);
|
|
2803
|
+
*
|
|
2804
|
+
* return (
|
|
2805
|
+
* <NumberField
|
|
2806
|
+
* label="Quantity"
|
|
2807
|
+
* value={quantity}
|
|
2808
|
+
* onChange={(e) => setQuantity(Number(e.target.value))}
|
|
2809
|
+
* min={1}
|
|
2810
|
+
* max={100}
|
|
2811
|
+
* />
|
|
2812
|
+
* );
|
|
2813
|
+
* };
|
|
2814
|
+
* ```
|
|
2815
|
+
* @example Number field with validation
|
|
2816
|
+
* ```tsx
|
|
2817
|
+
* import { NumberField } from "@trackunit/react-form-components";
|
|
2818
|
+
* import { useState } from "react";
|
|
2819
|
+
*
|
|
2820
|
+
* const TemperatureInput = () => {
|
|
2821
|
+
* const [temp, setTemp] = useState(20);
|
|
2822
|
+
*
|
|
2823
|
+
* return (
|
|
2824
|
+
* <NumberField
|
|
2825
|
+
* label="Temperature (°C)"
|
|
2826
|
+
* value={temp}
|
|
2827
|
+
* onChange={(e) => setTemp(Number(e.target.value))}
|
|
2828
|
+
* min={-40}
|
|
2829
|
+
* max={60}
|
|
2830
|
+
* step={0.5}
|
|
2831
|
+
* helpText="Enter a value between -40 and 60"
|
|
2832
|
+
* required
|
|
2833
|
+
* />
|
|
2834
|
+
* );
|
|
2835
|
+
* };
|
|
2836
|
+
* ```
|
|
2523
2837
|
*/
|
|
2524
2838
|
const NumberField = ({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, "data-testid": dataTestId, defaultValue, onBlur, onChange, ref, ...rest }) => {
|
|
2525
2839
|
const htmlForId = id ? id : "numberField-" + sharedUtils.uuidv4();
|
|
@@ -2666,11 +2980,60 @@ const PasswordBaseInput = ({ ref, fieldSize, ...rest }) => {
|
|
|
2666
2980
|
};
|
|
2667
2981
|
|
|
2668
2982
|
/**
|
|
2669
|
-
*
|
|
2983
|
+
* The `<PasswordField>` component is used to enter passwords or other confidential information.
|
|
2984
|
+
* Characters are masked as they are typed, with an option to toggle visibility.
|
|
2985
|
+
*
|
|
2986
|
+
* ### When to use
|
|
2987
|
+
* - Password input for login or registration forms
|
|
2988
|
+
* - Entering sensitive data that should be obfuscated (API keys, secrets)
|
|
2989
|
+
* - Any confidential text input
|
|
2990
|
+
*
|
|
2991
|
+
* ### When not to use
|
|
2992
|
+
* - Confirming user actions like deletion - use a Checkbox instead
|
|
2993
|
+
* - Non-sensitive text input - use `TextField` instead
|
|
2994
|
+
* - PIN codes - consider a specialized PIN input
|
|
2995
|
+
*
|
|
2996
|
+
* @example Basic usage
|
|
2997
|
+
* ```tsx
|
|
2998
|
+
* import { PasswordField } from "@trackunit/react-form-components";
|
|
2999
|
+
*
|
|
3000
|
+
* const [password, setPassword] = useState("");
|
|
2670
3001
|
*
|
|
2671
|
-
*
|
|
3002
|
+
* <PasswordField
|
|
3003
|
+
* label="Password"
|
|
3004
|
+
* value={password}
|
|
3005
|
+
* onChange={(e) => setPassword(e.target.value)}
|
|
3006
|
+
* required
|
|
3007
|
+
* />
|
|
3008
|
+
* ```
|
|
3009
|
+
* @example With validation
|
|
3010
|
+
* ```tsx
|
|
3011
|
+
* import { PasswordField } from "@trackunit/react-form-components";
|
|
2672
3012
|
*
|
|
2673
|
-
*
|
|
3013
|
+
* <PasswordField
|
|
3014
|
+
* label="New Password"
|
|
3015
|
+
* value={password}
|
|
3016
|
+
* onChange={(e) => setPassword(e.target.value)}
|
|
3017
|
+
* helpText="Must be at least 8 characters"
|
|
3018
|
+
* errorMessage={password.length < 8 ? "Password too short" : undefined}
|
|
3019
|
+
* />
|
|
3020
|
+
* ```
|
|
3021
|
+
* @example Confirm password pattern
|
|
3022
|
+
* ```tsx
|
|
3023
|
+
* import { PasswordField } from "@trackunit/react-form-components";
|
|
3024
|
+
*
|
|
3025
|
+
* <PasswordField
|
|
3026
|
+
* label="Password"
|
|
3027
|
+
* value={password}
|
|
3028
|
+
* onChange={(e) => setPassword(e.target.value)}
|
|
3029
|
+
* />
|
|
3030
|
+
* <PasswordField
|
|
3031
|
+
* label="Confirm Password"
|
|
3032
|
+
* value={confirmPassword}
|
|
3033
|
+
* onChange={(e) => setConfirmPassword(e.target.value)}
|
|
3034
|
+
* errorMessage={confirmPassword !== password ? "Passwords do not match" : undefined}
|
|
3035
|
+
* />
|
|
3036
|
+
* ```
|
|
2674
3037
|
*/
|
|
2675
3038
|
const PasswordField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, "data-testid": dataTestId, ref, ...rest }) => {
|
|
2676
3039
|
const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
|
|
@@ -2733,19 +3096,52 @@ const phoneErrorMessage = (phoneNumber, required) => {
|
|
|
2733
3096
|
};
|
|
2734
3097
|
|
|
2735
3098
|
/**
|
|
2736
|
-
* The PhoneField component is used to enter phone
|
|
2737
|
-
* It
|
|
2738
|
-
* It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
|
|
3099
|
+
* The `<PhoneField>` component is used to enter and validate phone numbers.
|
|
3100
|
+
* It includes built-in validation for phone number format and displays appropriate error messages.
|
|
2739
3101
|
*
|
|
2740
|
-
*
|
|
2741
|
-
*
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
2744
|
-
*
|
|
2745
|
-
*
|
|
2746
|
-
*
|
|
2747
|
-
*
|
|
2748
|
-
*
|
|
3102
|
+
* ### When to use
|
|
3103
|
+
* - Collecting phone numbers in contact forms
|
|
3104
|
+
* - User profile phone number fields
|
|
3105
|
+
* - Any input requiring phone number validation
|
|
3106
|
+
*
|
|
3107
|
+
* ### When not to use
|
|
3108
|
+
* - General text input - use `TextField` instead
|
|
3109
|
+
* - International phone with country selector - consider specialized international phone component
|
|
3110
|
+
*
|
|
3111
|
+
* @example Basic usage
|
|
3112
|
+
* ```tsx
|
|
3113
|
+
* import { PhoneField } from "@trackunit/react-form-components";
|
|
3114
|
+
*
|
|
3115
|
+
* const [phone, setPhone] = useState("");
|
|
3116
|
+
*
|
|
3117
|
+
* <PhoneField
|
|
3118
|
+
* label="Phone Number"
|
|
3119
|
+
* value={phone}
|
|
3120
|
+
* onChange={(e) => setPhone(e.target.value)}
|
|
3121
|
+
* required
|
|
3122
|
+
* />
|
|
3123
|
+
* ```
|
|
3124
|
+
* @example With help text
|
|
3125
|
+
* ```tsx
|
|
3126
|
+
* import { PhoneField } from "@trackunit/react-form-components";
|
|
3127
|
+
*
|
|
3128
|
+
* <PhoneField
|
|
3129
|
+
* label="Mobile Phone"
|
|
3130
|
+
* helpText="Include country code for international numbers"
|
|
3131
|
+
* placeholder="+1 555 123 4567"
|
|
3132
|
+
* />
|
|
3133
|
+
* ```
|
|
3134
|
+
* @example With custom error handling
|
|
3135
|
+
* ```tsx
|
|
3136
|
+
* import { PhoneField } from "@trackunit/react-form-components";
|
|
3137
|
+
*
|
|
3138
|
+
* <PhoneField
|
|
3139
|
+
* label="Contact Phone"
|
|
3140
|
+
* value={phone}
|
|
3141
|
+
* onChange={(e) => setPhone(e.target.value)}
|
|
3142
|
+
* errorMessage={isPhoneDuplicate ? "This phone is already registered" : undefined}
|
|
3143
|
+
* />
|
|
3144
|
+
* ```
|
|
2749
3145
|
*/
|
|
2750
3146
|
const PhoneField = ({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, "data-testid": dataTestId, name, onBlur, ref, ...rest }) => {
|
|
2751
3147
|
const htmlForId = id ? id : "phoneField-" + sharedUtils.uuidv4();
|
|
@@ -2863,10 +3259,57 @@ const RadioGroupContext = react.createContext(null);
|
|
|
2863
3259
|
*
|
|
2864
3260
|
* Radio buttons are used for mutually exclusive choices, not for multiple choices. Only one radio button can be selected at a time. When a user chooses a new item, the previous choice is automatically deselected.
|
|
2865
3261
|
*
|
|
2866
|
-
*
|
|
3262
|
+
* ### When to use
|
|
3263
|
+
* Use RadioGroup in forms, settings, or selections in a list where only one option can be selected.
|
|
3264
|
+
*
|
|
3265
|
+
* ### When not to use
|
|
3266
|
+
* Do not use RadioGroup if a user can select many options from a list. Use Checkbox instead.
|
|
3267
|
+
*
|
|
3268
|
+
* @example Basic radio group
|
|
3269
|
+
* ```tsx
|
|
3270
|
+
* import { RadioGroup, RadioItem } from "@trackunit/react-form-components";
|
|
3271
|
+
* import { useState, ChangeEvent } from "react";
|
|
3272
|
+
*
|
|
3273
|
+
* const MyForm = () => {
|
|
3274
|
+
* const [size, setSize] = useState("medium");
|
|
3275
|
+
*
|
|
3276
|
+
* return (
|
|
3277
|
+
* <RadioGroup
|
|
3278
|
+
* id="size-selection"
|
|
3279
|
+
* label="Select size"
|
|
3280
|
+
* value={size}
|
|
3281
|
+
* onChange={(e: ChangeEvent<HTMLInputElement>) => setSize(e.target.value)}
|
|
3282
|
+
* >
|
|
3283
|
+
* <RadioItem label="Small" value="small" />
|
|
3284
|
+
* <RadioItem label="Medium" value="medium" />
|
|
3285
|
+
* <RadioItem label="Large" value="large" />
|
|
3286
|
+
* </RadioGroup>
|
|
3287
|
+
* );
|
|
3288
|
+
* };
|
|
3289
|
+
* ```
|
|
3290
|
+
* @example Inline radio group with descriptions
|
|
3291
|
+
* ```tsx
|
|
3292
|
+
* import { RadioGroup, RadioItem } from "@trackunit/react-form-components";
|
|
3293
|
+
* import { useState, ChangeEvent } from "react";
|
|
2867
3294
|
*
|
|
2868
|
-
*
|
|
3295
|
+
* const PlanSelector = () => {
|
|
3296
|
+
* const [plan, setPlan] = useState("basic");
|
|
2869
3297
|
*
|
|
3298
|
+
* return (
|
|
3299
|
+
* <RadioGroup
|
|
3300
|
+
* id="plan-selection"
|
|
3301
|
+
* label="Choose your plan"
|
|
3302
|
+
* value={plan}
|
|
3303
|
+
* onChange={(e: ChangeEvent<HTMLInputElement>) => setPlan(e.target.value)}
|
|
3304
|
+
* inline
|
|
3305
|
+
* >
|
|
3306
|
+
* <RadioItem label="Basic" value="basic" description="$9/month" />
|
|
3307
|
+
* <RadioItem label="Pro" value="pro" description="$29/month" />
|
|
3308
|
+
* <RadioItem label="Enterprise" value="enterprise" description="Contact us" />
|
|
3309
|
+
* </RadioGroup>
|
|
3310
|
+
* );
|
|
3311
|
+
* };
|
|
3312
|
+
* ```
|
|
2870
3313
|
* @param {RadioGroupProps} props - The props for the RadioGroup component
|
|
2871
3314
|
* @returns {ReactElement} RadioGroup component
|
|
2872
3315
|
*/
|
|
@@ -3253,8 +3696,69 @@ const CreatableSelectField = ({ allowCreateWhileLoading = false, onCreateOption,
|
|
|
3253
3696
|
CreatableSelectField.displayName = "CreatableSelectField";
|
|
3254
3697
|
|
|
3255
3698
|
/**
|
|
3256
|
-
*
|
|
3699
|
+
* SelectField is a dropdown select component wrapped in the FormGroup component for selecting a single option from a list.
|
|
3700
|
+
*
|
|
3701
|
+
* ### When to use
|
|
3702
|
+
* Use SelectField when users need to choose one option from a predefined list of 4 or more items.
|
|
3703
|
+
*
|
|
3704
|
+
* ### When not to use
|
|
3705
|
+
* Do not use SelectField for fewer than 4 options. Use RadioGroup instead for better usability with small option sets.
|
|
3706
|
+
*
|
|
3707
|
+
* @example Basic select field
|
|
3708
|
+
* ```tsx
|
|
3709
|
+
* import { SelectField } from "@trackunit/react-form-components";
|
|
3710
|
+
* import { useState } from "react";
|
|
3711
|
+
*
|
|
3712
|
+
* const options = [
|
|
3713
|
+
* { value: "us", label: "United States" },
|
|
3714
|
+
* { value: "uk", label: "United Kingdom" },
|
|
3715
|
+
* { value: "de", label: "Germany" },
|
|
3716
|
+
* { value: "fr", label: "France" },
|
|
3717
|
+
* ];
|
|
3718
|
+
*
|
|
3719
|
+
* const MyForm = () => {
|
|
3720
|
+
* const [country, setCountry] = useState<{ value: string; label: string } | null>(null);
|
|
3721
|
+
*
|
|
3722
|
+
* return (
|
|
3723
|
+
* <SelectField
|
|
3724
|
+
* label="Country"
|
|
3725
|
+
* options={options}
|
|
3726
|
+
* value={country}
|
|
3727
|
+
* onChange={(option) => setCountry(option)}
|
|
3728
|
+
* placeholder="Select a country"
|
|
3729
|
+
* />
|
|
3730
|
+
* );
|
|
3731
|
+
* };
|
|
3732
|
+
* ```
|
|
3733
|
+
* @example Async select field with search
|
|
3734
|
+
* ```tsx
|
|
3735
|
+
* import { SelectField } from "@trackunit/react-form-components";
|
|
3736
|
+
* import { useState } from "react";
|
|
3737
|
+
*
|
|
3738
|
+
* const MyAsyncForm = () => {
|
|
3739
|
+
* const [selected, setSelected] = useState(null);
|
|
3257
3740
|
*
|
|
3741
|
+
* const loadOptions = async (inputValue: string) => {
|
|
3742
|
+
* const response = await fetch(`/api/users?search=${inputValue}`);
|
|
3743
|
+
* const users = await response.json();
|
|
3744
|
+
* return users.map((user: { id: string; name: string }) => ({
|
|
3745
|
+
* value: user.id,
|
|
3746
|
+
* label: user.name,
|
|
3747
|
+
* }));
|
|
3748
|
+
* };
|
|
3749
|
+
*
|
|
3750
|
+
* return (
|
|
3751
|
+
* <SelectField
|
|
3752
|
+
* label="Assign to user"
|
|
3753
|
+
* isAsync
|
|
3754
|
+
* loadOptions={loadOptions}
|
|
3755
|
+
* value={selected}
|
|
3756
|
+
* onChange={setSelected}
|
|
3757
|
+
* isClearable
|
|
3758
|
+
* />
|
|
3759
|
+
* );
|
|
3760
|
+
* };
|
|
3761
|
+
* ```
|
|
3258
3762
|
* @param {SelectFieldProps} props - The props for the SelectField component
|
|
3259
3763
|
*/
|
|
3260
3764
|
function SelectField({ ref, ...props }) {
|
|
@@ -3274,12 +3778,54 @@ const TextLengthIndicator = ({ length, maxLength }) => {
|
|
|
3274
3778
|
};
|
|
3275
3779
|
|
|
3276
3780
|
/**
|
|
3277
|
-
*
|
|
3781
|
+
* The `<TextAreaField>` component is used for multi-line text input.
|
|
3782
|
+
* Use when you need to allow users to enter a large amount of text, such as comments or descriptions.
|
|
3783
|
+
*
|
|
3784
|
+
* ### When to use
|
|
3785
|
+
* - Longer text inputs like comments, descriptions, or notes
|
|
3786
|
+
* - When the expected input is more than one line
|
|
3787
|
+
* - For free-form text that benefits from a larger input area
|
|
3788
|
+
*
|
|
3789
|
+
* ### When not to use
|
|
3790
|
+
* - Single-line inputs - use `TextField` instead
|
|
3791
|
+
* - Structured data like email or phone - use specialized field components
|
|
3792
|
+
* - Rich text editing - consider a rich text editor component
|
|
3793
|
+
*
|
|
3794
|
+
* @example Basic usage
|
|
3795
|
+
* ```tsx
|
|
3796
|
+
* import { TextAreaField } from "@trackunit/react-form-components";
|
|
3278
3797
|
*
|
|
3279
|
-
*
|
|
3798
|
+
* const [description, setDescription] = useState("");
|
|
3280
3799
|
*
|
|
3281
|
-
*
|
|
3800
|
+
* <TextAreaField
|
|
3801
|
+
* label="Description"
|
|
3802
|
+
* value={description}
|
|
3803
|
+
* onChange={(e) => setDescription(e.target.value)}
|
|
3804
|
+
* placeholder="Enter a description..."
|
|
3805
|
+
* />
|
|
3806
|
+
* ```
|
|
3807
|
+
* @example With character limit
|
|
3808
|
+
* ```tsx
|
|
3809
|
+
* import { TextAreaField } from "@trackunit/react-form-components";
|
|
3810
|
+
*
|
|
3811
|
+
* <TextAreaField
|
|
3812
|
+
* label="Comment"
|
|
3813
|
+
* maxLength={500}
|
|
3814
|
+
* helpText="Add any additional notes"
|
|
3815
|
+
* required
|
|
3816
|
+
* />
|
|
3817
|
+
* ```
|
|
3818
|
+
* @example With validation error
|
|
3819
|
+
* ```tsx
|
|
3820
|
+
* import { TextAreaField } from "@trackunit/react-form-components";
|
|
3282
3821
|
*
|
|
3822
|
+
* <TextAreaField
|
|
3823
|
+
* label="Notes"
|
|
3824
|
+
* value={notes}
|
|
3825
|
+
* onChange={(e) => setNotes(e.target.value)}
|
|
3826
|
+
* errorMessage={notes.length < 10 ? "Notes must be at least 10 characters" : undefined}
|
|
3827
|
+
* />
|
|
3828
|
+
* ```
|
|
3283
3829
|
* @param {TextAreaFieldProps} props - The props for the TextAreaField component
|
|
3284
3830
|
* @returns {ReactElement} TextAreaField component
|
|
3285
3831
|
*/
|
|
@@ -3300,6 +3846,61 @@ TextAreaField.displayName = "TextAreaField";
|
|
|
3300
3846
|
|
|
3301
3847
|
/**
|
|
3302
3848
|
* Text fields enable the user to interact with and input content and data. This component can be used for long and short form entries. Allow the size of the text input box to reflect the length of the content you expect the user to enter.
|
|
3849
|
+
*
|
|
3850
|
+
* ### When to use
|
|
3851
|
+
* Use text fields for short-form text input such as names, emails, or search queries.
|
|
3852
|
+
*
|
|
3853
|
+
* ### When not to use
|
|
3854
|
+
* Do not use text fields for multi-line text input. Use TextAreaField instead.
|
|
3855
|
+
*
|
|
3856
|
+
* @example Basic text field
|
|
3857
|
+
* ```tsx
|
|
3858
|
+
* import { TextField } from "@trackunit/react-form-components";
|
|
3859
|
+
* import { useState } from "react";
|
|
3860
|
+
*
|
|
3861
|
+
* const MyForm = () => {
|
|
3862
|
+
* const [name, setName] = useState("");
|
|
3863
|
+
*
|
|
3864
|
+
* return (
|
|
3865
|
+
* <TextField
|
|
3866
|
+
* label="Name"
|
|
3867
|
+
* value={name}
|
|
3868
|
+
* onChange={(e) => setName(e.target.value)}
|
|
3869
|
+
* placeholder="Enter your name"
|
|
3870
|
+
* />
|
|
3871
|
+
* );
|
|
3872
|
+
* };
|
|
3873
|
+
* ```
|
|
3874
|
+
* @example Text field with validation and help text
|
|
3875
|
+
* ```tsx
|
|
3876
|
+
* import { TextField } from "@trackunit/react-form-components";
|
|
3877
|
+
* import { useState } from "react";
|
|
3878
|
+
*
|
|
3879
|
+
* const MyForm = () => {
|
|
3880
|
+
* const [email, setEmail] = useState("");
|
|
3881
|
+
* const [error, setError] = useState<string | undefined>();
|
|
3882
|
+
*
|
|
3883
|
+
* const handleBlur = () => {
|
|
3884
|
+
* if (!email.includes("@")) {
|
|
3885
|
+
* setError("Please enter a valid email address");
|
|
3886
|
+
* } else {
|
|
3887
|
+
* setError(undefined);
|
|
3888
|
+
* }
|
|
3889
|
+
* };
|
|
3890
|
+
*
|
|
3891
|
+
* return (
|
|
3892
|
+
* <TextField
|
|
3893
|
+
* label="Email"
|
|
3894
|
+
* value={email}
|
|
3895
|
+
* onChange={(e) => setEmail(e.target.value)}
|
|
3896
|
+
* onBlur={handleBlur}
|
|
3897
|
+
* errorMessage={error}
|
|
3898
|
+
* helpText="We'll never share your email"
|
|
3899
|
+
* required
|
|
3900
|
+
* />
|
|
3901
|
+
* );
|
|
3902
|
+
* };
|
|
3903
|
+
* ```
|
|
3303
3904
|
*/
|
|
3304
3905
|
const TextField = ({ id, label, tip, helpText, helpAddon, errorMessage, isInvalid, maxLength, onChange, className, value, "data-testid": dataTestId, isWarning, ref, ...rest }) => {
|
|
3305
3906
|
const [valueLength, setValueLength] = react.useState(value ? `${value}`.length : 0);
|
|
@@ -3402,11 +4003,55 @@ const cvaToggleSwitchThumb = cssClassVarianceUtilities.cvaMerge(["block", "round
|
|
|
3402
4003
|
});
|
|
3403
4004
|
|
|
3404
4005
|
/**
|
|
3405
|
-
*
|
|
3406
|
-
* or
|
|
4006
|
+
* The `<ToggleSwitch>` is a low-level checkbox input wrapper with `role="switch"`.
|
|
4007
|
+
* It renders just the switch control without label or description.
|
|
4008
|
+
*
|
|
4009
|
+
* **Not intended for standalone use** - use `ToggleSwitchOption` instead for forms.
|
|
4010
|
+
* This component is for building custom toggle implementations or wrapping in other components.
|
|
4011
|
+
*
|
|
4012
|
+
* ### When to use
|
|
4013
|
+
* - Building custom toggle components with different layouts
|
|
4014
|
+
* - Integrating a toggle into a component that provides its own label (e.g., menu items)
|
|
4015
|
+
* - Creating specialized switch controls
|
|
4016
|
+
*
|
|
4017
|
+
* ### When not to use
|
|
4018
|
+
* - Standard forms - use `ToggleSwitchOption` instead (includes label/description)
|
|
4019
|
+
* - Multiple selections - use `Checkbox` components instead
|
|
4020
|
+
*
|
|
4021
|
+
* @example Basic usage (in custom component)
|
|
4022
|
+
* ```tsx
|
|
4023
|
+
* import { ToggleSwitch } from "@trackunit/react-form-components";
|
|
3407
4024
|
*
|
|
3408
|
-
*
|
|
4025
|
+
* const [isEnabled, setIsEnabled] = useState(false);
|
|
4026
|
+
*
|
|
4027
|
+
* <ToggleSwitch
|
|
4028
|
+
* toggled={isEnabled}
|
|
4029
|
+
* onChange={(toggled) => setIsEnabled(toggled)}
|
|
4030
|
+
* />
|
|
4031
|
+
* ```
|
|
4032
|
+
* @example Inside a custom wrapper
|
|
4033
|
+
* ```tsx
|
|
4034
|
+
* import { ToggleSwitch } from "@trackunit/react-form-components";
|
|
4035
|
+
*
|
|
4036
|
+
* <div className="flex items-center gap-2">
|
|
4037
|
+
* <span>Dark Mode</span>
|
|
4038
|
+
* <ToggleSwitch
|
|
4039
|
+
* toggled={darkMode}
|
|
4040
|
+
* onChange={(toggled) => setDarkMode(toggled)}
|
|
4041
|
+
* size="small"
|
|
4042
|
+
* />
|
|
4043
|
+
* </div>
|
|
4044
|
+
* ```
|
|
4045
|
+
* @example Disabled state
|
|
4046
|
+
* ```tsx
|
|
4047
|
+
* import { ToggleSwitch } from "@trackunit/react-form-components";
|
|
3409
4048
|
*
|
|
4049
|
+
* <ToggleSwitch
|
|
4050
|
+
* toggled={true}
|
|
4051
|
+
* onChange={() => {}}
|
|
4052
|
+
* disabled
|
|
4053
|
+
* />
|
|
4054
|
+
* ```
|
|
3410
4055
|
* @param {ToggleSwitchProps} props - The props for the ToggleSwitch component
|
|
3411
4056
|
* @returns {ReactElement} ToggleSwitch component
|
|
3412
4057
|
*/
|
|
@@ -3453,13 +4098,65 @@ const ToggleSwitch = react.forwardRef(({ onChange, onClick, preventDefaultOnClic
|
|
|
3453
4098
|
ToggleSwitch.displayName = "ToggleSwitch";
|
|
3454
4099
|
|
|
3455
4100
|
/**
|
|
3456
|
-
*
|
|
3457
|
-
*
|
|
4101
|
+
* The `<ToggleSwitchOption>` component is used for binary on/off settings in forms.
|
|
4102
|
+
* It combines a toggle switch with a label and optional description for complete form integration.
|
|
4103
|
+
*
|
|
4104
|
+
* ### When to use
|
|
4105
|
+
* - Enable/disable feature toggles in settings
|
|
4106
|
+
* - Binary choices where the action takes effect immediately
|
|
4107
|
+
* - Preferences that represent on/off states
|
|
4108
|
+
*
|
|
4109
|
+
* ### When not to use
|
|
4110
|
+
* - Multiple selections from a list - use `Checkbox` components instead
|
|
4111
|
+
* - Mutually exclusive options - use `RadioGroup` instead
|
|
4112
|
+
* - Actions requiring confirmation - use buttons with confirmation dialog
|
|
4113
|
+
*
|
|
4114
|
+
* @example Basic usage
|
|
4115
|
+
* ```tsx
|
|
4116
|
+
* import { ToggleSwitchOption } from "@trackunit/react-form-components";
|
|
4117
|
+
*
|
|
4118
|
+
* const [notifications, setNotifications] = useState(true);
|
|
3458
4119
|
*
|
|
3459
|
-
*
|
|
4120
|
+
* <ToggleSwitchOption
|
|
4121
|
+
* id="notifications"
|
|
4122
|
+
* label="Enable Notifications"
|
|
4123
|
+
* toggled={notifications}
|
|
4124
|
+
* onChange={(toggled) => setNotifications(toggled)}
|
|
4125
|
+
* />
|
|
4126
|
+
* ```
|
|
4127
|
+
* @example With description
|
|
4128
|
+
* ```tsx
|
|
4129
|
+
* import { ToggleSwitchOption } from "@trackunit/react-form-components";
|
|
3460
4130
|
*
|
|
3461
|
-
*
|
|
4131
|
+
* <ToggleSwitchOption
|
|
4132
|
+
* id="email-alerts"
|
|
4133
|
+
* label="Email Alerts"
|
|
4134
|
+
* description="Receive email notifications for important updates"
|
|
4135
|
+
* toggled={emailAlerts}
|
|
4136
|
+
* onChange={(toggled) => setEmailAlerts(toggled)}
|
|
4137
|
+
* />
|
|
4138
|
+
* ```
|
|
4139
|
+
* @example In a settings list
|
|
4140
|
+
* ```tsx
|
|
4141
|
+
* import { ToggleSwitchOption } from "@trackunit/react-form-components";
|
|
3462
4142
|
*
|
|
4143
|
+
* <div className="space-y-4">
|
|
4144
|
+
* <ToggleSwitchOption
|
|
4145
|
+
* id="dark-mode"
|
|
4146
|
+
* label="Dark Mode"
|
|
4147
|
+
* description="Use dark theme throughout the application"
|
|
4148
|
+
* toggled={darkMode}
|
|
4149
|
+
* onChange={(toggled) => setDarkMode(toggled)}
|
|
4150
|
+
* />
|
|
4151
|
+
* <ToggleSwitchOption
|
|
4152
|
+
* id="auto-save"
|
|
4153
|
+
* label="Auto-save"
|
|
4154
|
+
* description="Automatically save changes as you type"
|
|
4155
|
+
* toggled={autoSave}
|
|
4156
|
+
* onChange={(toggled) => setAutoSave(toggled)}
|
|
4157
|
+
* />
|
|
4158
|
+
* </div>
|
|
4159
|
+
* ```
|
|
3463
4160
|
* @param {ToggleSwitchOptionProps} props - The props for the ToggleSwitchOption component
|
|
3464
4161
|
* @returns {ReactElement} ToggleSwitchOption component
|
|
3465
4162
|
*/
|
|
@@ -3499,7 +4196,53 @@ const UploadInput = ({ disabled, acceptedTypes, nonInteractive, uploadLabel, mul
|
|
|
3499
4196
|
UploadInput.displayName = "UploadInput";
|
|
3500
4197
|
|
|
3501
4198
|
/**
|
|
3502
|
-
*
|
|
4199
|
+
* The `<UploadField>` component enables users to upload files through a form field.
|
|
4200
|
+
* It wraps the UploadInput with FormGroup for consistent form styling including label,
|
|
4201
|
+
* help text, and error handling.
|
|
4202
|
+
*
|
|
4203
|
+
* ### When to use
|
|
4204
|
+
* - Single file upload in forms (documents, images)
|
|
4205
|
+
* - When you need form field styling (label, validation messages)
|
|
4206
|
+
* - File attachments in form submissions
|
|
4207
|
+
*
|
|
4208
|
+
* ### When not to use
|
|
4209
|
+
* - Drag and drop file uploads - use `DropZone` instead
|
|
4210
|
+
* - Multiple file uploads with preview - consider specialized upload component
|
|
4211
|
+
* - Large file uploads requiring progress indication
|
|
4212
|
+
*
|
|
4213
|
+
* @example Basic usage
|
|
4214
|
+
* ```tsx
|
|
4215
|
+
* import { UploadField } from "@trackunit/react-form-components";
|
|
4216
|
+
*
|
|
4217
|
+
* <UploadField
|
|
4218
|
+
* label="Upload Document"
|
|
4219
|
+
* accept=".pdf,.doc,.docx"
|
|
4220
|
+
* onChange={(file) => handleFileUpload(file)}
|
|
4221
|
+
* />
|
|
4222
|
+
* ```
|
|
4223
|
+
* @example With validation
|
|
4224
|
+
* ```tsx
|
|
4225
|
+
* import { UploadField } from "@trackunit/react-form-components";
|
|
4226
|
+
*
|
|
4227
|
+
* <UploadField
|
|
4228
|
+
* label="Profile Picture"
|
|
4229
|
+
* accept="image/*"
|
|
4230
|
+
* helpText="Max file size: 5MB"
|
|
4231
|
+
* errorMessage={fileTooLarge ? "File exceeds 5MB limit" : undefined}
|
|
4232
|
+
* required
|
|
4233
|
+
* />
|
|
4234
|
+
* ```
|
|
4235
|
+
* @example In a form context
|
|
4236
|
+
* ```tsx
|
|
4237
|
+
* import { UploadField } from "@trackunit/react-form-components";
|
|
4238
|
+
*
|
|
4239
|
+
* <UploadField
|
|
4240
|
+
* label="Attachment"
|
|
4241
|
+
* tip="Optional supporting document"
|
|
4242
|
+
* accept=".pdf"
|
|
4243
|
+
* onChange={(file) => setAttachment(file)}
|
|
4244
|
+
* />
|
|
4245
|
+
* ```
|
|
3503
4246
|
*/
|
|
3504
4247
|
const UploadField = ({ label, id, tip, helpText, errorMessage, isInvalid, className, value, "data-testid": dataTestId, ref, ...rest }) => {
|
|
3505
4248
|
const renderAsInvalid = isInvalid || Boolean(errorMessage);
|
|
@@ -3551,9 +4294,53 @@ const UrlBaseInput = ({ isInvalid = false, "data-testid": dataTestId, disabled =
|
|
|
3551
4294
|
};
|
|
3552
4295
|
|
|
3553
4296
|
/**
|
|
3554
|
-
* The UrlField component is used to enter
|
|
3555
|
-
*
|
|
4297
|
+
* The `<UrlField>` component is used to enter and validate URLs/web addresses.
|
|
4298
|
+
* It automatically validates the format on blur and displays appropriate error messages.
|
|
4299
|
+
*
|
|
4300
|
+
* ### When to use
|
|
4301
|
+
* - Collecting website URLs in forms
|
|
4302
|
+
* - Social media profile links
|
|
4303
|
+
* - Any input requiring valid URL format
|
|
3556
4304
|
*
|
|
4305
|
+
* ### When not to use
|
|
4306
|
+
* - General text input - use `TextField` instead
|
|
4307
|
+
* - Email addresses - use `EmailField` instead
|
|
4308
|
+
* - Internal application links - use standard link/routing
|
|
4309
|
+
*
|
|
4310
|
+
* @example Basic usage
|
|
4311
|
+
* ```tsx
|
|
4312
|
+
* import { UrlField } from "@trackunit/react-form-components";
|
|
4313
|
+
*
|
|
4314
|
+
* const [website, setWebsite] = useState("");
|
|
4315
|
+
*
|
|
4316
|
+
* <UrlField
|
|
4317
|
+
* label="Website"
|
|
4318
|
+
* value={website}
|
|
4319
|
+
* onChange={(e) => setWebsite(e.target.value)}
|
|
4320
|
+
* placeholder="https://example.com"
|
|
4321
|
+
* />
|
|
4322
|
+
* ```
|
|
4323
|
+
* @example With help text
|
|
4324
|
+
* ```tsx
|
|
4325
|
+
* import { UrlField } from "@trackunit/react-form-components";
|
|
4326
|
+
*
|
|
4327
|
+
* <UrlField
|
|
4328
|
+
* label="Company Website"
|
|
4329
|
+
* helpText="Enter the full URL including https://"
|
|
4330
|
+
* required
|
|
4331
|
+
* />
|
|
4332
|
+
* ```
|
|
4333
|
+
* @example With custom validation
|
|
4334
|
+
* ```tsx
|
|
4335
|
+
* import { UrlField } from "@trackunit/react-form-components";
|
|
4336
|
+
*
|
|
4337
|
+
* <UrlField
|
|
4338
|
+
* label="Documentation URL"
|
|
4339
|
+
* value={docUrl}
|
|
4340
|
+
* onChange={(e) => setDocUrl(e.target.value)}
|
|
4341
|
+
* errorMessage={!docUrl.includes("docs") ? "URL must point to documentation" : undefined}
|
|
4342
|
+
* />
|
|
4343
|
+
* ```
|
|
3557
4344
|
*/
|
|
3558
4345
|
const UrlField = ({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, "data-testid": dataTestId, isInvalid = false, value, onBlur, ref, ...rest }) => {
|
|
3559
4346
|
const htmlForId = id ? id : "urlField-" + sharedUtils.uuidv4();
|