@clubmed/trident-ui 2.0.0-beta.64 → 2.0.0-beta.65
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/chunks/Backdrop.js +1 -1
- package/chunks/Backdrop.js.map +1 -1
- package/chunks/DateField.js +2 -2
- package/chunks/DateField.js.map +1 -1
- package/package.json +1 -1
- package/styles/ui/controls.css +3 -6
- package/styles/ui/range.css +5 -0
- package/ui/AdvancedToast.js +2 -2
- package/ui/AdvancedToast.js.map +1 -1
- package/ui/Avatar.js +1 -1
- package/ui/Avatar.js.map +1 -1
- package/ui/BasicToast.js +2 -2
- package/ui/BasicToast.js.map +1 -1
- package/ui/Breadcrumb.js +1 -0
- package/ui/Breadcrumb.js.map +1 -1
- package/ui/ChatButton.js +1 -1
- package/ui/ChatButton.js.map +1 -1
- package/ui/ChatInput.js +1 -1
- package/ui/ChatInput.js.map +1 -1
- package/ui/ChatWindow.js +2 -2
- package/ui/ChatWindow.js.map +1 -1
- package/ui/ChatWindowCsatPrompt.js +1 -1
- package/ui/ChatWindowCsatPrompt.js.map +1 -1
- package/ui/ChoiceExpander.js +1 -1
- package/ui/ChoiceExpander.js.map +1 -1
- package/ui/ExpandableText.js +1 -1
- package/ui/ExpandableText.js.map +1 -1
- package/ui/HamburgerIcon.js +1 -1
- package/ui/HamburgerIcon.js.map +1 -1
- package/ui/Link.js +1 -1
- package/ui/Link.js.map +1 -1
- package/ui/PageNavigation.js +1 -1
- package/ui/PageNavigation.js.map +1 -1
- package/ui/Pagination.js +2 -2
- package/ui/Pagination.js.map +1 -1
- package/ui/SidebarLayout.js +4 -4
- package/ui/SidebarLayout.js.map +1 -1
- package/ui/Toggle.js +1 -1
- package/ui/Toggle.js.map +1 -1
- package/ui/buttons/Button.type.js +1 -1
- package/ui/buttons/Button.type.js.map +1 -1
- package/ui/forms/CheckboxSelect.js +1 -1
- package/ui/forms/CheckboxSelect.js.map +1 -1
- package/ui/forms/FloatingLabelTextField.js +2 -2
- package/ui/forms/FloatingLabelTextField.js.map +1 -1
- package/ui/forms/NumberField.js +1 -1
- package/ui/forms/NumberField.js.map +1 -1
- package/ui/forms/PhoneFieldFullInput.js +1 -1
- package/ui/forms/PhoneFieldFullInput.js.map +1 -1
- package/ui/forms/PhoneFieldSplitInput.js +2 -2
- package/ui/forms/PhoneFieldSplitInput.js.map +1 -1
- package/ui/forms/Select.js +1 -1
- package/ui/forms/Select.js.map +1 -1
- package/ui/forms/TextField.js +3 -3
- package/ui/forms/TextField.js.map +1 -1
- package/ui/forms/checkboxes/Checkbox.js +1 -1
- package/ui/forms/checkboxes/Checkbox.js.map +1 -1
- package/ui/forms/password/Password.js +2 -2
- package/ui/forms/password/Password.js.map +1 -1
- package/ui/journey-card/JourneyDetails.js +2 -2
- package/ui/journey-card/JourneyDetails.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingLabelTextField.js","names":[],"sources":["../../../lib/ui/forms/FloatingLabelTextField.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState, useRef } from 'react';\nimport clsx from 'clsx';\nimport { useValue, type UseValueProps } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControlError } from './FormControlError';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport { type FormControlProps } from './FormControl';\n\nexport interface FloatingLabelTextFieldProps<Value = string> extends FormControlProps<Value> {\n icon?: IconicNames;\n iconType?: IconicTypes;\n formatter?: UseValueProps<Value>['formatter'];\n hasDropdown?: boolean;\n clear?: string;\n iconFirst?: boolean;\n}\n\nexport const FloatingLabelTextField = <Value = string,>(\n props: FloatingLabelTextFieldProps<Value>,\n) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n labelClassName,\n value: initialValue,\n validationStatus = 'default',\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n description,\n icon,\n iconType,\n iconFirst = true,\n hasDropdown = false,\n clear = '',\n className,\n dataTestId,\n dataName,\n 'data-testid': dataTestIdProp,\n onChange,\n formatter,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange, formatter });\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const [focused, setFocused] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const isFloating = focused || (value !== '' && value !== null && value !== undefined);\n const showError = internalStatus === 'error' && errorMessage;\n const shouldDisplayClearButton =\n !disabled && value !== '' && value !== null && value !== undefined && !!clear;\n\n const nbIconsStart = Number(!!icon && iconFirst);\n const nbIconsEnd =\n Number(!!icon && !iconFirst) +\n Number(shouldDisplayClearButton || hasDropdown) +\n Number(internalStatus === 'error' || internalStatus === 'success');\n\n return (\n <div\n className={clsx('flex flex-col gap-4', className)}\n data-name={dataName ?? 'FloatingLabelTextField'}\n data-testid={dataTestIdProp ?? dataTestId}\n >\n <div className=\"relative\">\n <input\n {...rest}\n ref={inputRef}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as string}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n style={\n {\n '--nbIconsStart': nbIconsStart,\n '--nbIconsEnd': nbIconsEnd,\n } as React.CSSProperties\n }\n className={clsx(\n 'text-b3 rounded-pill w-full border h-60 font-normal outline-none',\n 'ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'pt-[26px] pb-[8px]': isFloating && label,\n 'py-12': !(isFloating && label),\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={label ? undefined : name}\n aria-invalid={internalStatus === 'error'}\n aria-describedby={showError ? `${id}-error` : undefined}\n />\n\n {label && (\n <label\n htmlFor={id}\n style={\n {\n left: `calc(20px + ${nbIconsStart} * 32px)`,\n } as React.CSSProperties\n }\n className={clsx(\n 'pointer-events-none absolute right-0 transition-all duration-150 select-none pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'top-[10px] text-b6 font-semibold': isFloating,\n 'top-1/2 -translate-y-1/2 text-b3 font-normal': !isFloating,\n 'text-red': internalStatus === 'error' && isFloating,\n 'text-middleGrey': internalStatus !== 'error' && isFloating,\n 'text-black': !isFloating && internalStatus !== 'disabled',\n 'text-grey': internalStatus === 'disabled',\n },\n labelClassName,\n )}\n >\n {label}\n {required && !hideRequiredStar && (\n <span className=\"text-red ms-4\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && iconFirst && <Icon name={icon} width=\"24px\" />}\n\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n {(hasDropdown || shouldDisplayClearButton) &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" className=\"text-black\" width=\"24px\" />\n </button>\n ) : (\n <Icon name=\"ArrowDefaultDown\" className=\"text-black\" width=\"24px\" />\n ))}\n {!iconFirst && icon && <Icon name={icon} width=\"24px\" />}\n </span>\n </div>\n </div>\n\n {description && (\n <span className=\"text-b4 text-darkGrey font-normal px-20\">{description}</span>\n )}\n\n {showError && <FormControlError id={`${id}-error`}>{errorMessage}</FormControlError>}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAmBA,IAAa,KACX,MACG;CACH,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,mBACA,OAAO,GACP,sBAAmB,WACnB,iBACA,cAAW,IACX,cAAW,IACX,qBACA,gBACA,SACA,aACA,eAAY,IACZ,iBAAc,IACd,WAAQ,IACR,cACA,eACA,aACA,eAAe,GACf,aACA,cACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU;EAAW,CAAC,EAC5E,IAAiB,EAAkB;EAAE,YAAY;EAAU;EAAkB,CAAC,EAC9E,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,IAAW,EAAyB,KAAK,EAEzC,IAAa,KAAY,MAAU,MAAM,KAAU,MACnD,IAAY,MAAmB,WAAW,GAC1C,IACJ,CAAC,KAAY,MAAU,MAAM,KAAU,QAA+B,CAAC,CAAC,GAEpE,IAAe,OAAO,CAAC,CAAC,KAAQ,EAAU,EAC1C,IACJ,OAAO,CAAC,CAAC,KAAQ,CAAC,EAAU,GAC5B,OAAO,KAA4B,EAAY,GAC/C,OAAO,MAAmB,WAAW,MAAmB,UAAU;AAEpE,QACE,kBAAC,OAAD;EACE,WAAW,EAAK,uBAAuB,EAAU;EACjD,aAAW,KAAY;EACvB,eAAa,KAAkB;YAHjC;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MACE,GAAI;MACJ,KAAK;MACD;MACE;MACI;MACA;MACH;MACP,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;MACjE,eAAe,EAAW,GAAK;MAC/B,cAAc,EAAW,GAAM;MAC/B,OACE;OACE,kBAAkB;OAClB,gBAAgB;OACjB;MAEH,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"FloatingLabelTextField.js","names":[],"sources":["../../../lib/ui/forms/FloatingLabelTextField.tsx"],"sourcesContent":["'use client';\n\nimport { useId, useState, useRef } from 'react';\nimport clsx from 'clsx';\nimport { useValue, type UseValueProps } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControlError } from './FormControlError';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport { type FormControlProps } from './FormControl';\n\nexport interface FloatingLabelTextFieldProps<Value = string> extends FormControlProps<Value> {\n icon?: IconicNames;\n iconType?: IconicTypes;\n formatter?: UseValueProps<Value>['formatter'];\n hasDropdown?: boolean;\n clear?: string;\n iconFirst?: boolean;\n}\n\nexport const FloatingLabelTextField = <Value = string,>(\n props: FloatingLabelTextFieldProps<Value>,\n) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n labelClassName,\n value: initialValue,\n validationStatus = 'default',\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n description,\n icon,\n iconType,\n iconFirst = true,\n hasDropdown = false,\n clear = '',\n className,\n dataTestId,\n dataName,\n 'data-testid': dataTestIdProp,\n onChange,\n formatter,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange, formatter });\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const [focused, setFocused] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const isFloating = focused || (value !== '' && value !== null && value !== undefined);\n const showError = internalStatus === 'error' && errorMessage;\n const shouldDisplayClearButton =\n !disabled && value !== '' && value !== null && value !== undefined && !!clear;\n\n const nbIconsStart = Number(!!icon && iconFirst);\n const nbIconsEnd =\n Number(!!icon && !iconFirst) +\n Number(shouldDisplayClearButton || hasDropdown) +\n Number(internalStatus === 'error' || internalStatus === 'success');\n\n return (\n <div\n className={clsx('flex flex-col gap-4', className)}\n data-name={dataName ?? 'FloatingLabelTextField'}\n data-testid={dataTestIdProp ?? dataTestId}\n >\n <div className=\"relative\">\n <input\n {...rest}\n ref={inputRef}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as string}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n style={\n {\n '--nbIconsStart': nbIconsStart,\n '--nbIconsEnd': nbIconsEnd,\n } as React.CSSProperties\n }\n className={clsx(\n 'text-b3 rounded-pill w-full border h-60 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n 'ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'pt-[26px] pb-[8px]': isFloating && label,\n 'py-12': !(isFloating && label),\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={label ? undefined : name}\n aria-invalid={internalStatus === 'error'}\n aria-describedby={showError ? `${id}-error` : undefined}\n />\n\n {label && (\n <label\n htmlFor={id}\n style={\n {\n left: `calc(20px + ${nbIconsStart} * 32px)`,\n } as React.CSSProperties\n }\n className={clsx(\n 'pointer-events-none absolute right-0 transition-all duration-150 select-none pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'top-[10px] text-b6 font-semibold': isFloating,\n 'top-1/2 -translate-y-1/2 text-b3 font-normal': !isFloating,\n 'text-red': internalStatus === 'error' && isFloating,\n 'text-middleGrey': internalStatus !== 'error' && isFloating,\n 'text-black': !isFloating && internalStatus !== 'disabled',\n 'text-grey': internalStatus === 'disabled',\n },\n labelClassName,\n )}\n >\n {label}\n {required && !hideRequiredStar && (\n <span className=\"text-red ms-4\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && iconFirst && <Icon name={icon} width=\"24px\" />}\n\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n {(hasDropdown || shouldDisplayClearButton) &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" className=\"text-black\" width=\"24px\" />\n </button>\n ) : (\n <Icon name=\"ArrowDefaultDown\" className=\"text-black\" width=\"24px\" />\n ))}\n {!iconFirst && icon && <Icon name={icon} width=\"24px\" />}\n </span>\n </div>\n </div>\n\n {description && (\n <span className=\"text-b4 text-darkGrey font-normal px-20\">{description}</span>\n )}\n\n {showError && <FormControlError id={`${id}-error`}>{errorMessage}</FormControlError>}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAmBA,IAAa,KACX,MACG;CACH,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,mBACA,OAAO,GACP,sBAAmB,WACnB,iBACA,cAAW,IACX,cAAW,IACX,qBACA,gBACA,SACA,aACA,eAAY,IACZ,iBAAc,IACd,WAAQ,IACR,cACA,eACA,aACA,eAAe,GACf,aACA,cACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU;EAAW,CAAC,EAC5E,IAAiB,EAAkB;EAAE,YAAY;EAAU;EAAkB,CAAC,EAC9E,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,IAAW,EAAyB,KAAK,EAEzC,IAAa,KAAY,MAAU,MAAM,KAAU,MACnD,IAAY,MAAmB,WAAW,GAC1C,IACJ,CAAC,KAAY,MAAU,MAAM,KAAU,QAA+B,CAAC,CAAC,GAEpE,IAAe,OAAO,CAAC,CAAC,KAAQ,EAAU,EAC1C,IACJ,OAAO,CAAC,CAAC,KAAQ,CAAC,EAAU,GAC5B,OAAO,KAA4B,EAAY,GAC/C,OAAO,MAAmB,WAAW,MAAmB,UAAU;AAEpE,QACE,kBAAC,OAAD;EACE,WAAW,EAAK,uBAAuB,EAAU;EACjD,aAAW,KAAY;EACvB,eAAa,KAAkB;YAHjC;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MACE,GAAI;MACJ,KAAK;MACD;MACE;MACI;MACA;MACH;MACP,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;MACjE,eAAe,EAAW,GAAK;MAC/B,cAAc,EAAW,GAAM;MAC/B,OACE;OACE,kBAAkB;OAClB,gBAAgB;OACjB;MAEH,WAAW,EACT,8IACA,mFACA;OACE,sBAAsB,KAAc;OACpC,SAAS,EAAE,KAAc;OACzB,4DACE,MAAmB;OACrB,uBAAuB,MAAmB;OAC1C,8BAA8B,MAAmB;OACjD,cAAc,MAAmB;OACjC,gBAAgB,MAAmB;OACpC,CACF;MACD,cAAY,IAAQ,KAAA,IAAY;MAChC,gBAAc,MAAmB;MACjC,oBAAkB,IAAY,GAAG,EAAG,UAAU,KAAA;MAC9C,CAAA;KAED,KACC,kBAAC,SAAD;MACE,SAAS;MACT,OACE,EACE,MAAM,eAAe,EAAa,WACnC;MAEH,WAAW,EACT,uHACA;OACE,oCAAoC;OACpC,gDAAgD,CAAC;OACjD,YAAY,MAAmB,WAAW;OAC1C,mBAAmB,MAAmB,WAAW;OACjD,cAAc,CAAC,KAAc,MAAmB;OAChD,aAAa,MAAmB;OACjC,EACD,EACD;gBAlBH,CAoBG,GACA,KAAY,CAAC,KACZ,kBAAC,QAAD;OAAM,WAAU;OAAgB,eAAY;iBAAO;OAE5C,CAAA,CAAA;;KAKb,kBAAC,OAAD;MACE,WAAW,EACT,sFACA;OACE,aAAa,MAAmB;OAChC,YAAY,MAAmB;OAC/B,cAAc,MAAmB;OAClC,CACF;gBARH,CAUG,KAAQ,KAAa,kBAAC,GAAD;OAAM,MAAM;OAAM,OAAM;OAAS,CAAA,EAEvD,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACG,MAAmB,WAClB,kBAAC,GAAD;SAAM,MAAK;SAAe,OAAM;SAAO,MAAM;SAAY,CAAA;QAE1D,MAAmB,aAClB,kBAAC,GAAD;SAAM,MAAK;SAAe,OAAM;SAAO,MAAM;SAAY,CAAA;SAEzD,KAAe,OACd,IACC,kBAAC,UAAD;SACE,WAAU;SACV,UAAU,MAAM,EAAS,IAAa,EAAE,YAAY;SACpD,cAAY;SACZ,MAAK;mBAEL,kBAAC,GAAD;UAAM,MAAK;UAAe,WAAU;UAAa,OAAM;UAAS,CAAA;SACzD,CAAA,GAET,kBAAC,GAAD;SAAM,MAAK;SAAmB,WAAU;SAAa,OAAM;SAAS,CAAA;QAEvE,CAAC,KAAa,KAAQ,kBAAC,GAAD;SAAM,MAAM;SAAM,OAAM;SAAS,CAAA;;;;;;GAK7D,KACC,kBAAC,QAAD;IAAM,WAAU;cAA2C;IAAmB,CAAA;GAG/E,KAAa,kBAAC,GAAD;IAAkB,IAAI,GAAG,EAAG;cAAU;IAAgC,CAAA"}
|
package/ui/forms/NumberField.js
CHANGED
|
@@ -67,7 +67,7 @@ var l = (r) => {
|
|
|
67
67
|
}),
|
|
68
68
|
/* @__PURE__ */ a("input", {
|
|
69
69
|
...T,
|
|
70
|
-
className: e("text-b2 text-center font-bold outline-none", { "bg-pearl text-grey": i }),
|
|
70
|
+
className: e("text-b2 text-center font-bold outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", { "bg-pearl text-grey": i }),
|
|
71
71
|
style: s,
|
|
72
72
|
type: "number",
|
|
73
73
|
title: w.input,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberField.js","names":[],"sources":["../../../lib/ui/forms/NumberField.tsx"],"sourcesContent":["import clsx from 'clsx';\n\nimport { type ChangeEvent, type MouseEvent, useId } from 'react';\n\nimport { useValue } from '../hooks/useValue';\nimport { Button } from '../buttons/Button';\nimport { FormControl, type FormControlProps } from './FormControl';\n\ninterface NumberFieldProps extends FormControlProps<number> {\n min?: number;\n max?: number;\n labels: {\n increase: string;\n decrease: string;\n input: string;\n };\n}\n\nconst INPUT_STYLE = { width: '28px', height: '28px' };\n\nexport function useNumberField(props: NumberFieldProps) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n value: initialValue = 0,\n onChange,\n min = 0,\n max = 10,\n disabled = false,\n dataTestId = 'NumberField',\n inline = true,\n labels,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<number, string | number | boolean>({\n defaultValue: initialValue,\n formatter: Number,\n onChange,\n });\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = Number(e.target.value);\n\n if (newValue >= min && newValue <= max) {\n setValue(Number(newValue), e.nativeEvent);\n }\n };\n\n const increase = (event?: Event) => {\n if (value < max) {\n setValue(value + 1, event);\n }\n };\n\n const decrease = (event?: Event) => {\n if (value > min) {\n setValue(value - 1, event);\n }\n };\n\n return {\n ...rest,\n id,\n min,\n max,\n name,\n value,\n dataTestId,\n disabled,\n inline,\n labels,\n handleChange,\n increase,\n decrease,\n };\n}\n\nexport const NumberField = (props: NumberFieldProps) => {\n const {\n disabled,\n min,\n max,\n label,\n description,\n id,\n dataTestId,\n value,\n handleChange,\n increase,\n decrease,\n errorMessage,\n validationStatus,\n hideRequiredStar,\n required,\n inline,\n labels,\n ...rest\n } = useNumberField(props);\n\n return (\n <FormControl\n id={id}\n label={label}\n description={description}\n className={clsx('flex items-center', props.className)}\n dataName=\"NumberField\"\n dataTestId={dataTestId}\n errorMessage={errorMessage}\n validationStatus={validationStatus}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n layout=\"vertical\"\n inline={inline}\n >\n <div className=\"flex items-center gap-x-8\">\n <Button\n onClick={(e: MouseEvent<HTMLButtonElement>) => decrease(e.nativeEvent)}\n variant=\"circle\"\n disabled={value <= min || disabled}\n icon=\"MinusDefault\"\n aria-label={labels.decrease}\n data-testid={`${dataTestId}-decrease`}\n />\n <input\n {...rest}\n className={clsx('text-b2 text-center font-bold outline-none'
|
|
1
|
+
{"version":3,"file":"NumberField.js","names":[],"sources":["../../../lib/ui/forms/NumberField.tsx"],"sourcesContent":["import clsx from 'clsx';\n\nimport { type ChangeEvent, type MouseEvent, useId } from 'react';\n\nimport { useValue } from '../hooks/useValue';\nimport { Button } from '../buttons/Button';\nimport { FormControl, type FormControlProps } from './FormControl';\n\ninterface NumberFieldProps extends FormControlProps<number> {\n min?: number;\n max?: number;\n labels: {\n increase: string;\n decrease: string;\n input: string;\n };\n}\n\nconst INPUT_STYLE = { width: '28px', height: '28px' };\n\nexport function useNumberField(props: NumberFieldProps) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n value: initialValue = 0,\n onChange,\n min = 0,\n max = 10,\n disabled = false,\n dataTestId = 'NumberField',\n inline = true,\n labels,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<number, string | number | boolean>({\n defaultValue: initialValue,\n formatter: Number,\n onChange,\n });\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n const newValue = Number(e.target.value);\n\n if (newValue >= min && newValue <= max) {\n setValue(Number(newValue), e.nativeEvent);\n }\n };\n\n const increase = (event?: Event) => {\n if (value < max) {\n setValue(value + 1, event);\n }\n };\n\n const decrease = (event?: Event) => {\n if (value > min) {\n setValue(value - 1, event);\n }\n };\n\n return {\n ...rest,\n id,\n min,\n max,\n name,\n value,\n dataTestId,\n disabled,\n inline,\n labels,\n handleChange,\n increase,\n decrease,\n };\n}\n\nexport const NumberField = (props: NumberFieldProps) => {\n const {\n disabled,\n min,\n max,\n label,\n description,\n id,\n dataTestId,\n value,\n handleChange,\n increase,\n decrease,\n errorMessage,\n validationStatus,\n hideRequiredStar,\n required,\n inline,\n labels,\n ...rest\n } = useNumberField(props);\n\n return (\n <FormControl\n id={id}\n label={label}\n description={description}\n className={clsx('flex items-center', props.className)}\n dataName=\"NumberField\"\n dataTestId={dataTestId}\n errorMessage={errorMessage}\n validationStatus={validationStatus}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n layout=\"vertical\"\n inline={inline}\n >\n <div className=\"flex items-center gap-x-8\">\n <Button\n onClick={(e: MouseEvent<HTMLButtonElement>) => decrease(e.nativeEvent)}\n variant=\"circle\"\n disabled={value <= min || disabled}\n icon=\"MinusDefault\"\n aria-label={labels.decrease}\n data-testid={`${dataTestId}-decrease`}\n />\n <input\n {...rest}\n className={clsx(\n 'text-b2 text-center font-bold outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n {\n 'bg-pearl text-grey': disabled,\n },\n )}\n style={INPUT_STYLE}\n type=\"number\"\n title={labels.input}\n id={id}\n onChange={handleChange}\n disabled={disabled}\n required={required}\n value={value}\n min={min}\n max={max}\n />\n <Button\n onClick={(e: MouseEvent<HTMLButtonElement>) => increase(e.nativeEvent)}\n variant=\"circle\"\n aria-label={labels.increase}\n disabled={value >= max || disabled}\n icon=\"PlusDefault\"\n data-testid={`${dataTestId}-increase`}\n />\n </div>\n </FormControl>\n );\n};\n"],"mappings":";;;;;;;AAkBA,IAAM,IAAc;CAAE,OAAO;CAAQ,QAAQ;CAAQ;AAErD,SAAgB,EAAe,GAAyB;CACtD,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,OAAO,IAAe,GACtB,aACA,SAAM,GACN,SAAM,IACN,cAAW,IACX,gBAAa,eACb,YAAS,IACT,WACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAA4C;EACtE,cAAc;EACd,WAAW;EACX;EACD,CAAC,EAEI,KAAgB,MAAqC;EACzD,IAAM,IAAW,OAAO,EAAE,OAAO,MAAM;AAEvC,EAAI,KAAY,KAAO,KAAY,KACjC,EAAS,OAAO,EAAS,EAAE,EAAE,YAAY;IAIvC,KAAY,MAAkB;AAClC,EAAI,IAAQ,KACV,EAAS,IAAQ,GAAG,EAAM;IAIxB,KAAY,MAAkB;AAClC,EAAI,IAAQ,KACV,EAAS,IAAQ,GAAG,EAAM;;AAI9B,QAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;AAGH,IAAa,KAAe,MAA4B;CACtD,IAAM,EACJ,aACA,QACA,QACA,UACA,gBACA,OACA,eACA,UACA,iBACA,aACA,aACA,iBACA,qBACA,qBACA,aACA,WACA,WACA,GAAG,MACD,EAAe,EAAM;AAEzB,QACE,kBAAC,GAAD;EACM;EACG;EACM;EACb,WAAW,EAAK,qBAAqB,EAAM,UAAU;EACrD,UAAS;EACG;EACE;EACI;EACR;EACA;EACQ;EAClB,QAAO;EACC;YAER,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,UAAU,MAAqC,EAAS,EAAE,YAAY;KACtE,SAAQ;KACR,UAAU,KAAS,KAAO;KAC1B,MAAK;KACL,cAAY,EAAO;KACnB,eAAa,GAAG,EAAW;KAC3B,CAAA;IACF,kBAAC,SAAD;KACE,GAAI;KACJ,WAAW,EACT,wHACA,EACE,sBAAsB,GACvB,CACF;KACD,OAAO;KACP,MAAK;KACL,OAAO,EAAO;KACV;KACJ,UAAU;KACA;KACA;KACH;KACF;KACA;KACL,CAAA;IACF,kBAAC,GAAD;KACE,UAAU,MAAqC,EAAS,EAAE,YAAY;KACtE,SAAQ;KACR,cAAY,EAAO;KACnB,UAAU,KAAS,KAAO;KAC1B,MAAK;KACL,eAAa,GAAG,EAAW;KAC3B,CAAA;IACE;;EACM,CAAA"}
|
|
@@ -70,7 +70,7 @@ var g = (e) => {
|
|
|
70
70
|
onChange: E,
|
|
71
71
|
onKeyDown: T,
|
|
72
72
|
placeholder: o,
|
|
73
|
-
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none", {
|
|
73
|
+
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", {
|
|
74
74
|
"border-middleGrey focus:border-black active:border-black": S === "default",
|
|
75
75
|
"ps-[52px]": s,
|
|
76
76
|
"pe-[52px]": S === "error" || S === "success",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneFieldFullInput.js","names":[],"sources":["../../../lib/ui/forms/PhoneFieldFullInput.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport {\n type ChangeEvent,\n type InputHTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport {\n calculateCursorPosition,\n extractDigits,\n formatPhoneDigits,\n formatWithPattern,\n getLiteralPrefixInfo,\n stripLiteralPrefix,\n} from '../helpers/phone';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport type { FormControlProps } from './FormControl';\nimport type { PhoneValue } from './PhoneField';\n\nexport interface PhoneFieldFullProps {\n icon?: IconicNames;\n}\n\nconst usePhoneField = (args: {\n externalValue?: PhoneValue;\n pattern: string;\n onChange?: (event: Event, value: PhoneValue) => void;\n}) => {\n const { externalValue, pattern, onChange } = args;\n const inputRef = useRef<HTMLInputElement>(null);\n const cursorPositionRef = useRef<number | null>(null);\n const [value, setValue] = useState('');\n\n useEffect(() => {\n if (cursorPositionRef.current !== null && inputRef.current) {\n inputRef.current.setSelectionRange(cursorPositionRef.current, cursorPositionRef.current);\n cursorPositionRef.current = null;\n }\n }, [value]);\n\n useEffect(() => {\n if (externalValue && typeof externalValue === 'object' && 'full' in externalValue) {\n setValue(externalValue.full || '');\n }\n }, [externalValue]);\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Backspace' && e.key !== 'Delete') return;\n const cursorPosition = e.currentTarget.selectionStart || 0;\n const selectionEnd = e.currentTarget.selectionEnd || 0;\n if (cursorPosition !== selectionEnd) return;\n\n const { literalPrefixDigits } = getLiteralPrefixInfo(pattern);\n const targetChar = e.key === 'Backspace' ? value[cursorPosition - 1] : value[cursorPosition];\n if (!targetChar || /\\d/.test(targetChar)) return;\n\n e.preventDefault();\n const allDigits = stripLiteralPrefix(extractDigits(value), literalPrefixDigits);\n const digitsBeforeCursor = stripLiteralPrefix(\n extractDigits(value.substring(0, cursorPosition)),\n literalPrefixDigits,\n ).length;\n\n let newDigits: string;\n let targetCursorDigits: number;\n if (e.key === 'Backspace') {\n if (digitsBeforeCursor === 0) return;\n newDigits =\n allDigits.slice(0, digitsBeforeCursor - 1) + allDigits.slice(digitsBeforeCursor);\n targetCursorDigits = digitsBeforeCursor - 1;\n } else {\n if (digitsBeforeCursor >= allDigits.length) return;\n newDigits =\n allDigits.slice(0, digitsBeforeCursor) + allDigits.slice(digitsBeforeCursor + 1);\n targetCursorDigits = digitsBeforeCursor;\n }\n\n const formatted = formatWithPattern(newDigits, pattern);\n cursorPositionRef.current = calculateCursorPosition(\n targetCursorDigits,\n formatted,\n literalPrefixDigits,\n );\n setValue(formatted);\n onChange?.(e.nativeEvent, { full: formatted, raw: extractDigits(formatted) });\n },\n [pattern, value, onChange],\n );\n\n const onInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const formattedValue = formatPhoneDigits(\n e.target.value,\n pattern,\n e.target.selectionStart || 0,\n );\n if (!formattedValue) return;\n cursorPositionRef.current = formattedValue.nextCursor;\n setValue(formattedValue.formatted);\n\n onChange?.(e.nativeEvent, {\n full: formattedValue.formatted,\n raw: extractDigits(formattedValue.formatted),\n });\n },\n [pattern, onChange],\n );\n\n return { inputRef, value, onKeyDown, onInputChange };\n};\n\nexport interface PhoneFieldFullInputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'pattern'> {\n value?: PhoneValue;\n pattern?: string;\n icon?: PhoneFieldFullProps['icon'];\n iconType?: IconicTypes;\n validationStatus?: FormControlProps<PhoneValue>['validationStatus'];\n onChange?: (event: Event, value: PhoneValue) => void;\n}\n\nexport const PhoneFieldFullInput = ({\n id,\n name,\n value: externalValue,\n pattern = '## ## ## ## ##',\n placeholder = '',\n icon,\n iconType,\n disabled = false,\n required = false,\n validationStatus = 'default',\n onChange,\n ...inputProps\n}: PhoneFieldFullInputProps) => {\n const internalId = useId();\n const resolvedId = id ?? internalId;\n const resolvedName = name ?? resolvedId;\n\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const { inputRef, value, onKeyDown, onInputChange } = usePhoneField({\n externalValue,\n pattern,\n onChange,\n });\n\n return (\n <div className=\"relative\">\n <input\n {...(inputProps as any)}\n ref={inputRef}\n id={resolvedId}\n name={resolvedName}\n type=\"tel\"\n disabled={disabled}\n required={required}\n value={value}\n onChange={onInputChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'ps-[52px]': icon,\n 'pe-[52px]': internalStatus === 'error' || internalStatus === 'success',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={resolvedName}\n />\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && <Icon name={icon} width=\"24px\" />}\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n </span>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;AA4BA,IAAM,KAAiB,MAIjB;CACJ,IAAM,EAAE,kBAAe,YAAS,gBAAa,GACvC,IAAW,EAAyB,KAAK,EACzC,IAAoB,EAAsB,KAAK,EAC/C,CAAC,GAAO,KAAY,EAAS,GAAG;AA8EtC,QA5EA,QAAgB;AACd,EAAI,EAAkB,YAAY,QAAQ,EAAS,YACjD,EAAS,QAAQ,kBAAkB,EAAkB,SAAS,EAAkB,QAAQ,EACxF,EAAkB,UAAU;IAE7B,CAAC,EAAM,CAAC,EAEX,QAAgB;AACd,EAAI,KAAiB,OAAO,KAAkB,YAAY,UAAU,KAClE,EAAS,EAAc,QAAQ,GAAG;IAEnC,CAAC,EAAc,CAAC,EAiEZ;EAAE;EAAU;EAAO,WA/DR,GACf,MAAuC;AACtC,OAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,SAAU;GACjD,IAAM,IAAiB,EAAE,cAAc,kBAAkB;AAEzD,OAAI,OADiB,EAAE,cAAc,gBAAgB,GAChB;GAErC,IAAM,EAAE,2BAAwB,EAAqB,EAAQ,EACvD,IAAa,EAAE,QAAQ,cAAc,EAAM,IAAiB,KAAK,EAAM;AAC7E,OAAI,CAAC,KAAc,KAAK,KAAK,EAAW,CAAE;AAE1C,KAAE,gBAAgB;GAClB,IAAM,IAAY,EAAmB,EAAc,EAAM,EAAE,EAAoB,EACzE,IAAqB,EACzB,EAAc,EAAM,UAAU,GAAG,EAAe,CAAC,EACjD,EACD,CAAC,QAEE,GACA;AACJ,OAAI,EAAE,QAAQ,aAAa;AACzB,QAAI,MAAuB,EAAG;AAG9B,IAFA,IACE,EAAU,MAAM,GAAG,IAAqB,EAAE,GAAG,EAAU,MAAM,EAAmB,EAClF,IAAqB,IAAqB;UACrC;AACL,QAAI,KAAsB,EAAU,OAAQ;AAG5C,IAFA,IACE,EAAU,MAAM,GAAG,EAAmB,GAAG,EAAU,MAAM,IAAqB,EAAE,EAClF,IAAqB;;GAGvB,IAAM,IAAY,EAAkB,GAAW,EAAQ;AAOvD,GANA,EAAkB,UAAU,EAC1B,GACA,GACA,EACD,EACD,EAAS,EAAU,EACnB,IAAW,EAAE,aAAa;IAAE,MAAM;IAAW,KAAK,EAAc,EAAU;IAAE,CAAC;KAE/E;GAAC;GAAS;GAAO;GAAS,CAC3B;EAqBoC,eAnBf,GACnB,MAAqC;GACpC,IAAM,IAAiB,EACrB,EAAE,OAAO,OACT,GACA,EAAE,OAAO,kBAAkB,EAC5B;AACI,SACL,EAAkB,UAAU,EAAe,YAC3C,EAAS,EAAe,UAAU,EAElC,IAAW,EAAE,aAAa;IACxB,MAAM,EAAe;IACrB,KAAK,EAAc,EAAe,UAAU;IAC7C,CAAC;KAEJ,CAAC,GAAS,EAAS,CACpB;EAEmD;GAazC,KAAuB,EAClC,OACA,SACA,OAAO,GACP,aAAU,kBACV,iBAAc,IACd,SACA,aACA,cAAW,IACX,cAAW,IACX,sBAAmB,WACnB,aACA,GAAG,QAC2B;CAC9B,IAAM,IAAa,GAAO,EACpB,IAAa,KAAM,GACnB,IAAe,KAAQ,GAEvB,IAAiB,EAAkB;EAAE,YAAY;EAAU;EAAkB,CAAC,EAC9E,EAAE,aAAU,UAAO,cAAW,qBAAkB,EAAc;EAClE;EACA;EACA;EACD,CAAC;AAEF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,SAAD;GACE,GAAK;GACL,KAAK;GACL,IAAI;GACJ,MAAM;GACN,MAAK;GACK;GACA;GACH;GACP,UAAU;GACC;GACE;GACb,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"PhoneFieldFullInput.js","names":[],"sources":["../../../lib/ui/forms/PhoneFieldFullInput.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport {\n type ChangeEvent,\n type InputHTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport {\n calculateCursorPosition,\n extractDigits,\n formatPhoneDigits,\n formatWithPattern,\n getLiteralPrefixInfo,\n stripLiteralPrefix,\n} from '../helpers/phone';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport type { FormControlProps } from './FormControl';\nimport type { PhoneValue } from './PhoneField';\n\nexport interface PhoneFieldFullProps {\n icon?: IconicNames;\n}\n\nconst usePhoneField = (args: {\n externalValue?: PhoneValue;\n pattern: string;\n onChange?: (event: Event, value: PhoneValue) => void;\n}) => {\n const { externalValue, pattern, onChange } = args;\n const inputRef = useRef<HTMLInputElement>(null);\n const cursorPositionRef = useRef<number | null>(null);\n const [value, setValue] = useState('');\n\n useEffect(() => {\n if (cursorPositionRef.current !== null && inputRef.current) {\n inputRef.current.setSelectionRange(cursorPositionRef.current, cursorPositionRef.current);\n cursorPositionRef.current = null;\n }\n }, [value]);\n\n useEffect(() => {\n if (externalValue && typeof externalValue === 'object' && 'full' in externalValue) {\n setValue(externalValue.full || '');\n }\n }, [externalValue]);\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Backspace' && e.key !== 'Delete') return;\n const cursorPosition = e.currentTarget.selectionStart || 0;\n const selectionEnd = e.currentTarget.selectionEnd || 0;\n if (cursorPosition !== selectionEnd) return;\n\n const { literalPrefixDigits } = getLiteralPrefixInfo(pattern);\n const targetChar = e.key === 'Backspace' ? value[cursorPosition - 1] : value[cursorPosition];\n if (!targetChar || /\\d/.test(targetChar)) return;\n\n e.preventDefault();\n const allDigits = stripLiteralPrefix(extractDigits(value), literalPrefixDigits);\n const digitsBeforeCursor = stripLiteralPrefix(\n extractDigits(value.substring(0, cursorPosition)),\n literalPrefixDigits,\n ).length;\n\n let newDigits: string;\n let targetCursorDigits: number;\n if (e.key === 'Backspace') {\n if (digitsBeforeCursor === 0) return;\n newDigits =\n allDigits.slice(0, digitsBeforeCursor - 1) + allDigits.slice(digitsBeforeCursor);\n targetCursorDigits = digitsBeforeCursor - 1;\n } else {\n if (digitsBeforeCursor >= allDigits.length) return;\n newDigits =\n allDigits.slice(0, digitsBeforeCursor) + allDigits.slice(digitsBeforeCursor + 1);\n targetCursorDigits = digitsBeforeCursor;\n }\n\n const formatted = formatWithPattern(newDigits, pattern);\n cursorPositionRef.current = calculateCursorPosition(\n targetCursorDigits,\n formatted,\n literalPrefixDigits,\n );\n setValue(formatted);\n onChange?.(e.nativeEvent, { full: formatted, raw: extractDigits(formatted) });\n },\n [pattern, value, onChange],\n );\n\n const onInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const formattedValue = formatPhoneDigits(\n e.target.value,\n pattern,\n e.target.selectionStart || 0,\n );\n if (!formattedValue) return;\n cursorPositionRef.current = formattedValue.nextCursor;\n setValue(formattedValue.formatted);\n\n onChange?.(e.nativeEvent, {\n full: formattedValue.formatted,\n raw: extractDigits(formattedValue.formatted),\n });\n },\n [pattern, onChange],\n );\n\n return { inputRef, value, onKeyDown, onInputChange };\n};\n\nexport interface PhoneFieldFullInputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'pattern'> {\n value?: PhoneValue;\n pattern?: string;\n icon?: PhoneFieldFullProps['icon'];\n iconType?: IconicTypes;\n validationStatus?: FormControlProps<PhoneValue>['validationStatus'];\n onChange?: (event: Event, value: PhoneValue) => void;\n}\n\nexport const PhoneFieldFullInput = ({\n id,\n name,\n value: externalValue,\n pattern = '## ## ## ## ##',\n placeholder = '',\n icon,\n iconType,\n disabled = false,\n required = false,\n validationStatus = 'default',\n onChange,\n ...inputProps\n}: PhoneFieldFullInputProps) => {\n const internalId = useId();\n const resolvedId = id ?? internalId;\n const resolvedName = name ?? resolvedId;\n\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const { inputRef, value, onKeyDown, onInputChange } = usePhoneField({\n externalValue,\n pattern,\n onChange,\n });\n\n return (\n <div className=\"relative\">\n <input\n {...(inputProps as any)}\n ref={inputRef}\n id={resolvedId}\n name={resolvedName}\n type=\"tel\"\n disabled={disabled}\n required={required}\n value={value}\n onChange={onInputChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'ps-[52px]': icon,\n 'pe-[52px]': internalStatus === 'error' || internalStatus === 'success',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={resolvedName}\n />\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && <Icon name={icon} width=\"24px\" />}\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n </span>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -100,7 +100,7 @@ var _ = (e) => {
|
|
|
100
100
|
disabled: f,
|
|
101
101
|
value: E,
|
|
102
102
|
onChange: (e) => A(e.nativeEvent, e.target.value),
|
|
103
|
-
className: "opacity-0 absolute inset-0 w-full h-full cursor-pointer",
|
|
103
|
+
className: "opacity-0 absolute inset-0 w-full h-full cursor-pointer outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2",
|
|
104
104
|
id: `${S}-prefix`,
|
|
105
105
|
"aria-label": `${C}-prefix`,
|
|
106
106
|
children: o.map((e) => /* @__PURE__ */ h("option", {
|
|
@@ -120,7 +120,7 @@ var _ = (e) => {
|
|
|
120
120
|
onChange: k,
|
|
121
121
|
onKeyDown: O,
|
|
122
122
|
placeholder: l,
|
|
123
|
-
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none", {
|
|
123
|
+
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", {
|
|
124
124
|
"border-middleGrey focus:border-black active:border-black": w === "default",
|
|
125
125
|
"pe-[52px]": w === "error" || w === "success",
|
|
126
126
|
"bg-white text-black": w !== "disabled",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneFieldSplitInput.js","names":[],"sources":["../../../lib/ui/forms/PhoneFieldSplitInput.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { Icon, type IconicTypes } from '@clubmed/trident-icons';\nimport {\n type ChangeEvent,\n type InputHTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport {\n calculateCursorPosition,\n DEFAULT_PHONE_PREFIXES,\n extractDigits,\n formatPhoneDigits,\n formatWithPattern,\n getLiteralPrefixInfo,\n type PhonePrefix,\n stripLiteralPrefix,\n} from '../helpers/phone';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport type { FormControlProps } from './FormControl';\nimport type { PhoneValue } from './PhoneField';\n\ntype PhoneFieldChangeHandler = (event: Event, value: PhoneValue) => void;\n\nexport interface PhoneFieldSplitProps {\n prefixes?: PhonePrefix[];\n defaultPrefix?: string;\n}\n\nconst usePhoneField = (args: {\n externalValue?: PhoneValue;\n pattern: string;\n defaultPrefix: string;\n onChange?: PhoneFieldChangeHandler;\n}) => {\n const { externalValue, pattern, defaultPrefix, onChange } = args;\n const numberInputRef = useRef<HTMLInputElement>(null);\n const cursorPositionRef = useRef<number | null>(null);\n const [prefix, setPrefix] = useState(defaultPrefix);\n const [number, setNumber] = useState('');\n\n const emitChange = useCallback(\n (event: Event, nextPrefix: string, nextNumber: string) => {\n if (nextPrefix === prefix && nextNumber === number) {\n return;\n }\n\n const full = `${nextPrefix} ${nextNumber}`.trim();\n\n onChange?.(event, {\n full,\n prefix: nextPrefix,\n number: nextNumber,\n raw: extractDigits(full),\n });\n },\n [number, onChange, prefix],\n );\n\n useEffect(() => {\n if (cursorPositionRef.current !== null && numberInputRef.current) {\n numberInputRef.current.setSelectionRange(\n cursorPositionRef.current,\n cursorPositionRef.current,\n );\n cursorPositionRef.current = null;\n }\n }, [number]);\n\n useEffect(() => {\n if (externalValue && typeof externalValue === 'object' && 'full' in externalValue) {\n setPrefix(externalValue.prefix || defaultPrefix);\n setNumber(externalValue.number || '');\n }\n }, [externalValue, defaultPrefix]);\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Backspace' && e.key !== 'Delete') {\n return;\n }\n\n const cursorPosition = e.currentTarget.selectionStart || 0;\n const selectionEnd = e.currentTarget.selectionEnd || 0;\n\n if (cursorPosition !== selectionEnd) {\n return;\n }\n\n const { literalPrefixDigits } = getLiteralPrefixInfo(pattern);\n\n const targetChar =\n e.key === 'Backspace' ? number[cursorPosition - 1] : number[cursorPosition];\n\n if (!targetChar || /\\d/.test(targetChar)) {\n return;\n }\n\n e.preventDefault();\n\n const allDigits = stripLiteralPrefix(extractDigits(number), literalPrefixDigits);\n const digitsBeforeCursor = stripLiteralPrefix(\n extractDigits(number.substring(0, cursorPosition)),\n literalPrefixDigits,\n ).length;\n\n let newDigits: string;\n let targetCursorDigits: number;\n\n if (e.key === 'Backspace') {\n if (digitsBeforeCursor === 0) {\n return;\n }\n\n newDigits =\n allDigits.slice(0, digitsBeforeCursor - 1) + allDigits.slice(digitsBeforeCursor);\n targetCursorDigits = digitsBeforeCursor - 1;\n } else {\n if (digitsBeforeCursor >= allDigits.length) {\n return;\n }\n\n newDigits =\n allDigits.slice(0, digitsBeforeCursor) + allDigits.slice(digitsBeforeCursor + 1);\n targetCursorDigits = digitsBeforeCursor;\n }\n\n const formatted = formatWithPattern(newDigits, pattern);\n cursorPositionRef.current = calculateCursorPosition(\n targetCursorDigits,\n formatted,\n literalPrefixDigits,\n );\n\n setNumber(formatted);\n\n emitChange(e.nativeEvent, prefix, formatted);\n },\n [emitChange, pattern, number, prefix],\n );\n\n const onInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const formattedValue = formatPhoneDigits(\n e.target.value,\n pattern,\n e.target.selectionStart || 0,\n );\n if (!formattedValue) return;\n\n cursorPositionRef.current = formattedValue.nextCursor;\n setNumber(formattedValue.formatted);\n\n emitChange(e.nativeEvent, prefix, formattedValue.formatted);\n },\n [emitChange, pattern, prefix],\n );\n\n const onPrefixChange = useCallback(\n (event: Event, newPrefix: string) => {\n setPrefix(newPrefix);\n\n emitChange(event, newPrefix, number);\n },\n [emitChange, number],\n );\n\n return { numberInputRef, prefix, number, onKeyDown, onInputChange, onPrefixChange };\n};\n\nexport interface PhoneFieldSplitInputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'pattern'> {\n value?: PhoneValue;\n pattern?: string;\n prefixes?: PhoneFieldSplitProps['prefixes'];\n defaultPrefix?: PhoneFieldSplitProps['defaultPrefix'];\n iconType?: IconicTypes;\n validationStatus?: FormControlProps<PhoneValue>['validationStatus'];\n onChange?: (event: Event, value: PhoneValue) => void;\n}\n\nexport const PhoneFieldSplitInput = ({\n id,\n name,\n value: externalValue,\n pattern = '## ## ## ## ##',\n prefixes = DEFAULT_PHONE_PREFIXES,\n defaultPrefix = prefixes[0]?.code || '+1',\n placeholder = '',\n iconType,\n disabled = false,\n required = false,\n validationStatus = 'default',\n onChange,\n ...rest\n}: PhoneFieldSplitInputProps) => {\n const internalId = useId();\n const resolvedId = id ?? internalId;\n const resolvedName = name ?? resolvedId;\n\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const { numberInputRef, prefix, number, onKeyDown, onInputChange, onPrefixChange } =\n usePhoneField({\n externalValue,\n pattern,\n defaultPrefix,\n onChange,\n });\n\n return (\n <div className=\"flex gap-8\">\n <div\n className={clsx('relative rounded-pill z-0 flex-shrink-0', {\n 'bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n })}\n >\n {/* Visible fake select showing the short label */}\n <div\n aria-hidden=\"true\"\n className={clsx(\n 'text-b3 rounded-pill w-full border px-20 py-12 font-semibold pointer-events-none flex items-center justify-between gap-8',\n {\n 'border-middleGrey': internalStatus === 'default',\n 'text-black bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey text-black': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n >\n <span>{(prefixes as PhonePrefix[]).find((p) => p.code === prefix)?.label ?? prefix}</span>\n <Icon name=\"ArrowDefaultDown\" type=\"svg\" width=\"24px\" color=\"black\" />\n </div>\n\n {/* Real select — invisible but interactive, uses fullLabel for dropdown options */}\n <select\n disabled={disabled}\n value={prefix}\n onChange={(e) => onPrefixChange(e.nativeEvent, e.target.value)}\n className=\"opacity-0 absolute inset-0 w-full h-full cursor-pointer\"\n id={`${resolvedId}-prefix`}\n aria-label={`${resolvedName}-prefix`}\n >\n {(prefixes as PhonePrefix[]).map((p) => (\n <option key={p.code} value={p.code}>\n {p.fullLabel ?? p.label ?? p.code}\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"relative flex-1\">\n <input\n {...(rest as Record<string, unknown>)}\n ref={numberInputRef}\n type=\"tel\"\n disabled={disabled}\n required={required}\n value={number}\n onChange={onInputChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'pe-[52px]': internalStatus === 'error' || internalStatus === 'success',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={`${resolvedName}-number`}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-end px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n <span className=\"flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n </span>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PhoneFieldSplitInput.js","names":[],"sources":["../../../lib/ui/forms/PhoneFieldSplitInput.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { Icon, type IconicTypes } from '@clubmed/trident-icons';\nimport {\n type ChangeEvent,\n type InputHTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport {\n calculateCursorPosition,\n DEFAULT_PHONE_PREFIXES,\n extractDigits,\n formatPhoneDigits,\n formatWithPattern,\n getLiteralPrefixInfo,\n type PhonePrefix,\n stripLiteralPrefix,\n} from '../helpers/phone';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport type { FormControlProps } from './FormControl';\nimport type { PhoneValue } from './PhoneField';\n\ntype PhoneFieldChangeHandler = (event: Event, value: PhoneValue) => void;\n\nexport interface PhoneFieldSplitProps {\n prefixes?: PhonePrefix[];\n defaultPrefix?: string;\n}\n\nconst usePhoneField = (args: {\n externalValue?: PhoneValue;\n pattern: string;\n defaultPrefix: string;\n onChange?: PhoneFieldChangeHandler;\n}) => {\n const { externalValue, pattern, defaultPrefix, onChange } = args;\n const numberInputRef = useRef<HTMLInputElement>(null);\n const cursorPositionRef = useRef<number | null>(null);\n const [prefix, setPrefix] = useState(defaultPrefix);\n const [number, setNumber] = useState('');\n\n const emitChange = useCallback(\n (event: Event, nextPrefix: string, nextNumber: string) => {\n if (nextPrefix === prefix && nextNumber === number) {\n return;\n }\n\n const full = `${nextPrefix} ${nextNumber}`.trim();\n\n onChange?.(event, {\n full,\n prefix: nextPrefix,\n number: nextNumber,\n raw: extractDigits(full),\n });\n },\n [number, onChange, prefix],\n );\n\n useEffect(() => {\n if (cursorPositionRef.current !== null && numberInputRef.current) {\n numberInputRef.current.setSelectionRange(\n cursorPositionRef.current,\n cursorPositionRef.current,\n );\n cursorPositionRef.current = null;\n }\n }, [number]);\n\n useEffect(() => {\n if (externalValue && typeof externalValue === 'object' && 'full' in externalValue) {\n setPrefix(externalValue.prefix || defaultPrefix);\n setNumber(externalValue.number || '');\n }\n }, [externalValue, defaultPrefix]);\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key !== 'Backspace' && e.key !== 'Delete') {\n return;\n }\n\n const cursorPosition = e.currentTarget.selectionStart || 0;\n const selectionEnd = e.currentTarget.selectionEnd || 0;\n\n if (cursorPosition !== selectionEnd) {\n return;\n }\n\n const { literalPrefixDigits } = getLiteralPrefixInfo(pattern);\n\n const targetChar =\n e.key === 'Backspace' ? number[cursorPosition - 1] : number[cursorPosition];\n\n if (!targetChar || /\\d/.test(targetChar)) {\n return;\n }\n\n e.preventDefault();\n\n const allDigits = stripLiteralPrefix(extractDigits(number), literalPrefixDigits);\n const digitsBeforeCursor = stripLiteralPrefix(\n extractDigits(number.substring(0, cursorPosition)),\n literalPrefixDigits,\n ).length;\n\n let newDigits: string;\n let targetCursorDigits: number;\n\n if (e.key === 'Backspace') {\n if (digitsBeforeCursor === 0) {\n return;\n }\n\n newDigits =\n allDigits.slice(0, digitsBeforeCursor - 1) + allDigits.slice(digitsBeforeCursor);\n targetCursorDigits = digitsBeforeCursor - 1;\n } else {\n if (digitsBeforeCursor >= allDigits.length) {\n return;\n }\n\n newDigits =\n allDigits.slice(0, digitsBeforeCursor) + allDigits.slice(digitsBeforeCursor + 1);\n targetCursorDigits = digitsBeforeCursor;\n }\n\n const formatted = formatWithPattern(newDigits, pattern);\n cursorPositionRef.current = calculateCursorPosition(\n targetCursorDigits,\n formatted,\n literalPrefixDigits,\n );\n\n setNumber(formatted);\n\n emitChange(e.nativeEvent, prefix, formatted);\n },\n [emitChange, pattern, number, prefix],\n );\n\n const onInputChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const formattedValue = formatPhoneDigits(\n e.target.value,\n pattern,\n e.target.selectionStart || 0,\n );\n if (!formattedValue) return;\n\n cursorPositionRef.current = formattedValue.nextCursor;\n setNumber(formattedValue.formatted);\n\n emitChange(e.nativeEvent, prefix, formattedValue.formatted);\n },\n [emitChange, pattern, prefix],\n );\n\n const onPrefixChange = useCallback(\n (event: Event, newPrefix: string) => {\n setPrefix(newPrefix);\n\n emitChange(event, newPrefix, number);\n },\n [emitChange, number],\n );\n\n return { numberInputRef, prefix, number, onKeyDown, onInputChange, onPrefixChange };\n};\n\nexport interface PhoneFieldSplitInputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'pattern'> {\n value?: PhoneValue;\n pattern?: string;\n prefixes?: PhoneFieldSplitProps['prefixes'];\n defaultPrefix?: PhoneFieldSplitProps['defaultPrefix'];\n iconType?: IconicTypes;\n validationStatus?: FormControlProps<PhoneValue>['validationStatus'];\n onChange?: (event: Event, value: PhoneValue) => void;\n}\n\nexport const PhoneFieldSplitInput = ({\n id,\n name,\n value: externalValue,\n pattern = '## ## ## ## ##',\n prefixes = DEFAULT_PHONE_PREFIXES,\n defaultPrefix = prefixes[0]?.code || '+1',\n placeholder = '',\n iconType,\n disabled = false,\n required = false,\n validationStatus = 'default',\n onChange,\n ...rest\n}: PhoneFieldSplitInputProps) => {\n const internalId = useId();\n const resolvedId = id ?? internalId;\n const resolvedName = name ?? resolvedId;\n\n const internalStatus = useInternalStatus({ isDisabled: disabled, validationStatus });\n const { numberInputRef, prefix, number, onKeyDown, onInputChange, onPrefixChange } =\n usePhoneField({\n externalValue,\n pattern,\n defaultPrefix,\n onChange,\n });\n\n return (\n <div className=\"flex gap-8\">\n <div\n className={clsx('relative rounded-pill z-0 flex-shrink-0', {\n 'bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n })}\n >\n {/* Visible fake select showing the short label */}\n <div\n aria-hidden=\"true\"\n className={clsx(\n 'text-b3 rounded-pill w-full border px-20 py-12 font-semibold pointer-events-none flex items-center justify-between gap-8',\n {\n 'border-middleGrey': internalStatus === 'default',\n 'text-black bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey text-black': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n >\n <span>{(prefixes as PhonePrefix[]).find((p) => p.code === prefix)?.label ?? prefix}</span>\n <Icon name=\"ArrowDefaultDown\" type=\"svg\" width=\"24px\" color=\"black\" />\n </div>\n\n {/* Real select — invisible but interactive, uses fullLabel for dropdown options */}\n <select\n disabled={disabled}\n value={prefix}\n onChange={(e) => onPrefixChange(e.nativeEvent, e.target.value)}\n className=\"opacity-0 absolute inset-0 w-full h-full cursor-pointer outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n id={`${resolvedId}-prefix`}\n aria-label={`${resolvedName}-prefix`}\n >\n {(prefixes as PhonePrefix[]).map((p) => (\n <option key={p.code} value={p.code}>\n {p.fullLabel ?? p.label ?? p.code}\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"relative flex-1\">\n <input\n {...(rest as Record<string, unknown>)}\n ref={numberInputRef}\n type=\"tel\"\n disabled={disabled}\n required={required}\n value={number}\n onChange={onInputChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'pe-[52px]': internalStatus === 'error' || internalStatus === 'success',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={`${resolvedName}-number`}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-end px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n <span className=\"flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n </span>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
package/ui/forms/Select.js
CHANGED
|
@@ -41,7 +41,7 @@ var c = (c) => {
|
|
|
41
41
|
onChange: (e) => {
|
|
42
42
|
D(e.target.value, e.nativeEvent);
|
|
43
43
|
},
|
|
44
|
-
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none appearance-none bg-transparent", {
|
|
44
|
+
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 appearance-none bg-transparent", {
|
|
45
45
|
"border-middleGrey focus:border-black active:border-black pe-[52px]": O === "default",
|
|
46
46
|
"pe-[84px]": O === "error" || O === "success",
|
|
47
47
|
"text-black": O !== "disabled",
|
package/ui/forms/Select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","names":[],"sources":["../../../lib/ui/forms/Select.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useValue } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControl, type FormControlProps } from './FormControl';\nimport { Icon, type IconicTypes } from '@clubmed/trident-icons';\nimport { type SelectHTMLAttributes, useId } from 'react';\n\nexport interface SelectProps<Value>\n extends FormControlProps<Value, SelectHTMLAttributes<HTMLSelectElement>> {\n description?: string;\n iconType?: IconicTypes;\n errorMessage?: string;\n dataTestId?: string;\n}\n\nexport const Select = <Value = string,>(props: SelectProps<Value>) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n description,\n validationStatus = 'default',\n iconType,\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n className,\n dataTestId = id,\n onChange,\n children,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange });\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n return (\n <FormControl\n id={id}\n className={className}\n label={label}\n description={description}\n dataName=\"TextField\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={validationStatus}\n errorMessage={errorMessage}\n >\n <div\n className={clsx('relative rounded-pill z-0', {\n 'bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n })}\n >\n <select\n {...rest}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as any}\n onChange={(e) => {\n setValue(e.target.value as Value, e.nativeEvent);\n }}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none appearance-none bg-transparent',\n {\n 'border-middleGrey focus:border-black active:border-black pe-[52px]':\n internalStatus === 'default',\n 'pe-[84px]': internalStatus === 'error' || internalStatus === 'success',\n 'text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={name}\n >\n {children}\n </select>\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12 -z-1',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n\n <button className=\"pointer-events-auto inline-flex\">\n <Icon name=\"ArrowDefaultDown\" type=\"svg\" width=\"24px\" color=\"black\" />\n </button>\n </span>\n </div>\n </div>\n </FormControl>\n );\n};\n"],"mappings":";;;;;;;;AAeA,IAAa,KAA2B,MAA8B;CACpE,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,gBACA,sBAAmB,WACnB,aACA,iBACA,cAAW,IACX,cAAW,IACX,qBACA,cACA,gBAAa,GACb,aACA,aACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU,CAAC,EACjE,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC;AAEF,QACE,kBAAC,GAAD;EACM;EACO;EACJ;EACM;EACb,UAAS;EACG;EACF;EACA;EACQ;EACA;EACJ;YAEd,kBAAC,OAAD;GACE,WAAW,EAAK,6BAA6B;IAC3C,YAAY,MAAmB;IAC/B,8BAA8B,MAAmB;IAClD,CAAC;aAJJ,CAME,kBAAC,UAAD;IACE,GAAI;IACA;IACE;IACI;IACA;IACH;IACP,WAAW,MAAM;AACf,OAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;;IAElD,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"Select.js","names":[],"sources":["../../../lib/ui/forms/Select.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useValue } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControl, type FormControlProps } from './FormControl';\nimport { Icon, type IconicTypes } from '@clubmed/trident-icons';\nimport { type SelectHTMLAttributes, useId } from 'react';\n\nexport interface SelectProps<Value>\n extends FormControlProps<Value, SelectHTMLAttributes<HTMLSelectElement>> {\n description?: string;\n iconType?: IconicTypes;\n errorMessage?: string;\n dataTestId?: string;\n}\n\nexport const Select = <Value = string,>(props: SelectProps<Value>) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n description,\n validationStatus = 'default',\n iconType,\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n className,\n dataTestId = id,\n onChange,\n children,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange });\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n return (\n <FormControl\n id={id}\n className={className}\n label={label}\n description={description}\n dataName=\"TextField\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={validationStatus}\n errorMessage={errorMessage}\n >\n <div\n className={clsx('relative rounded-pill z-0', {\n 'bg-white': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n })}\n >\n <select\n {...rest}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as any}\n onChange={(e) => {\n setValue(e.target.value as Value, e.nativeEvent);\n }}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 appearance-none bg-transparent',\n {\n 'border-middleGrey focus:border-black active:border-black pe-[52px]':\n internalStatus === 'default',\n 'pe-[84px]': internalStatus === 'error' || internalStatus === 'success',\n 'text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={name}\n >\n {children}\n </select>\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12 -z-1',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' && (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n )}\n\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n\n <button className=\"pointer-events-auto inline-flex\">\n <Icon name=\"ArrowDefaultDown\" type=\"svg\" width=\"24px\" color=\"black\" />\n </button>\n </span>\n </div>\n </div>\n </FormControl>\n );\n};\n"],"mappings":";;;;;;;;AAeA,IAAa,KAA2B,MAA8B;CACpE,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,gBACA,sBAAmB,WACnB,aACA,iBACA,cAAW,IACX,cAAW,IACX,qBACA,cACA,gBAAa,GACb,aACA,aACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU,CAAC,EACjE,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC;AAEF,QACE,kBAAC,GAAD;EACM;EACO;EACJ;EACM;EACb,UAAS;EACG;EACF;EACA;EACQ;EACA;EACJ;YAEd,kBAAC,OAAD;GACE,WAAW,EAAK,6BAA6B;IAC3C,YAAY,MAAmB;IAC/B,8BAA8B,MAAmB;IAClD,CAAC;aAJJ,CAME,kBAAC,UAAD;IACE,GAAI;IACA;IACE;IACI;IACA;IACH;IACP,WAAW,MAAM;AACf,OAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;;IAElD,WAAW,EACT,oMACA;KACE,sEACE,MAAmB;KACrB,aAAa,MAAmB,WAAW,MAAmB;KAC9D,cAAc,MAAmB;KACjC,8BAA8B,MAAmB;KACjD,cAAc,MAAmB;KACjC,gBAAgB,MAAmB;KACpC,CACF;IACD,cAAY;IAEX;IACM,CAAA,EAET,kBAAC,OAAD;IACE,WAAW,EACT,2FACA;KACE,aAAa,MAAmB;KAChC,YAAY,MAAmB;KAC/B,cAAc,MAAmB;KAClC,CACF;cAED,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACG,MAAmB,WAClB,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAO,MAAM;OAAY,CAAA;MAG1D,MAAmB,aAClB,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAO,MAAM;OAAY,CAAA;MAG3D,kBAAC,UAAD;OAAQ,WAAU;iBAChB,kBAAC,GAAD;QAAM,MAAK;QAAmB,MAAK;QAAM,OAAM;QAAO,OAAM;QAAU,CAAA;OAC/D,CAAA;MACJ;;IACH,CAAA,CACF;;EACM,CAAA"}
|
package/ui/forms/TextField.js
CHANGED
|
@@ -41,7 +41,7 @@ var c = (c) => {
|
|
|
41
41
|
"--nbIconsStart": Number(!!g && E),
|
|
42
42
|
"--nbIconsEnd": Number(!!g && !E) + Number(w && !N || N && M !== "error") + Number(M === "error" || M === "success")
|
|
43
43
|
},
|
|
44
|
-
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]", {
|
|
44
|
+
className: e("text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]", {
|
|
45
45
|
"border-middleGrey focus:border-black active:border-black": M === "default",
|
|
46
46
|
"bg-white text-black": M !== "disabled",
|
|
47
47
|
"bg-pearl border-middleGrey": M === "disabled",
|
|
@@ -62,7 +62,7 @@ var c = (c) => {
|
|
|
62
62
|
className: "ms-auto flex gap-x-8",
|
|
63
63
|
children: [
|
|
64
64
|
M === "error" && (N ? /* @__PURE__ */ o("button", {
|
|
65
|
-
className: "pointer-events-auto cursor-pointer flex",
|
|
65
|
+
className: "pointer-events-auto cursor-pointer flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2",
|
|
66
66
|
onClick: (e) => j("", e.nativeEvent),
|
|
67
67
|
"aria-label": T,
|
|
68
68
|
type: "reset",
|
|
@@ -82,7 +82,7 @@ var c = (c) => {
|
|
|
82
82
|
type: _
|
|
83
83
|
}),
|
|
84
84
|
(w || N && M !== "error") && (N ? /* @__PURE__ */ o("button", {
|
|
85
|
-
className: "pointer-events-auto cursor-pointer flex",
|
|
85
|
+
className: "pointer-events-auto cursor-pointer flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2",
|
|
86
86
|
onClick: (e) => j("", e.nativeEvent),
|
|
87
87
|
"aria-label": T,
|
|
88
88
|
type: "reset",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextField.js","names":[],"sources":["../../../lib/ui/forms/TextField.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useValue, type UseValueProps } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControl, type FormControlProps } from './FormControl';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport { useId } from 'react';\n\nexport interface TextFieldProps<Value> extends FormControlProps<Value> {\n description?: string;\n icon?: IconicNames;\n iconType?: IconicTypes;\n errorMessage?: string;\n dataTestId?: string;\n formatter?: UseValueProps<Value>['formatter'];\n hasDropdown?: boolean;\n clear?: string;\n iconFirst?: boolean;\n}\n\nexport const TextField = <Value = string,>(props: TextFieldProps<Value>) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n description,\n validationStatus = 'default',\n icon,\n iconType,\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n className,\n dataTestId = 'TextField',\n hasDropdown = false,\n clear = '',\n iconFirst = true,\n onChange,\n formatter,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange, formatter });\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n const shouldDisplayClearButton =\n !disabled && value !== '' && value !== null && value !== undefined && !!clear;\n\n return (\n <FormControl\n id={id}\n label={label}\n className={className}\n description={description}\n dataName=\"TextField\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={validationStatus}\n errorMessage={errorMessage}\n >\n <div className=\"relative\">\n <input\n {...rest}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as any}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n style={\n {\n '--nbIconsStart': Number(!!icon && iconFirst),\n '--nbIconsEnd':\n Number(!!icon && !iconFirst) +\n Number(\n (hasDropdown && !shouldDisplayClearButton) ||\n (shouldDisplayClearButton && internalStatus !== 'error'),\n ) +\n Number(internalStatus === 'error' || internalStatus === 'success'),\n } as React.CSSProperties\n }\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={name}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && iconFirst && <Icon name={icon} width=\"24px\" />}\n\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto cursor-pointer flex\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n </button>\n ) : (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n ))}\n\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n {(hasDropdown || (shouldDisplayClearButton && internalStatus !== 'error')) &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto cursor-pointer flex\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" className=\"text-black\" width=\"24px\" />\n </button>\n ) : (\n <Icon name=\"ArrowDefaultDown\" className=\"text-black\" width=\"24px\" />\n ))}\n {!iconFirst && icon && <Icon name={icon} width=\"24px\" />}\n </span>\n </div>\n </div>\n </FormControl>\n );\n};\n"],"mappings":";;;;;;;;AAmBA,IAAa,KAA8B,MAAiC;CAC1E,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,gBACA,sBAAmB,WACnB,SACA,aACA,iBACA,cAAW,IACX,cAAW,IACX,qBACA,cACA,gBAAa,aACb,iBAAc,IACd,WAAQ,IACR,eAAY,IACZ,aACA,cACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU;EAAW,CAAC,EAC5E,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC,EAEI,IACJ,CAAC,KAAY,MAAU,MAAM,KAAU,QAA+B,CAAC,CAAC;AAE1E,QACE,kBAAC,GAAD;EACM;EACG;EACI;EACE;EACb,UAAS;EACG;EACF;EACA;EACQ;EACA;EACJ;YAEd,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,SAAD;IACE,GAAI;IACA;IACE;IACI;IACA;IACH;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;IACjE,OACE;KACE,kBAAkB,OAAO,CAAC,CAAC,KAAQ,EAAU;KAC7C,gBACE,OAAO,CAAC,CAAC,KAAQ,CAAC,EAAU,GAC5B,OACG,KAAe,CAAC,KACd,KAA4B,MAAmB,QACnD,GACD,OAAO,MAAmB,WAAW,MAAmB,UAAU;KACrE;IAEH,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"TextField.js","names":[],"sources":["../../../lib/ui/forms/TextField.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useValue, type UseValueProps } from '../hooks/useValue';\nimport { useInternalStatus } from '../hooks/useInternalStatus';\nimport { FormControl, type FormControlProps } from './FormControl';\nimport { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';\nimport { useId } from 'react';\n\nexport interface TextFieldProps<Value> extends FormControlProps<Value> {\n description?: string;\n icon?: IconicNames;\n iconType?: IconicTypes;\n errorMessage?: string;\n dataTestId?: string;\n formatter?: UseValueProps<Value>['formatter'];\n hasDropdown?: boolean;\n clear?: string;\n iconFirst?: boolean;\n}\n\nexport const TextField = <Value = string,>(props: TextFieldProps<Value>) => {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n description,\n validationStatus = 'default',\n icon,\n iconType,\n errorMessage,\n disabled = false,\n required = false,\n hideRequiredStar,\n className,\n dataTestId = 'TextField',\n hasDropdown = false,\n clear = '',\n iconFirst = true,\n onChange,\n formatter,\n ...rest\n } = props;\n\n const { value, setValue } = useValue<Value>({ initialValue, onChange, formatter });\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n const shouldDisplayClearButton =\n !disabled && value !== '' && value !== null && value !== undefined && !!clear;\n\n return (\n <FormControl\n id={id}\n label={label}\n className={className}\n description={description}\n dataName=\"TextField\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={validationStatus}\n errorMessage={errorMessage}\n >\n <div className=\"relative\">\n <input\n {...rest}\n id={id}\n name={name}\n disabled={disabled}\n required={required}\n value={value as any}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n style={\n {\n '--nbIconsStart': Number(!!icon && iconFirst),\n '--nbIconsEnd':\n Number(!!icon && !iconFirst) +\n Number(\n (hasDropdown && !shouldDisplayClearButton) ||\n (shouldDisplayClearButton && internalStatus !== 'error'),\n ) +\n Number(internalStatus === 'error' || internalStatus === 'success'),\n } as React.CSSProperties\n }\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden px-20 py-12 font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 ps-[calc(20px+var(--nbIconsStart)*32px)] pe-[calc(20px+var(--nbIconsEnd)*32px)]',\n {\n 'border-middleGrey focus:border-black active:border-black':\n internalStatus === 'default',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'border-red': internalStatus === 'error',\n 'border-green': internalStatus === 'success',\n },\n )}\n aria-label={name}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n {\n 'text-grey': internalStatus === 'disabled',\n 'text-red': internalStatus === 'error',\n 'text-green': internalStatus === 'success',\n },\n )}\n >\n {icon && iconFirst && <Icon name={icon} width=\"24px\" />}\n\n <span className=\"ms-auto flex gap-x-8\">\n {internalStatus === 'error' &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto cursor-pointer flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n </button>\n ) : (\n <Icon name=\"CrossDefault\" width=\"24px\" type={iconType} />\n ))}\n\n {internalStatus === 'success' && (\n <Icon name=\"CheckDefault\" width=\"24px\" type={iconType} />\n )}\n {(hasDropdown || (shouldDisplayClearButton && internalStatus !== 'error')) &&\n (shouldDisplayClearButton ? (\n <button\n className=\"pointer-events-auto cursor-pointer flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n onClick={(e) => setValue('' as Value, e.nativeEvent)}\n aria-label={clear}\n type=\"reset\"\n >\n <Icon name=\"CrossDefault\" className=\"text-black\" width=\"24px\" />\n </button>\n ) : (\n <Icon name=\"ArrowDefaultDown\" className=\"text-black\" width=\"24px\" />\n ))}\n {!iconFirst && icon && <Icon name={icon} width=\"24px\" />}\n </span>\n </div>\n </div>\n </FormControl>\n );\n};\n"],"mappings":";;;;;;;;AAmBA,IAAa,KAA8B,MAAiC;CAC1E,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,gBACA,sBAAmB,WACnB,SACA,aACA,iBACA,cAAW,IACX,cAAW,IACX,qBACA,cACA,gBAAa,aACb,iBAAc,IACd,WAAQ,IACR,eAAY,IACZ,aACA,cACA,GAAG,MACD,GAEE,EAAE,UAAO,gBAAa,EAAgB;EAAE;EAAc;EAAU;EAAW,CAAC,EAC5E,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC,EAEI,IACJ,CAAC,KAAY,MAAU,MAAM,KAAU,QAA+B,CAAC,CAAC;AAE1E,QACE,kBAAC,GAAD;EACM;EACG;EACI;EACE;EACb,UAAS;EACG;EACF;EACA;EACQ;EACA;EACJ;YAEd,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,SAAD;IACE,GAAI;IACA;IACE;IACI;IACA;IACH;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;IACjE,OACE;KACE,kBAAkB,OAAO,CAAC,CAAC,KAAQ,EAAU;KAC7C,gBACE,OAAO,CAAC,CAAC,KAAQ,CAAC,EAAU,GAC5B,OACG,KAAe,CAAC,KACd,KAA4B,MAAmB,QACnD,GACD,OAAO,MAAmB,WAAW,MAAmB,UAAU;KACrE;IAEH,WAAW,EACT,qPACA;KACE,4DACE,MAAmB;KACrB,uBAAuB,MAAmB;KAC1C,8BAA8B,MAAmB;KACjD,cAAc,MAAmB;KACjC,gBAAgB,MAAmB;KACpC,CACF;IACD,cAAY;IACZ,CAAA,EAEF,kBAAC,OAAD;IACE,WAAW,EACT,sFACA;KACE,aAAa,MAAmB;KAChC,YAAY,MAAmB;KAC/B,cAAc,MAAmB;KAClC,CACF;cARH,CAUG,KAAQ,KAAa,kBAAC,GAAD;KAAM,MAAM;KAAM,OAAM;KAAS,CAAA,EAEvD,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACG,MAAmB,YACjB,IACC,kBAAC,UAAD;OACE,WAAU;OACV,UAAU,MAAM,EAAS,IAAa,EAAE,YAAY;OACpD,cAAY;OACZ,MAAK;iBAEL,kBAAC,GAAD;QAAM,MAAK;QAAe,OAAM;QAAO,MAAM;QAAY,CAAA;OAClD,CAAA,GAET,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAO,MAAM;OAAY,CAAA;MAG5D,MAAmB,aAClB,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAO,MAAM;OAAY,CAAA;OAEzD,KAAgB,KAA4B,MAAmB,aAC9D,IACC,kBAAC,UAAD;OACE,WAAU;OACV,UAAU,MAAM,EAAS,IAAa,EAAE,YAAY;OACpD,cAAY;OACZ,MAAK;iBAEL,kBAAC,GAAD;QAAM,MAAK;QAAe,WAAU;QAAa,OAAM;QAAS,CAAA;OACzD,CAAA,GAET,kBAAC,GAAD;OAAM,MAAK;OAAmB,WAAU;OAAa,OAAM;OAAS,CAAA;MAEvE,CAAC,KAAa,KAAQ,kBAAC,GAAD;OAAM,MAAM;OAAM,OAAM;OAAS,CAAA;MACnD;OACH;MACF;;EACM,CAAA"}
|
|
@@ -14,7 +14,7 @@ function l(l) {
|
|
|
14
14
|
"!border-red !text-red": E === "error",
|
|
15
15
|
"bg-pearl": D
|
|
16
16
|
}), A = /* @__PURE__ */ c("span", {
|
|
17
|
-
className: e("rounded-8 inline-flex shrink-0 items-center justify-center self-start border transition-colors hover:!border-current/60 focus-visible
|
|
17
|
+
className: e("rounded-8 inline-flex shrink-0 items-center justify-center self-start border transition-colors hover:!border-current/60 has-[:focus-visible]:ring-4 has-[:focus-visible]:ring-black has-[:focus-visible]:ring-offset-2", t(m), n(m), h, k, p),
|
|
18
18
|
"data-name": "Checkbox",
|
|
19
19
|
children: [/* @__PURE__ */ s("input", {
|
|
20
20
|
...T,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","names":[],"sources":["../../../../lib/ui/forms/checkboxes/Checkbox.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useId, type ComponentPropsWithoutRef, type Ref } from 'react';\nimport { Icon } from '@clubmed/trident-icons';\nimport type { Colors } from '../../types/Colors';\nimport { getBorderColor, getTextColor } from '../../helpers/colors/colors';\nimport { FormControlError } from '@/ui/forms/FormControlError';\nimport { useInternalStatus, type ValidationStatus } from '@/ui/hooks/useInternalStatus';\n\nexport interface CheckboxProps\n extends Omit<ComponentPropsWithoutRef<'input'>, 'size' | 'onChange' | 'value'> {\n color?: Colors;\n size?: string;\n value?: string | number | boolean;\n validationStatus?: ValidationStatus;\n errorMessage?: string;\n ['data-testid']?: string;\n ref?: Ref<HTMLInputElement>;\n onChange?: (event: Event, value: boolean) => void;\n}\n\nexport function Checkbox(props: CheckboxProps) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n className,\n color = 'black',\n size = 'size-24',\n disabled = false,\n tabIndex = 0,\n validationStatus = 'default',\n errorMessage,\n children,\n ref,\n onChange,\n value,\n 'data-testid': dataTestId,\n ...rest\n } = props;\n\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n const isDisabled = internalStatus === 'disabled';\n\n const shouldDisplayErrorMessage = internalStatus === 'error' && errorMessage;\n\n // Apply validation styling to checkbox via className\n const checkboxClassName = clsx({\n '!border-red !text-red': internalStatus === 'error',\n 'bg-pearl': isDisabled,\n });\n\n const checkbox = (\n <span\n className={clsx(\n 'rounded-8 inline-flex shrink-0 items-center justify-center self-start border transition-colors hover:!border-current/60 focus-visible
|
|
1
|
+
{"version":3,"file":"Checkbox.js","names":[],"sources":["../../../../lib/ui/forms/checkboxes/Checkbox.tsx"],"sourcesContent":["import clsx from 'clsx';\nimport { useId, type ComponentPropsWithoutRef, type Ref } from 'react';\nimport { Icon } from '@clubmed/trident-icons';\nimport type { Colors } from '../../types/Colors';\nimport { getBorderColor, getTextColor } from '../../helpers/colors/colors';\nimport { FormControlError } from '@/ui/forms/FormControlError';\nimport { useInternalStatus, type ValidationStatus } from '@/ui/hooks/useInternalStatus';\n\nexport interface CheckboxProps\n extends Omit<ComponentPropsWithoutRef<'input'>, 'size' | 'onChange' | 'value'> {\n color?: Colors;\n size?: string;\n value?: string | number | boolean;\n validationStatus?: ValidationStatus;\n errorMessage?: string;\n ['data-testid']?: string;\n ref?: Ref<HTMLInputElement>;\n onChange?: (event: Event, value: boolean) => void;\n}\n\nexport function Checkbox(props: CheckboxProps) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n className,\n color = 'black',\n size = 'size-24',\n disabled = false,\n tabIndex = 0,\n validationStatus = 'default',\n errorMessage,\n children,\n ref,\n onChange,\n value,\n 'data-testid': dataTestId,\n ...rest\n } = props;\n\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n const isDisabled = internalStatus === 'disabled';\n\n const shouldDisplayErrorMessage = internalStatus === 'error' && errorMessage;\n\n // Apply validation styling to checkbox via className\n const checkboxClassName = clsx({\n '!border-red !text-red': internalStatus === 'error',\n 'bg-pearl': isDisabled,\n });\n\n const checkbox = (\n <span\n className={clsx(\n 'rounded-8 inline-flex shrink-0 items-center justify-center self-start border transition-colors hover:!border-current/60 has-[:focus-visible]:ring-4 has-[:focus-visible]:ring-black has-[:focus-visible]:ring-offset-2',\n getBorderColor(color),\n getTextColor(color),\n size,\n checkboxClassName,\n className,\n )}\n data-name=\"Checkbox\"\n >\n <input\n {...rest}\n disabled={disabled}\n id={id}\n name={name}\n className=\"peer sr-only\"\n ref={ref}\n tabIndex={tabIndex}\n type=\"checkbox\"\n value={typeof value === 'boolean' ? String(value) : value}\n onChange={(e) => {\n onChange?.(e.nativeEvent, e.target.checked);\n }}\n />\n <Icon\n className=\"scale-1/2 transition-[transform,opacity] peer-checked:scale-auto opacity-0 peer-checked:opacity-100\"\n name=\"CheckDefault\"\n width=\"100%\"\n />\n </span>\n );\n\n if (!children && !errorMessage) {\n return checkbox;\n }\n\n return (\n <div\n className={clsx('flex flex-col space-y-2', className)}\n data-testid={dataTestId || `checkbox-container-${id}`}\n >\n <label\n className={clsx('relative flex items-center gap-8', {\n 'text-grey': disabled,\n })}\n >\n {checkbox}\n {children}\n </label>\n {shouldDisplayErrorMessage && <FormControlError>{errorMessage}</FormControlError>}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,EAAS,GAAsB;CAC7C,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,cACA,WAAQ,SACR,UAAO,WACP,cAAW,IACX,cAAW,GACX,sBAAmB,WACnB,iBACA,aACA,QACA,aACA,UACA,eAAe,GACf,GAAG,MACD,GAEE,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC,EACI,IAAa,MAAmB,YAEhC,IAA4B,MAAmB,WAAW,GAG1D,IAAoB,EAAK;EAC7B,yBAAyB,MAAmB;EAC5C,YAAY;EACb,CAAC,EAEI,IACJ,kBAAC,QAAD;EACE,WAAW,EACT,0NACA,EAAe,EAAM,EACrB,EAAa,EAAM,EACnB,GACA,GACA,EACD;EACD,aAAU;YATZ,CAWE,kBAAC,SAAD;GACE,GAAI;GACM;GACN;GACE;GACN,WAAU;GACL;GACK;GACV,MAAK;GACL,OAAO,OAAO,KAAU,YAAY,OAAO,EAAM,GAAG;GACpD,WAAW,MAAM;AACf,QAAW,EAAE,aAAa,EAAE,OAAO,QAAQ;;GAE7C,CAAA,EACF,kBAAC,GAAD;GACE,WAAU;GACV,MAAK;GACL,OAAM;GACN,CAAA,CACG;;AAOT,QAJI,CAAC,KAAY,CAAC,IACT,IAIP,kBAAC,OAAD;EACE,WAAW,EAAK,2BAA2B,EAAU;EACrD,eAAa,KAAc,sBAAsB;YAFnD,CAIE,kBAAC,SAAD;GACE,WAAW,EAAK,oCAAoC,EAClD,aAAa,GACd,CAAC;aAHJ,CAKG,GACA,EACK;MACP,KAA6B,kBAAC,GAAD,EAAA,UAAmB,GAAgC,CAAA,CAC7E"}
|
|
@@ -41,7 +41,7 @@ function d(d) {
|
|
|
41
41
|
disabled: _,
|
|
42
42
|
required: v,
|
|
43
43
|
onChange: (e) => A(e.target.value, e.nativeEvent),
|
|
44
|
-
className: e("text-b3 rounded-pill w-full border overflow-hidden ps-20 py-[11px] font-normal outline-none", {
|
|
44
|
+
className: e("text-b3 rounded-pill w-full border overflow-hidden ps-20 py-[11px] font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2", {
|
|
45
45
|
"border-middleGrey focus:border-black active:border-black pe-[52px]": (C || b === "default") && O !== "disabled",
|
|
46
46
|
"bg-white text-black": O !== "disabled",
|
|
47
47
|
"bg-pearl border-middleGrey": O === "disabled",
|
|
@@ -67,7 +67,7 @@ function d(d) {
|
|
|
67
67
|
}),
|
|
68
68
|
!_ && /* @__PURE__ */ l("button", {
|
|
69
69
|
type: "button",
|
|
70
|
-
className: "pointer-events-auto size-24 inline-flex",
|
|
70
|
+
className: "pointer-events-auto size-24 inline-flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2",
|
|
71
71
|
onClick: N,
|
|
72
72
|
children: /* @__PURE__ */ l(c, {
|
|
73
73
|
name: j === "password" ? "Invisible" : "Visible",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Password.js","names":[],"sources":["../../../../lib/ui/forms/password/Password.tsx"],"sourcesContent":["import { useInternalStatus } from '../../hooks/useInternalStatus';\nimport clsx from 'clsx';\n\nimport { type HTMLInputTypeAttribute, useEffect, useId, useState } from 'react';\n\nimport { useValue } from '../../hooks/useValue';\nimport { FormControl, type FormControlProps } from '../FormControl';\nimport { Icon } from '@clubmed/trident-icons';\nimport { ValidationMessage } from './ValidationMessage';\n\nexport interface PasswordProps<Value> extends FormControlProps<Value> {\n validationMessages?: ValidationMessage[];\n withoutFieldValidation?: boolean;\n}\n\nexport function Password<Value = string>(props: PasswordProps<Value>) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n disabled = false,\n required = false,\n hideRequiredStar,\n validationStatus = 'default',\n errorMessage,\n validationMessages = [],\n withoutFieldValidation = false,\n className,\n onChange,\n dataTestId = 'Password',\n ...rest\n } = props;\n\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n const { value, setValue } = useValue<Value>({\n initialValue,\n onChange,\n });\n const [type, setType] = useState<HTMLInputTypeAttribute>('password');\n\n useEffect(() => {\n if (disabled) {\n setType('password');\n } else {\n setType(type);\n }\n }, [type, disabled]);\n\n const toggleType = () => setType(type === 'password' ? 'text' : 'password');\n\n return (\n <FormControl\n className={className}\n id={id}\n label={label}\n dataName=\"Password\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={withoutFieldValidation ? 'default' : validationStatus}\n errorMessage={errorMessage}\n >\n <div className=\"relative\">\n <input\n {...rest}\n id={id}\n name={name}\n type={type}\n value={value as any}\n disabled={disabled}\n required={required}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden ps-20 py-[11px] font-normal outline-none',\n {\n 'border-middleGrey focus:border-black active:border-black pe-[52px]':\n (withoutFieldValidation || validationStatus === 'default') &&\n internalStatus !== 'disabled',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'pe-[84px]':\n !withoutFieldValidation &&\n (validationStatus === 'error' || validationStatus === 'success'),\n 'border-red': !withoutFieldValidation && validationStatus === 'error',\n 'border-green': !withoutFieldValidation && validationStatus === 'success',\n },\n )}\n aria-label={name}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n )}\n >\n <span className=\"ms-auto flex gap-x-8\">\n {!withoutFieldValidation && validationStatus === 'error' && (\n <Icon name=\"CrossDefault\" color=\"red\" width=\"24px\" />\n )}\n\n {!withoutFieldValidation && validationStatus === 'success' && (\n <Icon name=\"CheckDefault\" color=\"green\" width=\"24px\" />\n )}\n\n {!disabled && (\n <button\n type=\"button\"\n className=\"pointer-events-auto size-24 inline-flex\"\n onClick={toggleType}\n >\n <Icon\n name={type === 'password' ? 'Invisible' : 'Visible'}\n width=\"24px\"\n type=\"svg\"\n />\n </button>\n )}\n </span>\n </div>\n </div>\n\n {validationMessages.length > 0 && (\n <div className=\"flex flex-col gap-[10px] mt-8\">\n {validationMessages.map(({ label, status }, index) => (\n <ValidationMessage label={label} status={status} key={index} />\n ))}\n </div>\n )}\n </FormControl>\n );\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,EAAyB,GAA6B;CACpE,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,cAAW,IACX,cAAW,IACX,qBACA,sBAAmB,WACnB,iBACA,wBAAqB,EAAE,EACvB,4BAAyB,IACzB,cACA,aACA,gBAAa,YACb,GAAG,MACD,GAEE,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC,EAEI,EAAE,UAAO,gBAAa,EAAgB;EAC1C;EACA;EACD,CAAC,EACI,CAAC,GAAM,KAAW,EAAiC,WAAW;AAEpE,SAAgB;AACd,EACE,EADE,IACM,aAEA,EAAK;IAEd,CAAC,GAAM,EAAS,CAAC;CAEpB,IAAM,UAAmB,EAAQ,MAAS,aAAa,SAAS,WAAW;AAE3E,QACE,kBAAC,GAAD;EACa;EACP;EACG;EACP,UAAS;EACG;EACF;EACA;EACQ;EAClB,kBAAkB,IAAyB,YAAY;EACzC;YAVhB,CAYE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,SAAD;IACE,GAAI;IACA;IACE;IACA;IACC;IACG;IACA;IACV,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;IACjE,WAAW,EACT
|
|
1
|
+
{"version":3,"file":"Password.js","names":[],"sources":["../../../../lib/ui/forms/password/Password.tsx"],"sourcesContent":["import { useInternalStatus } from '../../hooks/useInternalStatus';\nimport clsx from 'clsx';\n\nimport { type HTMLInputTypeAttribute, useEffect, useId, useState } from 'react';\n\nimport { useValue } from '../../hooks/useValue';\nimport { FormControl, type FormControlProps } from '../FormControl';\nimport { Icon } from '@clubmed/trident-icons';\nimport { ValidationMessage } from './ValidationMessage';\n\nexport interface PasswordProps<Value> extends FormControlProps<Value> {\n validationMessages?: ValidationMessage[];\n withoutFieldValidation?: boolean;\n}\n\nexport function Password<Value = string>(props: PasswordProps<Value>) {\n const internalId = useId();\n\n const {\n id = internalId,\n name = id,\n label,\n value: initialValue,\n disabled = false,\n required = false,\n hideRequiredStar,\n validationStatus = 'default',\n errorMessage,\n validationMessages = [],\n withoutFieldValidation = false,\n className,\n onChange,\n dataTestId = 'Password',\n ...rest\n } = props;\n\n const internalStatus = useInternalStatus({\n isDisabled: disabled,\n validationStatus,\n });\n\n const { value, setValue } = useValue<Value>({\n initialValue,\n onChange,\n });\n const [type, setType] = useState<HTMLInputTypeAttribute>('password');\n\n useEffect(() => {\n if (disabled) {\n setType('password');\n } else {\n setType(type);\n }\n }, [type, disabled]);\n\n const toggleType = () => setType(type === 'password' ? 'text' : 'password');\n\n return (\n <FormControl\n className={className}\n id={id}\n label={label}\n dataName=\"Password\"\n dataTestId={dataTestId}\n disabled={disabled}\n required={required}\n hideRequiredStar={hideRequiredStar}\n validationStatus={withoutFieldValidation ? 'default' : validationStatus}\n errorMessage={errorMessage}\n >\n <div className=\"relative\">\n <input\n {...rest}\n id={id}\n name={name}\n type={type}\n value={value as any}\n disabled={disabled}\n required={required}\n onChange={(e) => setValue(e.target.value as Value, e.nativeEvent)}\n className={clsx(\n 'text-b3 rounded-pill w-full border overflow-hidden ps-20 py-[11px] font-normal outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',\n {\n 'border-middleGrey focus:border-black active:border-black pe-[52px]':\n (withoutFieldValidation || validationStatus === 'default') &&\n internalStatus !== 'disabled',\n 'bg-white text-black': internalStatus !== 'disabled',\n 'bg-pearl border-middleGrey': internalStatus === 'disabled',\n 'pe-[84px]':\n !withoutFieldValidation &&\n (validationStatus === 'error' || validationStatus === 'success'),\n 'border-red': !withoutFieldValidation && validationStatus === 'error',\n 'border-green': !withoutFieldValidation && validationStatus === 'success',\n },\n )}\n aria-label={name}\n />\n\n <div\n className={clsx(\n 'pointer-events-none absolute inset-0 flex items-center justify-between px-20 py-12',\n )}\n >\n <span className=\"ms-auto flex gap-x-8\">\n {!withoutFieldValidation && validationStatus === 'error' && (\n <Icon name=\"CrossDefault\" color=\"red\" width=\"24px\" />\n )}\n\n {!withoutFieldValidation && validationStatus === 'success' && (\n <Icon name=\"CheckDefault\" color=\"green\" width=\"24px\" />\n )}\n\n {!disabled && (\n <button\n type=\"button\"\n className=\"pointer-events-auto size-24 inline-flex outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n onClick={toggleType}\n >\n <Icon\n name={type === 'password' ? 'Invisible' : 'Visible'}\n width=\"24px\"\n type=\"svg\"\n />\n </button>\n )}\n </span>\n </div>\n </div>\n\n {validationMessages.length > 0 && (\n <div className=\"flex flex-col gap-[10px] mt-8\">\n {validationMessages.map(({ label, status }, index) => (\n <ValidationMessage label={label} status={status} key={index} />\n ))}\n </div>\n )}\n </FormControl>\n );\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,EAAyB,GAA6B;CACpE,IAAM,IAAa,GAAO,EAEpB,EACJ,QAAK,GACL,UAAO,GACP,UACA,OAAO,GACP,cAAW,IACX,cAAW,IACX,qBACA,sBAAmB,WACnB,iBACA,wBAAqB,EAAE,EACvB,4BAAyB,IACzB,cACA,aACA,gBAAa,YACb,GAAG,MACD,GAEE,IAAiB,EAAkB;EACvC,YAAY;EACZ;EACD,CAAC,EAEI,EAAE,UAAO,gBAAa,EAAgB;EAC1C;EACA;EACD,CAAC,EACI,CAAC,GAAM,KAAW,EAAiC,WAAW;AAEpE,SAAgB;AACd,EACE,EADE,IACM,aAEA,EAAK;IAEd,CAAC,GAAM,EAAS,CAAC;CAEpB,IAAM,UAAmB,EAAQ,MAAS,aAAa,SAAS,WAAW;AAE3E,QACE,kBAAC,GAAD;EACa;EACP;EACG;EACP,UAAS;EACG;EACF;EACA;EACQ;EAClB,kBAAkB,IAAyB,YAAY;EACzC;YAVhB,CAYE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,SAAD;IACE,GAAI;IACA;IACE;IACA;IACC;IACG;IACA;IACV,WAAW,MAAM,EAAS,EAAE,OAAO,OAAgB,EAAE,YAAY;IACjE,WAAW,EACT,yKACA;KACE,uEACG,KAA0B,MAAqB,cAChD,MAAmB;KACrB,uBAAuB,MAAmB;KAC1C,8BAA8B,MAAmB;KACjD,aACE,CAAC,MACA,MAAqB,WAAW,MAAqB;KACxD,cAAc,CAAC,KAA0B,MAAqB;KAC9D,gBAAgB,CAAC,KAA0B,MAAqB;KACjE,CACF;IACD,cAAY;IACZ,CAAA,EAEF,kBAAC,OAAD;IACE,WAAW,EACT,qFACD;cAED,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACG,CAAC,KAA0B,MAAqB,WAC/C,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAM,OAAM;OAAS,CAAA;MAGtD,CAAC,KAA0B,MAAqB,aAC/C,kBAAC,GAAD;OAAM,MAAK;OAAe,OAAM;OAAQ,OAAM;OAAS,CAAA;MAGxD,CAAC,KACA,kBAAC,UAAD;OACE,MAAK;OACL,WAAU;OACV,SAAS;iBAET,kBAAC,GAAD;QACE,MAAM,MAAS,aAAa,cAAc;QAC1C,OAAM;QACN,MAAK;QACL,CAAA;OACK,CAAA;MAEN;;IACH,CAAA,CACF;MAEL,EAAmB,SAAS,KAC3B,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAmB,KAAK,EAAE,UAAO,aAAU,MAC1C,kBAAC,GAAD;IAA0B;IAAe;IAAsB,EAAT,EAAS,CAC/D;GACE,CAAA,CAEI"}
|
|
@@ -122,7 +122,7 @@ function l({ itinerary: l, direction: u, directionType: d, departureDate: f, dep
|
|
|
122
122
|
type: "button",
|
|
123
123
|
onClick: () => I((e) => !e),
|
|
124
124
|
"aria-expanded": F,
|
|
125
|
-
className: "flex w-full cursor-pointer flex-row items-end justify-between border-none bg-transparent p-0",
|
|
125
|
+
className: "flex w-full cursor-pointer flex-row items-end justify-between border-none bg-transparent p-0 outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2",
|
|
126
126
|
children: [/* @__PURE__ */ c("div", {
|
|
127
127
|
className: "flex flex-col text-left",
|
|
128
128
|
children: [/* @__PURE__ */ s("span", {
|
|
@@ -166,7 +166,7 @@ function l({ itinerary: l, direction: u, directionType: d, departureDate: f, dep
|
|
|
166
166
|
children: E
|
|
167
167
|
}), D && /* @__PURE__ */ s("a", {
|
|
168
168
|
href: D,
|
|
169
|
-
className: "font-sans text-b4 underline",
|
|
169
|
+
className: "font-sans text-b4 underline outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 rounded-pill",
|
|
170
170
|
children: O
|
|
171
171
|
})]
|
|
172
172
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JourneyDetails.js","names":[],"sources":["../../../lib/ui/journey-card/JourneyDetails.tsx"],"sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ComponentPropsWithoutRef } from 'react';\nimport { useState } from 'react';\nimport { Icon } from '@clubmed/trident-icons';\nimport { Tag } from '../Tag';\nimport { ElasticHeight } from '../ElasticHeight';\nimport { FlightTimeline } from './FlightTimeline';\nimport { ItineraryDetails } from './ItineraryDetails';\nimport type { ItineraryDetailsProps } from './ItineraryDetails';\n\nexport interface AirportInfo {\n name: string;\n terminal?: string;\n}\n\nexport interface JourneyDetailsProps extends ComponentPropsWithoutRef<'div'> {\n /** Human-readable leg label, e.g. \"Outbound\" or \"Inbound\" */\n direction: string;\n /** Controls which plane icon is rendered; falls back to `direction` when omitted */\n directionType?: 'Inbound' | 'Outbound';\n departureDate: string;\n departureTime: string;\n arrivalDate: string;\n arrivalTime: string;\n /** Total flight duration, e.g. \"9h30mn\" */\n duration: string;\n departureAirport: AirportInfo;\n arrivalAirport: AirportInfo;\n /** Connection label shown on the timeline, e.g. \"Direct\" or \"1 Stop over\" */\n stopLabel: string;\n /** Number of stopover dots on the timeline */\n nbStopovers?: number;\n airlineLogoSrc: string;\n airlineLogoAlt: string;\n /** Primary operator name */\n operatedBy: string;\n /** Secondary operator line, e.g. \"Operated by Hop\" */\n companyName?: string;\n /** Cabin / luggage summary text */\n characteristics: string;\n /** Carbon footprint text */\n carbonEmission: string;\n carbonEmissionLearnMoreUrl?: string;\n carbonEmissionLearnMoreLabel: string;\n /** How many calendar days after departure the arrival falls */\n plusDays?: number;\n /** Label appended to plusDays value, e.g. \"day\" */\n plusDaysLabel: string;\n /** Local time qualifier shown near arrival time, e.g. \"(local time)\" */\n localTimeLabel: string;\n /** Optional expanded itinerary with per-segment flight cards */\n itinerary?: ItineraryDetailsProps;\n /** When true, the component is displayed in a vertical layout for side-by-side JourneyCards */\n vertical?: boolean;\n}\n\nexport function JourneyDetails({\n itinerary,\n direction,\n directionType,\n departureDate,\n departureTime,\n arrivalDate,\n arrivalTime,\n duration,\n departureAirport,\n arrivalAirport,\n stopLabel,\n nbStopovers,\n airlineLogoSrc,\n airlineLogoAlt,\n operatedBy,\n companyName,\n characteristics,\n carbonEmission,\n carbonEmissionLearnMoreUrl,\n carbonEmissionLearnMoreLabel,\n plusDays,\n plusDaysLabel,\n localTimeLabel,\n className,\n vertical = false,\n ...props\n}: JourneyDetailsProps) {\n const [isOpen, setIsOpen] = useState(false);\n const isOutbound = (directionType ?? direction) === 'Outbound';\n\n return (\n <div\n data-name=\"JourneyDetails\"\n {...props}\n className={clsx('flex h-fit w-full flex-col gap-8', className)}\n >\n {/* Row 1 — direction label + airline logo */}\n <div className=\"flex h-48 w-full flex-row items-center justify-between\">\n <div className=\"flex h-fit flex-row items-center gap-12\">\n <Icon\n name={isOutbound ? 'PlaneOutbound' : 'PlaneInBound'}\n width=\"24px\"\n className=\"text-black\"\n />\n <span className=\"font-sans text-b3 font-semibold\">{direction}</span>\n </div>\n <img\n src={airlineLogoSrc}\n alt={airlineLogoAlt}\n width={100}\n height={28}\n className=\"object-contain\"\n />\n </div>\n\n {/* Row 2 — schedule */}\n <div className=\"flex h-fit w-full flex-col gap-4\">\n <div className=\"flex w-full flex-row items-end justify-between\">\n <div className=\"flex flex-1 flex-col\">\n <span className=\"font-sans text-b4\">{departureDate}</span>\n <span className=\"font-sans text-b1 font-semibold\">{departureTime}</span>\n </div>\n\n <div className=\"flex flex-1 justify-center\">\n <span className=\"text-center font-sans text-b4\">{duration}</span>\n </div>\n\n <div className=\"flex flex-1 flex-col items-end\">\n <div\n className={clsx(\n 'flex',\n !vertical && 'flex-row items-center justify-end gap-4',\n vertical && 'flex-col items-end justify-start gap-0',\n )}\n >\n <span className=\"font-sans text-b4\">{arrivalDate}</span>\n {plusDays && plusDays > 0 && (\n <Tag\n label={`+${plusDays} ${plusDaysLabel}`}\n theme=\"label\"\n backgroundColor=\"black\"\n color=\"white\"\n className=\"rounded-full\"\n />\n )}\n </div>\n <span className=\"text-right font-sans text-b4\">{localTimeLabel}</span>\n <span className=\"text-right font-sans text-b1 font-semibold\">{arrivalTime}</span>\n </div>\n </div>\n\n <FlightTimeline nbStopovers={nbStopovers} />\n\n <div className=\"flex w-full flex-row items-start justify-between\">\n <div className=\"flex flex-1 flex-col\">\n <span className=\"font-sans text-b4 font-semibold\">{departureAirport.name}</span>\n {departureAirport.terminal && (\n <span className=\"font-sans text-b4\">{departureAirport.terminal}</span>\n )}\n </div>\n <span className=\"flex-1 text-center font-sans text-b4\">{stopLabel}</span>\n <div className=\"flex flex-1 flex-col items-end\">\n <span className=\"font-sans text-b4 font-semibold\">{arrivalAirport.name}</span>\n {arrivalAirport.terminal && (\n <span className=\"text-right font-sans text-b4\">{arrivalAirport.terminal}</span>\n )}\n </div>\n </div>\n </div>\n\n {/* Row 3 — operator toggle */}\n <button\n type=\"button\"\n onClick={() => setIsOpen((v) => !v)}\n aria-expanded={isOpen}\n className=\"flex w-full cursor-pointer flex-row items-end justify-between border-none bg-transparent p-0\"\n >\n <div className=\"flex flex-col text-left\">\n <span className=\"font-sans text-b4 font-semibold\">{operatedBy}</span>\n {companyName && <span className=\"font-sans text-b4\">{companyName}</span>}\n </div>\n <Icon\n name=\"ArrowOutlinedUp\"\n width=\"24px\"\n className={clsx('text-black transition-transform duration-200', {\n 'rotate-180': !isOpen,\n })}\n />\n </button>\n\n {/* Rows 4 & 5 — accordion */}\n <ElasticHeight isExpanded={isOpen} innerClassName=\"flex flex-col gap-8\">\n <div className=\"flex h-fit w-full flex-row items-start gap-8\">\n <Icon name=\"Luggage\" width=\"24px\" className=\"shrink-0 text-black\" />\n <span className=\"font-sans text-b4\">{characteristics}</span>\n </div>\n <div className=\"flex h-fit w-full flex-row items-start gap-8\">\n <Icon name=\"HappyToCare\" width=\"24px\" className=\"shrink-0 text-black\" />\n <div className=\"flex flex-col\">\n <span className=\"font-sans text-b4\">{carbonEmission}</span>\n {carbonEmissionLearnMoreUrl && (\n <a href={carbonEmissionLearnMoreUrl} className=\"font-sans text-b4 underline\">\n {carbonEmissionLearnMoreLabel}\n </a>\n )}\n </div>\n </div>\n {itinerary && <ItineraryDetails {...itinerary} />}\n </ElasticHeight>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JourneyDetails.js","names":[],"sources":["../../../lib/ui/journey-card/JourneyDetails.tsx"],"sourcesContent":["'use client';\n\nimport clsx from 'clsx';\nimport type { ComponentPropsWithoutRef } from 'react';\nimport { useState } from 'react';\nimport { Icon } from '@clubmed/trident-icons';\nimport { Tag } from '../Tag';\nimport { ElasticHeight } from '../ElasticHeight';\nimport { FlightTimeline } from './FlightTimeline';\nimport { ItineraryDetails } from './ItineraryDetails';\nimport type { ItineraryDetailsProps } from './ItineraryDetails';\n\nexport interface AirportInfo {\n name: string;\n terminal?: string;\n}\n\nexport interface JourneyDetailsProps extends ComponentPropsWithoutRef<'div'> {\n /** Human-readable leg label, e.g. \"Outbound\" or \"Inbound\" */\n direction: string;\n /** Controls which plane icon is rendered; falls back to `direction` when omitted */\n directionType?: 'Inbound' | 'Outbound';\n departureDate: string;\n departureTime: string;\n arrivalDate: string;\n arrivalTime: string;\n /** Total flight duration, e.g. \"9h30mn\" */\n duration: string;\n departureAirport: AirportInfo;\n arrivalAirport: AirportInfo;\n /** Connection label shown on the timeline, e.g. \"Direct\" or \"1 Stop over\" */\n stopLabel: string;\n /** Number of stopover dots on the timeline */\n nbStopovers?: number;\n airlineLogoSrc: string;\n airlineLogoAlt: string;\n /** Primary operator name */\n operatedBy: string;\n /** Secondary operator line, e.g. \"Operated by Hop\" */\n companyName?: string;\n /** Cabin / luggage summary text */\n characteristics: string;\n /** Carbon footprint text */\n carbonEmission: string;\n carbonEmissionLearnMoreUrl?: string;\n carbonEmissionLearnMoreLabel: string;\n /** How many calendar days after departure the arrival falls */\n plusDays?: number;\n /** Label appended to plusDays value, e.g. \"day\" */\n plusDaysLabel: string;\n /** Local time qualifier shown near arrival time, e.g. \"(local time)\" */\n localTimeLabel: string;\n /** Optional expanded itinerary with per-segment flight cards */\n itinerary?: ItineraryDetailsProps;\n /** When true, the component is displayed in a vertical layout for side-by-side JourneyCards */\n vertical?: boolean;\n}\n\nexport function JourneyDetails({\n itinerary,\n direction,\n directionType,\n departureDate,\n departureTime,\n arrivalDate,\n arrivalTime,\n duration,\n departureAirport,\n arrivalAirport,\n stopLabel,\n nbStopovers,\n airlineLogoSrc,\n airlineLogoAlt,\n operatedBy,\n companyName,\n characteristics,\n carbonEmission,\n carbonEmissionLearnMoreUrl,\n carbonEmissionLearnMoreLabel,\n plusDays,\n plusDaysLabel,\n localTimeLabel,\n className,\n vertical = false,\n ...props\n}: JourneyDetailsProps) {\n const [isOpen, setIsOpen] = useState(false);\n const isOutbound = (directionType ?? direction) === 'Outbound';\n\n return (\n <div\n data-name=\"JourneyDetails\"\n {...props}\n className={clsx('flex h-fit w-full flex-col gap-8', className)}\n >\n {/* Row 1 — direction label + airline logo */}\n <div className=\"flex h-48 w-full flex-row items-center justify-between\">\n <div className=\"flex h-fit flex-row items-center gap-12\">\n <Icon\n name={isOutbound ? 'PlaneOutbound' : 'PlaneInBound'}\n width=\"24px\"\n className=\"text-black\"\n />\n <span className=\"font-sans text-b3 font-semibold\">{direction}</span>\n </div>\n <img\n src={airlineLogoSrc}\n alt={airlineLogoAlt}\n width={100}\n height={28}\n className=\"object-contain\"\n />\n </div>\n\n {/* Row 2 — schedule */}\n <div className=\"flex h-fit w-full flex-col gap-4\">\n <div className=\"flex w-full flex-row items-end justify-between\">\n <div className=\"flex flex-1 flex-col\">\n <span className=\"font-sans text-b4\">{departureDate}</span>\n <span className=\"font-sans text-b1 font-semibold\">{departureTime}</span>\n </div>\n\n <div className=\"flex flex-1 justify-center\">\n <span className=\"text-center font-sans text-b4\">{duration}</span>\n </div>\n\n <div className=\"flex flex-1 flex-col items-end\">\n <div\n className={clsx(\n 'flex',\n !vertical && 'flex-row items-center justify-end gap-4',\n vertical && 'flex-col items-end justify-start gap-0',\n )}\n >\n <span className=\"font-sans text-b4\">{arrivalDate}</span>\n {plusDays && plusDays > 0 && (\n <Tag\n label={`+${plusDays} ${plusDaysLabel}`}\n theme=\"label\"\n backgroundColor=\"black\"\n color=\"white\"\n className=\"rounded-full\"\n />\n )}\n </div>\n <span className=\"text-right font-sans text-b4\">{localTimeLabel}</span>\n <span className=\"text-right font-sans text-b1 font-semibold\">{arrivalTime}</span>\n </div>\n </div>\n\n <FlightTimeline nbStopovers={nbStopovers} />\n\n <div className=\"flex w-full flex-row items-start justify-between\">\n <div className=\"flex flex-1 flex-col\">\n <span className=\"font-sans text-b4 font-semibold\">{departureAirport.name}</span>\n {departureAirport.terminal && (\n <span className=\"font-sans text-b4\">{departureAirport.terminal}</span>\n )}\n </div>\n <span className=\"flex-1 text-center font-sans text-b4\">{stopLabel}</span>\n <div className=\"flex flex-1 flex-col items-end\">\n <span className=\"font-sans text-b4 font-semibold\">{arrivalAirport.name}</span>\n {arrivalAirport.terminal && (\n <span className=\"text-right font-sans text-b4\">{arrivalAirport.terminal}</span>\n )}\n </div>\n </div>\n </div>\n\n {/* Row 3 — operator toggle */}\n <button\n type=\"button\"\n onClick={() => setIsOpen((v) => !v)}\n aria-expanded={isOpen}\n className=\"flex w-full cursor-pointer flex-row items-end justify-between border-none bg-transparent p-0 outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2\"\n >\n <div className=\"flex flex-col text-left\">\n <span className=\"font-sans text-b4 font-semibold\">{operatedBy}</span>\n {companyName && <span className=\"font-sans text-b4\">{companyName}</span>}\n </div>\n <Icon\n name=\"ArrowOutlinedUp\"\n width=\"24px\"\n className={clsx('text-black transition-transform duration-200', {\n 'rotate-180': !isOpen,\n })}\n />\n </button>\n\n {/* Rows 4 & 5 — accordion */}\n <ElasticHeight isExpanded={isOpen} innerClassName=\"flex flex-col gap-8\">\n <div className=\"flex h-fit w-full flex-row items-start gap-8\">\n <Icon name=\"Luggage\" width=\"24px\" className=\"shrink-0 text-black\" />\n <span className=\"font-sans text-b4\">{characteristics}</span>\n </div>\n <div className=\"flex h-fit w-full flex-row items-start gap-8\">\n <Icon name=\"HappyToCare\" width=\"24px\" className=\"shrink-0 text-black\" />\n <div className=\"flex flex-col\">\n <span className=\"font-sans text-b4\">{carbonEmission}</span>\n {carbonEmissionLearnMoreUrl && (\n <a\n href={carbonEmissionLearnMoreUrl}\n className=\"font-sans text-b4 underline outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2 rounded-pill\"\n >\n {carbonEmissionLearnMoreLabel}\n </a>\n )}\n </div>\n </div>\n {itinerary && <ItineraryDetails {...itinerary} />}\n </ElasticHeight>\n </div>\n );\n}\n"],"mappings":"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"}
|