@trackunit/react-form-components 1.11.17 → 1.11.19

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