@spear-ai/spectral 1.16.5 → 1.16.7

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/dist/Button.js CHANGED
@@ -3,7 +3,7 @@ import { LoaderIcon } from "./Icons/LoaderIcon.js";
3
3
  import { cn } from "./utils/twUtils.js";
4
4
  import { Slot } from "./primitives/slot.js";
5
5
  import { Children, isValidElement } from "react";
6
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { cva } from "class-variance-authority";
8
8
 
9
9
  //#region src/components/Button/Button.tsx
@@ -78,7 +78,7 @@ const Button = ({ asChild = false, children, className, dataTestId, disabled, en
78
78
  tabIndex: canUseAsChild && disabled ? -1 : void 0,
79
79
  type: canUseAsChild ? void 0 : type,
80
80
  ...props,
81
- children: canUseAsChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
81
+ children: canUseAsChild ? children : /* @__PURE__ */ jsxs(Fragment$1, { children: [
82
82
  startIcon && /* @__PURE__ */ jsx("span", {
83
83
  className: cn("flex", variant !== "unstyled" && "pr-1"),
84
84
  "aria-hidden": true,
@@ -6,7 +6,7 @@ import { Input } from "../primitives/input.js";
6
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../primitives/select.js";
7
7
  import { ControlGroup, ControlGroupItem, useControlGroup } from "../ControlGroup.js";
8
8
  import { useId } from "react";
9
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
10
 
11
11
  //#region src/components/ControlGroup/ControlGroupSelect.tsx
12
12
  const numberInputNoSpinner = "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none";
@@ -127,7 +127,7 @@ const ControlGroupSelectInner = ({ amountStep, dataTestId, dropdownWidth, inputA
127
127
  placeholder: selectCaption
128
128
  })
129
129
  });
130
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ControlGroupItem, {
130
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ControlGroupItem, {
131
131
  className: cn(useAboveLabels ? firstItemAboveLabelClasses : void 0, inputItemClassName),
132
132
  children: useAboveLabels ? /* @__PURE__ */ jsxs("div", {
133
133
  className: fieldStackClass,
@@ -1 +1 @@
1
- {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!' placeholder={selectCaption} />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={inputId} id={inputLabelId}>\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select {...selectProps} data-testid={`${dataTestId}-select-root`} disabled={isDisabled} {...(isSelectOpenControlled ? { open: selectProps.open } : {})} onOpenChange={handleSelectOpenChange}>\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={selectTriggerId} id={selectLabelId}>\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent data-testid={`${dataTestId}-select-content`} dropdownWidth={dropdownWidth}>\n {selectOptions.map((option) => (\n <SelectItem disabled={option.disabled} key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ControlGroupSelect.js","names":[],"sources":["../../src/components/ControlGroup/ControlGroupSelect.tsx"],"sourcesContent":["import { Label } from '@components/Label/Label'\nimport { Input } from '@primitives/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@primitives/select'\nimport { getStateClasses, type DropdownWidth, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useId, type ComponentProps } from 'react'\nimport { ControlGroup, ControlGroupItem, useControlGroup, type ControlGroupProps } from './ControlGroup'\n\nconst numberInputNoSpinner = '[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none'\nconst defaultInputLabel = 'Amount'\nconst defaultSelectLabel = 'Select an option'\n\nexport interface SelectOptionType {\n disabled?: boolean\n label: string\n value: string\n}\n\n/** `inline`: `inputPlaceholder` / `selectPlaceholder` show inside the fields. `above`: same strings render as labels above each control (no inner placeholders). */\nexport type ControlGroupSelectCaptionLayout = 'above' | 'inline'\n\ntype ControlGroupSelectInputControlProps =\n | {\n inputValue: ComponentProps<typeof Input>['value']\n onInputChange: ComponentProps<typeof Input>['onChange']\n }\n | {\n inputValue?: undefined\n onInputChange?: undefined\n }\n\ntype ControlGroupSelectBaseProps = ComponentProps<typeof Select> &\n Pick<ControlGroupProps, 'orientation'> & {\n amountStep?: number\n /** Accessible name for the group wrapper (use when there is no visible group heading). */\n ariaLabel?: string\n captionLayout?: ControlGroupSelectCaptionLayout\n className?: string\n dataTestId?: string\n disabled?: boolean\n dropdownWidth?: DropdownWidth\n errorMessage?: string | string[] | Record<string, unknown> | null\n id?: string\n /** Class applied to the input `ControlGroupItem` segment for width/split composition. */\n inputItemClassName?: string\n /** When `captionLayout` is `inline`, overrides the input's accessible name (defaults to `inputPlaceholder` when set). */\n inputAriaLabel?: string\n inputPlaceholder?: string\n maxAmount?: number\n /** Number of message lines to reserve (default: 1). */\n messageReserveLines?: number\n /** Whether to keep message space reserved when hidden (default: false). */\n messageReserveSpace?: boolean\n minAmount?: number\n selectPlaceholder?: string\n /** When `captionLayout` is `inline` and `selectPlaceholder` is empty, sets the select trigger's accessible name. */\n selectAriaLabel?: string\n /** Class applied to the select `ControlGroupItem` segment for width/split composition. */\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n state?: Exclude<FormFieldState, 'disabled'>\n type?: 'number' | 'text'\n warningMessage?: string | string[] | Record<string, unknown> | null\n }\n\nexport type ControlGroupSelectProps = ControlGroupSelectBaseProps & ControlGroupSelectInputControlProps\n\nconst fieldStackClass = 'flex w-full min-w-0 flex-col gap-1.5'\nconst groupedFieldBaseClasses =\n 'h-12! min-h-12! border-2! border-input-border bg-input-bg text-base text-input-text transition duration-200 placeholder:text-input-text-placeholder hover:border-input-border--hover focus-visible:border-input-border--focus focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus disabled:pointer-events-none disabled:border-input-border--disabled disabled:bg-input-bg--disabled disabled:text-input-text--disabled'\n\nconst getFieldMinWidth = (caption?: string, extraCharacters: number = 0): string | undefined => {\n const normalizedCaption = caption?.trim()\n if (!normalizedCaption) return undefined\n return `${Math.max(normalizedCaption.length + extraCharacters, 8)}ch`\n}\n\nconst getReadableLabel = (label: string | undefined, fallback: string): string => {\n const normalizedLabel = label?.trim()\n return normalizedLabel && normalizedLabel.length > 0 ? normalizedLabel : fallback\n}\n\nexport const ControlGroupSelect = ({\n amountStep,\n ariaLabel,\n captionLayout = 'inline',\n className,\n dataTestId = 'spectral-control-group-select',\n disabled,\n errorMessage,\n id,\n dropdownWidth = 'trigger',\n inputAriaLabel,\n inputPlaceholder,\n inputItemClassName,\n inputValue,\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxAmount = 1000000,\n minAmount = 0,\n onInputChange,\n orientation = 'horizontal',\n selectAriaLabel,\n selectItemClassName,\n selectOptions,\n selectPlaceholder,\n state = 'default',\n type = 'number',\n warningMessage,\n ...selectProps\n}: ControlGroupSelectProps) => {\n const baseId = useId()\n const idPrefix = id ?? baseId\n const inputId = `${idPrefix}-amount`\n const selectTriggerId = `${idPrefix}-select`\n const inputLabelId = `${inputId}-label`\n const selectLabelId = `${selectTriggerId}-label`\n\n const useAboveLabels = captionLayout === 'above'\n const inputCaption = useAboveLabels ? undefined : inputPlaceholder\n const selectCaption = useAboveLabels ? undefined : selectPlaceholder\n const inputLabelText = getReadableLabel(inputPlaceholder, defaultInputLabel)\n const selectLabelText = getReadableLabel(selectPlaceholder, defaultSelectLabel)\n\n const inputAccessibleName = inputAriaLabel ?? (useAboveLabels ? undefined : inputLabelText)\n const selectTriggerAriaLabel = selectAriaLabel ?? (useAboveLabels ? undefined : selectLabelText)\n const inputMinWidth = getFieldMinWidth(inputPlaceholder, 3)\n const selectTriggerMinWidth = getFieldMinWidth(selectPlaceholder, 5)\n const groupAriaLabel = ariaLabel ?? `${inputLabelText} and ${selectLabelText}`\n\n const isDisabled = !!disabled\n const isInputControlled = inputValue !== undefined && onInputChange !== undefined\n\n return (\n <ControlGroup\n aria-label={groupAriaLabel}\n className={className}\n data-testid={dataTestId}\n disabled={disabled}\n errorMessage={errorMessage}\n id={idPrefix}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n orientation={orientation}\n state={state}\n warningMessage={warningMessage}\n >\n <ControlGroupSelectInner\n amountStep={amountStep}\n dataTestId={dataTestId}\n inputAccessibleName={inputAccessibleName}\n inputCaption={inputCaption}\n inputId={inputId}\n inputLabelId={inputLabelId}\n inputLabelText={inputLabelText}\n inputItemClassName={inputItemClassName}\n inputMinWidth={inputMinWidth}\n inputValue={isInputControlled ? inputValue : undefined}\n isDisabled={isDisabled}\n maxAmount={maxAmount}\n minAmount={minAmount}\n onInputChange={isInputControlled ? onInputChange : undefined}\n dropdownWidth={dropdownWidth}\n selectCaption={selectCaption}\n selectOptions={selectOptions}\n selectLabelId={selectLabelId}\n selectLabelText={selectLabelText}\n selectItemClassName={selectItemClassName}\n selectProps={selectProps}\n selectTriggerAriaLabel={selectTriggerAriaLabel}\n selectTriggerId={selectTriggerId}\n selectTriggerMinWidth={selectTriggerMinWidth}\n type={type}\n useAboveLabels={useAboveLabels}\n />\n </ControlGroup>\n )\n}\n\ninterface ControlGroupSelectInnerProps {\n amountStep?: number\n dataTestId: string\n dropdownWidth: DropdownWidth\n inputAccessibleName?: string\n inputCaption?: string\n inputId: string\n inputLabelId: string\n inputLabelText: string\n inputItemClassName?: string\n inputMinWidth?: string\n inputValue?: ComponentProps<typeof Input>['value']\n isDisabled: boolean\n maxAmount: number\n minAmount: number\n onInputChange?: ComponentProps<typeof Input>['onChange']\n selectCaption?: string\n selectLabelId: string\n selectLabelText: string\n selectItemClassName?: string\n selectOptions: SelectOptionType[]\n selectProps: Omit<ComponentProps<typeof Select>, 'children'>\n selectTriggerAriaLabel?: string\n selectTriggerId: string\n selectTriggerMinWidth?: string\n type: 'number' | 'text'\n useAboveLabels: boolean\n}\n\nconst ControlGroupSelectInner = ({\n amountStep,\n dataTestId,\n dropdownWidth,\n inputAccessibleName,\n inputCaption,\n inputId,\n inputLabelId,\n inputLabelText,\n inputItemClassName,\n inputMinWidth,\n inputValue,\n isDisabled,\n maxAmount,\n minAmount,\n onInputChange,\n selectCaption,\n selectLabelId,\n selectLabelText,\n selectItemClassName,\n selectOptions,\n selectProps,\n selectTriggerAriaLabel,\n selectTriggerId,\n selectTriggerMinWidth,\n type,\n useAboveLabels,\n}: ControlGroupSelectInnerProps) => {\n const { messageId, orientation, state } = useControlGroup()\n const isSelectOpenControlled = selectProps.open !== undefined\n const handleSelectOpenChange: NonNullable<ComponentProps<typeof Select>['onOpenChange']> = (nextOpen) => {\n selectProps.onOpenChange?.(nextOpen)\n }\n\n const inputRadiusClasses = orientation === 'horizontal' ? 'rounded-s-md rounded-e-none' : 'rounded-ss-md rounded-se-md rounded-es-none rounded-ee-none'\n const selectRadiusClasses = orientation === 'horizontal' ? 'rounded-s-none rounded-e-md' : 'rounded-ss-none rounded-se-none rounded-es-md rounded-ee-md'\n const firstItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0' : 'mbe-0'\n const secondItemAboveLabelClasses = orientation === 'horizontal' ? 'me-0 [&>*:last-child]:-ms-0.5' : 'mbe-0 [&>*:last-child]:-mt-0.5'\n\n const inputElement = (\n <Input\n aria-describedby={messageId}\n aria-label={inputAccessibleName}\n aria-labelledby={useAboveLabels ? inputLabelId : undefined}\n className={cn(groupedFieldBaseClasses, inputRadiusClasses, getStateClasses(state), type === 'number' && numberInputNoSpinner, type === 'number' && 'tabular-nums')}\n data-testid={`${dataTestId}-input`}\n disabled={isDisabled}\n id={useAboveLabels ? inputId : undefined}\n type={type === 'number' ? 'number' : 'text'}\n placeholder={inputCaption}\n style={inputMinWidth ? { minWidth: inputMinWidth } : undefined}\n min={minAmount ?? 0}\n max={maxAmount ?? 1000000}\n {...(inputValue !== undefined && onInputChange !== undefined ? { value: inputValue, onChange: onInputChange } : {})}\n step={amountStep ?? 1}\n />\n )\n\n const selectTriggerElement = (\n <SelectTrigger\n aria-describedby={messageId}\n aria-label={selectTriggerAriaLabel}\n aria-labelledby={useAboveLabels ? selectLabelId : undefined}\n className={cn(\n 'text-input-text data-placeholder:text-input-text-placeholder!',\n selectRadiusClasses,\n 'px-4 w-full justify-between focus-visible:border-input-border--focus focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus',\n getStateClasses(state),\n )}\n data-testid={`${dataTestId}-select-trigger`}\n disabled={isDisabled}\n id={useAboveLabels ? selectTriggerId : undefined}\n style={selectTriggerMinWidth ? { minWidth: selectTriggerMinWidth } : undefined}\n >\n <SelectValue className='min-w-0 block max-w-full truncate text-left whitespace-nowrap text-input-text! data-placeholder:text-input-text-placeholder!' placeholder={selectCaption} />\n </SelectTrigger>\n )\n\n return (\n <>\n <ControlGroupItem className={cn(useAboveLabels ? firstItemAboveLabelClasses : undefined, inputItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={inputId} id={inputLabelId}>\n {inputLabelText}\n </Label>\n {inputElement}\n </div>\n ) : (\n inputElement\n )}\n </ControlGroupItem>\n <Select {...selectProps} data-testid={`${dataTestId}-select-root`} disabled={isDisabled} {...(isSelectOpenControlled ? { open: selectProps.open } : {})} onOpenChange={handleSelectOpenChange}>\n <ControlGroupItem className={cn(useAboveLabels ? secondItemAboveLabelClasses : undefined, selectItemClassName)}>\n {useAboveLabels ? (\n <div className={fieldStackClass}>\n <Label className='text-text-primary' htmlFor={selectTriggerId} id={selectLabelId}>\n {selectLabelText}\n </Label>\n {selectTriggerElement}\n </div>\n ) : (\n selectTriggerElement\n )}\n </ControlGroupItem>\n <SelectContent data-testid={`${dataTestId}-select-content`} dropdownWidth={dropdownWidth}>\n {selectOptions.map((option) => (\n <SelectItem disabled={option.disabled} key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n )\n}\n"],"mappings":"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"}
@@ -17,6 +17,7 @@ interface DateTimePickerProps extends Omit<ComponentProps<'div'>, 'onChange' | '
17
17
  disablePastDates?: boolean;
18
18
  errorMessage?: string | string[] | Record<string, unknown> | null;
19
19
  hourFormat?: HourFormat;
20
+ inputClassName?: string;
20
21
  label?: string;
21
22
  locale?: Partial<Locale$1>;
22
23
  messageReserveLines?: number;
@@ -37,6 +38,7 @@ declare function DateTimePicker({
37
38
  disablePastDates,
38
39
  errorMessage,
39
40
  hourFormat,
41
+ inputClassName,
40
42
  label,
41
43
  locale,
42
44
  messageReserveLines,
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimePicker.d.ts","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"mappings":";;;;;;;;;;;;UAYiB,mBAAA,SAA4B,IAAA,CAAK,cAAA;EAChD,aAAA,GAAgB,IAAA,CAAK,aAAA;EACrB,YAAA,GAAe,IAAA;EACf,QAAA;EACA,gBAAA;EACA,YAAA,uBAAmC,MAAA;EACnC,UAAA,GAAa,UAAA;EACb,KAAA;EACA,MAAA,GAAS,OAAA,CAAQ,QAAA;EACjB,mBAAA;EACA,mBAAA;EACA,QAAA,IAAY,IAAA,EAAM,IAAA;EAClB,cAAA;EACA,KAAA;EACA,UAAA;EARa;EAUb,gBAAA,GAAmB,OAAA,CAAQ,sBAAA;EAC3B,KAAA,GAAQ,IAAA;AAAA;AAAA;EAIR,aAAA;EACA,SAAA;EACA,YAAA;EACA,QAAA;EACA,gBAAA;EACA,YAAA;EACA,UAAA;EACA,KAAA;EACA,MAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA;EACA,cAAA;EACA,KAAA;EACA,UAAA;EACA,gBAAA;EACA,KAAA;EACA,EAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"DateTimePicker.d.ts","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"mappings":";;;;;;;;;;;;UAYiB,mBAAA,SAA4B,IAAA,CAAK,cAAA;EAChD,aAAA,GAAgB,IAAA,CAAK,aAAA;EACrB,YAAA,GAAe,IAAA;EACf,QAAA;EACA,gBAAA;EACA,YAAA,uBAAmC,MAAA;EACnC,UAAA,GAAa,UAAA;EACb,cAAA;EACA,KAAA;EACA,MAAA,GAAS,OAAA,CAAQ,QAAA;EACjB,mBAAA;EACA,mBAAA;EACA,QAAA,IAAY,IAAA,EAAM,IAAA;EAClB,cAAA;EACA,KAAA;EACA,UAAA;EANiB;EAQjB,gBAAA,GAAmB,OAAA,CAAQ,sBAAA;EAC3B,KAAA,GAAQ,IAAA;AAAA;AAAA;EAIR,aAAA;EACA,SAAA;EACA,YAAA;EACA,QAAA;EACA,gBAAA;EACA,YAAA;EACA,UAAA;EACA,cAAA;EACA,KAAA;EACA,MAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA;EACA,cAAA;EACA,KAAA;EACA,UAAA;EACA,gBAAA;EACA,KAAA;EACA,EAAA;EAAA,GACG;AAAA,GACF,mBAAA,GAAmB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
@@ -16,7 +16,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
16
16
  import "react-day-picker";
17
17
 
18
18
  //#region src/components/DateTimePicker/DateTimePicker.tsx
19
- const DateTimePicker = ({ calendarProps, className, defaultValue, disabled = false, disablePastDates = true, errorMessage, hourFormat, label, locale, messageReserveLines = 1, messageReserveSpace = false, onChange, showTimePicker = true, state = "default", timeLocale, timeTranslations, value, id, ...props }) => {
19
+ const DateTimePicker = ({ calendarProps, className, defaultValue, disabled = false, disablePastDates = true, errorMessage, hourFormat, inputClassName, label, locale, messageReserveLines = 1, messageReserveSpace = false, onChange, showTimePicker = true, state = "default", timeLocale, timeTranslations, value, id, ...props }) => {
20
20
  const fieldId = useFormFieldId(id);
21
21
  const errorMessageId = getErrorMessageId(fieldId);
22
22
  const describedBy = state === "error" && errorMessage ? errorMessageId : void 0;
@@ -50,7 +50,7 @@ const DateTimePicker = ({ calendarProps, className, defaultValue, disabled = fal
50
50
  children: [/* @__PURE__ */ jsx(DateTimeDisplayInput, {
51
51
  "aria-describedby": describedBy,
52
52
  "aria-invalid": state === "error",
53
- className: cn("gap-4 pr-12 flex w-full justify-start", !date && "text-text-secondary"),
53
+ className: cn("gap-4 pr-12 flex w-full justify-start", !date && "text-text-secondary", inputClassName),
54
54
  "data-testid": "spectral-datetime-picker-input",
55
55
  disabled,
56
56
  endIcon: /* @__PURE__ */ jsx(PopoverTrigger, {
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimePicker.js","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { CalendarIcon } from '@components/Icons'\nimport { Popover, PopoverContent, PopoverTrigger } from '@components/Popover/Popover'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useMemo, type ComponentProps } from 'react'\nimport { type Locale } from 'react-day-picker'\nimport { Calendar, type CalendarProps } from './Calendar'\nimport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nimport { detectHourFormat, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePicker } from './TimePicker'\n\nexport interface DateTimePickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n calendarProps?: Omit<CalendarProps, 'mode' | 'selected' | 'onSelect' | 'disablePastDates' | 'locale'>\n defaultValue?: Date\n disabled?: boolean\n disablePastDates?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n hourFormat?: HourFormat\n label?: string\n locale?: Partial<Locale>\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (date: Date | undefined) => void\n showTimePicker?: boolean\n state?: 'default' | 'disabled' | 'error'\n timeLocale?: string\n /** Override translation strings for time picker ARIA labels */\n timeTranslations?: Partial<TimePickerTranslations>\n value?: Date\n}\n\nexport const DateTimePicker = ({\n calendarProps,\n className,\n defaultValue,\n disabled = false,\n disablePastDates = true,\n errorMessage,\n hourFormat,\n label,\n locale,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onChange,\n showTimePicker = true,\n state = 'default',\n timeLocale,\n timeTranslations,\n value,\n id,\n ...props\n}: DateTimePickerProps) => {\n const fieldId = useFormFieldId(id)\n const errorMessageId = getErrorMessageId(fieldId)\n const describedBy = state === 'error' && errorMessage ? errorMessageId : undefined\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue,\n onChange,\n value,\n })\n\n // Resolve time locale with fallback chain\n const resolvedTimeLocale = useMemo(() => getResolvedLocale(timeLocale), [timeLocale])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedTimeLocale), [hourFormat, resolvedTimeLocale])\n\n const handleDateSelect = (selectedDate: Date | undefined) => {\n if (!selectedDate) {\n setDate(undefined)\n return\n }\n\n // Preserve the time from the existing date\n if (date) {\n selectedDate.setHours(date.getHours(), date.getMinutes(), 0, 0)\n }\n\n setDate(selectedDate)\n }\n\n const handleTimeChange = useCallback(\n (newDate: Date | undefined) => {\n setDate(newDate)\n },\n [setDate],\n )\n\n const handlePeriodChange = (period: Period) => {\n // Period change is already handled in TimePicker\n // This callback is for external consumers who want to react to period changes\n void period\n }\n\n const handleInputDateChange = (newDate: Date | undefined) => {\n setDate(newDate)\n }\n\n return (\n <Popover>\n <div className={cn('w-full', className)} data-slot='datetime-picker' data-testid='spectral-datetime-picker' {...props}>\n <DateTimeDisplayInput\n aria-describedby={describedBy}\n aria-invalid={state === 'error'}\n className={cn('gap-4 pr-12 flex w-full justify-start', !date && 'text-text-secondary')}\n data-testid='spectral-datetime-picker-input'\n disabled={disabled}\n endIcon={\n <PopoverTrigger asChild disabled={disabled}>\n <CalendarIcon\n aria-label='Open date picker'\n className={cn('right-4 text-input-icon hover:text-input-icon--hover absolute top-1/2 -translate-y-1/2 cursor-pointer focus:outline-none', disabled ? 'pointer-events-none cursor-not-allowed opacity-50' : 'hover:text-input-icon--hover cursor-pointer')}\n data-testid='spectral-datetime-picker-trigger'\n disabled={disabled}\n />\n </PopoverTrigger>\n }\n hourFormat={effectiveHourFormat}\n id={fieldId}\n label={label}\n onChange={handleInputDateChange}\n showTime={showTimePicker}\n state={state}\n value={date}\n />\n <ErrorMessage\n dataTestId='spectral-datetime-picker-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n\n <PopoverContent\n align='start'\n className={cn('rounded-lg py-4 px-6 flex', !showTimePicker && 'w-[330px]', showTimePicker && effectiveHourFormat === '24' && 'w-[486px]', showTimePicker && effectiveHourFormat === '12' && 'w-[560px]')}\n data-testid='spectral-datetime-picker-popover'\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar {...calendarProps} disablePastDates={disablePastDates} locale={locale} mode='single' onSelect={handleDateSelect} selected={date} />\n {showTimePicker && (\n <div className='pl-6 border-l border-border-secondary'>\n <TimePicker date={date} hourFormat={effectiveHourFormat} locale={resolvedTimeLocale} onChange={handleTimeChange} onPeriodChange={handlePeriodChange} translations={timeTranslations} />\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n\nDateTimePicker.displayName = 'DateTimePicker'\n\n// Re-export sub-components for granular usage\nexport { Calendar } from './Calendar'\nexport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nexport { DateTimeInput } from './DateTimeInput'\nexport { TimePeriodSelect } from './TimePeriodSelect'\nexport { TimePicker } from './TimePicker'\nexport * from './DateTimeUtils'\nexport { type Locale } from 'react-day-picker'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBAAkB,EAC7B,eACA,WACA,cACA,WAAW,OACX,mBAAmB,MACnB,cACA,YACA,OACA,QACA,sBAAsB,GACtB,sBAAsB,OACtB,UACA,iBAAiB,MACjB,QAAQ,WACR,YACA,kBACA,OACA,IACA,GAAG,YACsB;CACzB,MAAM,UAAU,eAAe,GAAG;CAClC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,cAAc,UAAU,WAAW,eAAe,iBAAiB;CACzE,MAAM,CAAC,MAAM,WAAW,qBAAuC;EAC7D;EACA;EACA;EACD,CAAC;CAGF,MAAM,qBAAqB,cAAc,kBAAkB,WAAW,EAAE,CAAC,WAAW,CAAC;CAGrF,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,mBAAmB,EAAE,CAAC,YAAY,mBAAmB,CAAC;CAE/H,MAAM,oBAAoB,iBAAmC;AAC3D,MAAI,CAAC,cAAc;AACjB,WAAQ,OAAU;AAClB;;AAIF,MAAI,KACF,cAAa,SAAS,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE;AAGjE,UAAQ,aAAa;;CAGvB,MAAM,mBAAmB,aACtB,YAA8B;AAC7B,UAAQ,QAAQ;IAElB,CAAC,QAAQ,CACV;CAED,MAAM,sBAAsB,WAAmB;CAM/C,MAAM,yBAAyB,YAA8B;AAC3D,UAAQ,QAAQ;;AAGlB,QACE,qBAAC,SAAD,aACE,qBAAC,OAAD;EAAK,WAAW,GAAG,UAAU,UAAU;EAAE,aAAU;EAAkB,eAAY;EAA2B,GAAI;YAAhH,CACE,oBAAC,sBAAD;GACE,oBAAkB;GAClB,gBAAc,UAAU;GACxB,WAAW,GAAG,yCAAyC,CAAC,QAAQ,sBAAsB;GACtF,eAAY;GACF;GACV,SACE,oBAAC,gBAAD;IAAgB;IAAkB;cAChC,oBAAC,cAAD;KACE,cAAW;KACX,WAAW,GAAG,4HAA4H,WAAW,sDAAsD,8CAA8C;KACzP,eAAY;KACF;KACV;IACa;GAEnB,YAAY;GACZ,IAAI;GACG;GACP,UAAU;GACV,UAAU;GACH;GACP,OAAO;GACP,GACF,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACA;GACrB,EACE;KAEN,qBAAC,gBAAD;EACE,OAAM;EACN,WAAW,GAAG,6BAA6B,CAAC,kBAAkB,aAAa,kBAAkB,wBAAwB,QAAQ,aAAa,kBAAkB,wBAAwB,QAAQ,YAAY;EACxM,eAAY;EACZ,kBAAkB,MAAM,EAAE,gBAAgB;YAJ5C,CAME,oBAAC,UAAD;GAAU,GAAI;GAAiC;GAA0B;GAAQ,MAAK;GAAS,UAAU;GAAkB,UAAU;GAAQ,GAC5I,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,YAAD;IAAkB;IAAM,YAAY;IAAqB,QAAQ;IAAoB,UAAU;IAAkB,gBAAgB;IAAoB,cAAc;IAAoB;GACnL,EAEO;IACT;;AAId,eAAe,cAAc"}
1
+ {"version":3,"file":"DateTimePicker.js","names":[],"sources":["../src/components/DateTimePicker/DateTimePicker.tsx"],"sourcesContent":["import { CalendarIcon } from '@components/Icons'\nimport { Popover, PopoverContent, PopoverTrigger } from '@components/Popover/Popover'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useMemo, type ComponentProps } from 'react'\nimport { type Locale } from 'react-day-picker'\nimport { Calendar, type CalendarProps } from './Calendar'\nimport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nimport { detectHourFormat, getResolvedLocale, type HourFormat, type Period, type TimePickerTranslations } from './DateTimeUtils'\nimport { TimePicker } from './TimePicker'\n\nexport interface DateTimePickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {\n calendarProps?: Omit<CalendarProps, 'mode' | 'selected' | 'onSelect' | 'disablePastDates' | 'locale'>\n defaultValue?: Date\n disabled?: boolean\n disablePastDates?: boolean\n errorMessage?: string | string[] | Record<string, unknown> | null\n hourFormat?: HourFormat\n inputClassName?: string\n label?: string\n locale?: Partial<Locale>\n messageReserveLines?: number\n messageReserveSpace?: boolean\n onChange?: (date: Date | undefined) => void\n showTimePicker?: boolean\n state?: 'default' | 'disabled' | 'error'\n timeLocale?: string\n /** Override translation strings for time picker ARIA labels */\n timeTranslations?: Partial<TimePickerTranslations>\n value?: Date\n}\n\nexport const DateTimePicker = ({\n calendarProps,\n className,\n defaultValue,\n disabled = false,\n disablePastDates = true,\n errorMessage,\n hourFormat,\n inputClassName,\n label,\n locale,\n messageReserveLines = 1,\n messageReserveSpace = false,\n onChange,\n showTimePicker = true,\n state = 'default',\n timeLocale,\n timeTranslations,\n value,\n id,\n ...props\n}: DateTimePickerProps) => {\n const fieldId = useFormFieldId(id)\n const errorMessageId = getErrorMessageId(fieldId)\n const describedBy = state === 'error' && errorMessage ? errorMessageId : undefined\n const [date, setDate] = useUncontrolledState<Date | undefined>({\n defaultValue,\n onChange,\n value,\n })\n\n // Resolve time locale with fallback chain\n const resolvedTimeLocale = useMemo(() => getResolvedLocale(timeLocale), [timeLocale])\n\n // Auto-detect hour format from locale if not explicitly provided\n const effectiveHourFormat = useMemo(() => hourFormat ?? detectHourFormat(resolvedTimeLocale), [hourFormat, resolvedTimeLocale])\n\n const handleDateSelect = (selectedDate: Date | undefined) => {\n if (!selectedDate) {\n setDate(undefined)\n return\n }\n\n // Preserve the time from the existing date\n if (date) {\n selectedDate.setHours(date.getHours(), date.getMinutes(), 0, 0)\n }\n\n setDate(selectedDate)\n }\n\n const handleTimeChange = useCallback(\n (newDate: Date | undefined) => {\n setDate(newDate)\n },\n [setDate],\n )\n\n const handlePeriodChange = (period: Period) => {\n // Period change is already handled in TimePicker\n // This callback is for external consumers who want to react to period changes\n void period\n }\n\n const handleInputDateChange = (newDate: Date | undefined) => {\n setDate(newDate)\n }\n\n return (\n <Popover>\n <div className={cn('w-full', className)} data-slot='datetime-picker' data-testid='spectral-datetime-picker' {...props}>\n <DateTimeDisplayInput\n aria-describedby={describedBy}\n aria-invalid={state === 'error'}\n className={cn('gap-4 pr-12 flex w-full justify-start', !date && 'text-text-secondary', inputClassName)}\n data-testid='spectral-datetime-picker-input'\n disabled={disabled}\n endIcon={\n <PopoverTrigger asChild disabled={disabled}>\n <CalendarIcon\n aria-label='Open date picker'\n className={cn('right-4 text-input-icon hover:text-input-icon--hover absolute top-1/2 -translate-y-1/2 cursor-pointer focus:outline-none', disabled ? 'pointer-events-none cursor-not-allowed opacity-50' : 'hover:text-input-icon--hover cursor-pointer')}\n data-testid='spectral-datetime-picker-trigger'\n disabled={disabled}\n />\n </PopoverTrigger>\n }\n hourFormat={effectiveHourFormat}\n id={fieldId}\n label={label}\n onChange={handleInputDateChange}\n showTime={showTimePicker}\n state={state}\n value={date}\n />\n <ErrorMessage\n dataTestId='spectral-datetime-picker-error-message'\n id={errorMessageId}\n message={state === 'error' ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n\n <PopoverContent\n align='start'\n className={cn('rounded-lg py-4 px-6 flex', !showTimePicker && 'w-[330px]', showTimePicker && effectiveHourFormat === '24' && 'w-[486px]', showTimePicker && effectiveHourFormat === '12' && 'w-[560px]')}\n data-testid='spectral-datetime-picker-popover'\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar {...calendarProps} disablePastDates={disablePastDates} locale={locale} mode='single' onSelect={handleDateSelect} selected={date} />\n {showTimePicker && (\n <div className='pl-6 border-l border-border-secondary'>\n <TimePicker date={date} hourFormat={effectiveHourFormat} locale={resolvedTimeLocale} onChange={handleTimeChange} onPeriodChange={handlePeriodChange} translations={timeTranslations} />\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n\nDateTimePicker.displayName = 'DateTimePicker'\n\n// Re-export sub-components for granular usage\nexport { Calendar } from './Calendar'\nexport { DateTimeDisplayInput } from './DateTimeDisplayInput'\nexport { DateTimeInput } from './DateTimeInput'\nexport { TimePeriodSelect } from './TimePeriodSelect'\nexport { TimePicker } from './TimePicker'\nexport * from './DateTimeUtils'\nexport { type Locale } from 'react-day-picker'\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiCA,MAAa,kBAAkB,EAC7B,eACA,WACA,cACA,WAAW,OACX,mBAAmB,MACnB,cACA,YACA,gBACA,OACA,QACA,sBAAsB,GACtB,sBAAsB,OACtB,UACA,iBAAiB,MACjB,QAAQ,WACR,YACA,kBACA,OACA,IACA,GAAG,YACsB;CACzB,MAAM,UAAU,eAAe,GAAG;CAClC,MAAM,iBAAiB,kBAAkB,QAAQ;CACjD,MAAM,cAAc,UAAU,WAAW,eAAe,iBAAiB;CACzE,MAAM,CAAC,MAAM,WAAW,qBAAuC;EAC7D;EACA;EACA;EACD,CAAC;CAGF,MAAM,qBAAqB,cAAc,kBAAkB,WAAW,EAAE,CAAC,WAAW,CAAC;CAGrF,MAAM,sBAAsB,cAAc,cAAc,iBAAiB,mBAAmB,EAAE,CAAC,YAAY,mBAAmB,CAAC;CAE/H,MAAM,oBAAoB,iBAAmC;AAC3D,MAAI,CAAC,cAAc;AACjB,WAAQ,OAAU;AAClB;;AAIF,MAAI,KACF,cAAa,SAAS,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,GAAG,EAAE;AAGjE,UAAQ,aAAa;;CAGvB,MAAM,mBAAmB,aACtB,YAA8B;AAC7B,UAAQ,QAAQ;IAElB,CAAC,QAAQ,CACV;CAED,MAAM,sBAAsB,WAAmB;CAM/C,MAAM,yBAAyB,YAA8B;AAC3D,UAAQ,QAAQ;;AAGlB,QACE,qBAAC,SAAD,aACE,qBAAC,OAAD;EAAK,WAAW,GAAG,UAAU,UAAU;EAAE,aAAU;EAAkB,eAAY;EAA2B,GAAI;YAAhH,CACE,oBAAC,sBAAD;GACE,oBAAkB;GAClB,gBAAc,UAAU;GACxB,WAAW,GAAG,yCAAyC,CAAC,QAAQ,uBAAuB,eAAe;GACtG,eAAY;GACF;GACV,SACE,oBAAC,gBAAD;IAAgB;IAAkB;cAChC,oBAAC,cAAD;KACE,cAAW;KACX,WAAW,GAAG,4HAA4H,WAAW,sDAAsD,8CAA8C;KACzP,eAAY;KACF;KACV;IACa;GAEnB,YAAY;GACZ,IAAI;GACG;GACP,UAAU;GACV,UAAU;GACH;GACP,OAAO;GACP,GACF,oBAAC,cAAD;GACE,YAAW;GACX,IAAI;GACJ,SAAS,UAAU,UAAU,eAAe;GACvB;GACA;GACrB,EACE;KAEN,qBAAC,gBAAD;EACE,OAAM;EACN,WAAW,GAAG,6BAA6B,CAAC,kBAAkB,aAAa,kBAAkB,wBAAwB,QAAQ,aAAa,kBAAkB,wBAAwB,QAAQ,YAAY;EACxM,eAAY;EACZ,kBAAkB,MAAM,EAAE,gBAAgB;YAJ5C,CAME,oBAAC,UAAD;GAAU,GAAI;GAAiC;GAA0B;GAAQ,MAAK;GAAS,UAAU;GAAkB,UAAU;GAAQ,GAC5I,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,YAAD;IAAkB;IAAM,YAAY;IAAqB,QAAQ;IAAoB,UAAU;IAAkB,gBAAgB;IAAoB,cAAc;IAAoB;GACnL,EAEO;IACT;;AAId,eAAe,cAAc"}
package/dist/Dialog.d.ts CHANGED
@@ -51,10 +51,12 @@ declare const DialogFooter: ({
51
51
  ...props
52
52
  }: ComponentProps<'div'>) => _$react_jsx_runtime0.JSX.Element;
53
53
  declare const DialogTitle: ({
54
+ children,
54
55
  className,
55
56
  ...props
56
57
  }: ComponentProps<typeof DialogPrimitive.Title>) => _$react_jsx_runtime0.JSX.Element;
57
58
  declare const DialogDescription: ({
59
+ children,
58
60
  className,
59
61
  ...props
60
62
  }: ComponentProps<typeof DialogPrimitive.Description>) => _$react_jsx_runtime0.JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI3E,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIpF,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAmCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI9D,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIpF,iBAAA;EAAiB,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Dialog.d.ts","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"mappings":";;;;;;cAMM,MAAA;EAAM,MAAA;EAAA,KAAA;EAAA,GAAA;AAAA,GAIT,IAAA,CAAK,cAAA,QAAsB,eAAA,CAAgB,IAAA;EAC5C,MAAA;EACA,aAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIK,aAAA;EAAA,GAAa;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI7E,YAAA;EAAA,GAAY;AAAA,GAAkB,cAAA,QAAsB,eAAA,CAAgB,MAAA,MAAO,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI3E,WAAA;EAAW,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAIpF,aAAA;EAAa,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,QAAsB,eAAA,CAAgB,OAAA,MAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAYxF,aAAA;EAAa,QAAA;EAAA,SAAA;EAAA,aAAA;EAAA,eAAA;EAAA,iBAAA;EAAA,oBAAA;EAAA,eAAA;EAAA,GAAA;AAAA,GAShB,cAAA,QAAsB,eAAA,CAAgB,OAAA;EACvC,aAAA;EACA,eAAA,IAAmB,KAAA,EAAO,aAAA;EAC1B,iBAAA,IAAqB,KAAA,EAAO,YAAA,GAAe,UAAA;EAC3C,oBAAA,IAAwB,KAAA,EAAO,YAAA;EAC/B,eAAA;AAAA,MACD,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAmCK,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAI9D,YAAA;EAAY,SAAA;EAAA,GAAA;AAAA,GAA6B,cAAA,YAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAM9D,WAAA;EAAW,QAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAAuC,cAAA,QAAsB,eAAA,CAAgB,KAAA,MAAM,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAY9F,iBAAA;EAAiB,QAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAAuC,cAAA,QAAsB,eAAA,CAAgB,WAAA,MAAY,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Dialog.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { CloseIcon } from "./Icons/CloseIcon.js";
3
3
  import { cn } from "./utils/twUtils.js";
4
- import "react";
4
+ import { isValidElement } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import * as DialogPrimitive from "@radix-ui/react-dialog";
7
7
  import { RemoveScroll } from "react-remove-scroll";
@@ -87,20 +87,51 @@ const DialogFooter = ({ className, ...props }) => {
87
87
  ...props
88
88
  });
89
89
  };
90
- const DialogTitle = ({ className, ...props }) => {
91
- return /* @__PURE__ */ jsx(DialogPrimitive.Title, {
90
+ const hasTextContent = (value) => typeof value === "string" ? value.trim().length > 0 : typeof value === "number";
91
+ const DialogTitle = ({ children, className, ...props }) => {
92
+ if (hasTextContent(children)) return /* @__PURE__ */ jsx(DialogPrimitive.Title, {
92
93
  className: cn("text-2xl font-semibold leading-none", className),
93
94
  "data-slot": "dialog-title",
94
95
  "data-testid": "spectral-dialog-title",
95
- ...props
96
+ ...props,
97
+ children
98
+ });
99
+ if (isValidElement(children)) return /* @__PURE__ */ jsx(DialogPrimitive.Title, {
100
+ asChild: true,
101
+ "data-slot": "dialog-title",
102
+ "data-testid": "spectral-dialog-title",
103
+ ...props,
104
+ children
105
+ });
106
+ return /* @__PURE__ */ jsx(DialogPrimitive.Title, {
107
+ className,
108
+ "data-slot": "dialog-title",
109
+ "data-testid": "spectral-dialog-title",
110
+ ...props,
111
+ children
96
112
  });
97
113
  };
98
- const DialogDescription = ({ className, ...props }) => {
99
- return /* @__PURE__ */ jsx(DialogPrimitive.Description, {
114
+ const DialogDescription = ({ children, className, ...props }) => {
115
+ if (hasTextContent(children)) return /* @__PURE__ */ jsx(DialogPrimitive.Description, {
100
116
  className: cn("text-muted-foreground text-sm", className),
101
117
  "data-slot": "dialog-description",
102
118
  "data-testid": "spectral-dialog-description",
103
- ...props
119
+ ...props,
120
+ children
121
+ });
122
+ if (isValidElement(children)) return /* @__PURE__ */ jsx(DialogPrimitive.Description, {
123
+ asChild: true,
124
+ "data-slot": "dialog-description",
125
+ "data-testid": "spectral-dialog-description",
126
+ ...props,
127
+ children
128
+ });
129
+ return /* @__PURE__ */ jsx(DialogPrimitive.Description, {
130
+ className,
131
+ "data-slot": "dialog-description",
132
+ "data-testid": "spectral-dialog-description",
133
+ ...props,
134
+ children
104
135
  });
105
136
  };
106
137
 
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return <DialogPrimitive.Root open={isOpen} modal={modal} data-slot='dialog' data-testid='spectral-dialog' {...props} />\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return <DialogPrimitive.Trigger asChild data-testid='spectral-dialog-trigger' {...props} />\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return <DialogPrimitive.Portal data-slot='dialog-portal' data-testid='dialog-portal' {...props} />\n}\n\nconst DialogClose = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return <DialogPrimitive.Close asChild data-slot='dialog-close' data-testid='spectral-dialog-close' {...props} className={cn('hover:cursor-pointer', className)} />\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:animate-out',\n 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal data-slot='dialog-portal' data-testid='spectral-dialog-portal'>\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent data-[state=open]:text-text-primary top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:opacity-100 hover:cursor-pointer disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={18} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:text-left flex flex-col text-center', className)} data-slot='dialog-header' data-testid='spectral-dialog-header' {...props} />\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)} data-slot='dialog-footer' data-testid='spectral-dialog-footer' {...props} />\n}\n\nconst DialogTitle = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n return <DialogPrimitive.Title className={cn('text-2xl font-semibold leading-none', className)} data-slot='dialog-title' data-testid='spectral-dialog-title' {...props} />\n}\n\nconst DialogDescription = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n return <DialogPrimitive.Description className={cn('text-muted-foreground text-sm', className)} data-slot='dialog-description' data-testid='spectral-dialog-description' {...props} />\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":";;;;;;;;;AAMA,MAAM,UAAU,EACd,QACA,QAAQ,OACR,GAAG,YAIC;AACJ,QAAO,oBAAC,gBAAgB,MAAjB;EAAsB,MAAM;EAAe;EAAO,aAAU;EAAS,eAAY;EAAkB,GAAI;EAAS;;AAGzH,MAAM,iBAAiB,EAAE,GAAG,YAA4D;AACtF,QAAO,oBAAC,gBAAgB,SAAjB;EAAyB;EAAQ,eAAY;EAA0B,GAAI;EAAS;;AAG7F,MAAM,gBAAgB,EAAE,GAAG,YAA2D;AACpF,QAAO,oBAAC,gBAAgB,QAAjB;EAAwB,aAAU;EAAgB,eAAY;EAAgB,GAAI;EAAS;;AAGpG,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QAAO,oBAAC,gBAAgB,OAAjB;EAAuB;EAAQ,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAO,WAAW,GAAG,wBAAwB,UAAU;EAAI;;AAGpK,MAAM,iBAAiB,EAAE,WAAW,GAAG,YAA4D;AACjG,QACE,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,gLACd,8CAA8C,UAAU;EACxD,aAAU;EACV,eAAY;EACZ,GAAI;EACJ;;AAIN,MAAM,iBAAiB,EACrB,UACA,WACA,gBAAgB,MAChB,iBACA,mBACA,sBACA,kBAAkB,MAClB,GAAG,YAOC;AACJ,QACE,qBAAC,cAAD;EAAc,aAAU;EAAgB,eAAY;YAApD,CACG,iBAAiB,oBAAC,eAAD,EAAiB,GACnC,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,oOACA,wLACA,sIACA,aAAa,WAAW,WACxB,UACD;GACD,aAAU;GACV,eAAY;GACK;GACE;GACG;GACtB,GAAI;aAbN,CAeG,UACA,mBACC,qBAAC,gBAAgB,OAAjB;IACE,WAAW;IACX,aAAU;IACV,eAAY;cAHd,CAKE,oBAAC,WAAD,EAAW,MAAM,IAAM,GACvB,oBAAC,QAAD;KAAM,WAAU;eAAU;KAAmB,EACvB;MAEF;KACb;;;AAInB,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,gDAAgD,UAAU;EAAE,aAAU;EAAgB,eAAY;EAAyB,GAAI;EAAS;;AAGpK,MAAM,gBAAgB,EAAE,WAAW,GAAG,YAAmC;AACvE,QAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,+GAA+G,UAAU;EAAE,aAAU;EAAgB,eAAY;EAAyB,GAAI;EAAS;;AAGnO,MAAM,eAAe,EAAE,WAAW,GAAG,YAA0D;AAC7F,QAAO,oBAAC,gBAAgB,OAAjB;EAAuB,WAAW,GAAG,uCAAuC,UAAU;EAAE,aAAU;EAAe,eAAY;EAAwB,GAAI;EAAS;;AAG3K,MAAM,qBAAqB,EAAE,WAAW,GAAG,YAAgE;AACzG,QAAO,oBAAC,gBAAgB,aAAjB;EAA6B,WAAW,GAAG,iCAAiC,UAAU;EAAE,aAAU;EAAqB,eAAY;EAA8B,GAAI;EAAS"}
1
+ {"version":3,"file":"Dialog.js","names":[],"sources":["../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import { CloseIcon } from '@components/Icons/CloseIcon'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { cn } from '@utils/twUtils'\nimport { isValidElement, type ComponentProps, type ReactNode } from 'react'\nimport { RemoveScroll } from 'react-remove-scroll'\n\nconst Dialog = ({\n isOpen,\n modal = false,\n ...props\n}: Omit<ComponentProps<typeof DialogPrimitive.Root>, 'open'> & {\n isOpen?: boolean\n dialogOverlay?: boolean\n}) => {\n return <DialogPrimitive.Root open={isOpen} modal={modal} data-slot='dialog' data-testid='spectral-dialog' {...props} />\n}\n\nconst DialogTrigger = ({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) => {\n return <DialogPrimitive.Trigger asChild data-testid='spectral-dialog-trigger' {...props} />\n}\n\nconst DialogPortal = ({ ...props }: ComponentProps<typeof DialogPrimitive.Portal>) => {\n return <DialogPrimitive.Portal data-slot='dialog-portal' data-testid='dialog-portal' {...props} />\n}\n\nconst DialogClose = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Close>) => {\n return <DialogPrimitive.Close asChild data-slot='dialog-close' data-testid='spectral-dialog-close' {...props} className={cn('hover:cursor-pointer', className)} />\n}\n\nconst DialogOverlay = ({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) => {\n return (\n <DialogPrimitive.Overlay\n className={cn('inset-0 bg-black/50 backdrop-blur-sm fixed z-50 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:animate-out',\n 'motion-safe:data-[state=closed]:fade-out-0', className)}\n data-slot='dialog-overlay'\n data-testid='spectral-dialog-overlay'\n {...props}\n />\n )\n}\n\nconst DialogContent = ({\n children,\n className,\n dialogOverlay = true,\n onEscapeKeyDown,\n onInteractOutside,\n onPointerDownOutside,\n showCloseButton = true,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n dialogOverlay?: boolean\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n onInteractOutside?: (event: PointerEvent | FocusEvent) => void\n onPointerDownOutside?: (event: PointerEvent) => void\n showCloseButton?: boolean\n}) => {\n return (\n <DialogPortal data-slot='dialog-portal' data-testid='spectral-dialog-portal'>\n {dialogOverlay && <DialogOverlay />}\n <DialogPrimitive.Content\n className={cn(\n 'max-w-xl gap-4 rounded-lg p-6 shadow-lg has-[[data-slot=dialog-footer]]:pb-0 fixed top-[50%] left-[50%] z-50 flex max-h-[90vh] w-full -translate-x-1/2 -translate-y-1/2 flex-col overflow-y-auto overscroll-contain bg-dialog-bg',\n 'motion-safe:data-[state=open]:duration-200 motion-safe:data-[state=open]:animate-in motion-safe:data-[state=open]:slide-in-from-bottom-20 motion-safe:data-[state=open]:zoom-in-100!',\n 'motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=closed]:zoom-out-95',\n RemoveScroll.classNames.fullWidth,\n className,\n )}\n data-slot='dialog-content'\n data-testid='spectral-dialog-content'\n onEscapeKeyDown={onEscapeKeyDown}\n onInteractOutside={onInteractOutside}\n onPointerDownOutside={onPointerDownOutside}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n className={`focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-accent data-[state=open]:text-text-primary top-4 right-4 rounded-xs absolute opacity-70 transition-opacity hover:opacity-100 hover:cursor-pointer disabled:pointer-events-none data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:shrink-0`}\n data-slot='dialog-close'\n data-testid='spectral-dialog-close'\n >\n <CloseIcon size={18} />\n <span className='sr-only'>Close dialog</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n )\n}\n\nconst DialogHeader = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:text-left flex flex-col text-center', className)} data-slot='dialog-header' data-testid='spectral-dialog-header' {...props} />\n}\n\nconst DialogFooter = ({ className, ...props }: ComponentProps<'div'>) => {\n return <div className={cn('gap-2 sm:flex-row sm:justify-end bottom-0 py-4 px-6 -mx-6 sticky z-10 flex flex-col-reverse bg-dialog-bg/85', className)} data-slot='dialog-footer' data-testid='spectral-dialog-footer' {...props} />\n}\n\nconst hasTextContent = (value: ReactNode) => (typeof value === 'string' ? value.trim().length > 0 : typeof value === 'number')\n\nconst DialogTitle = ({ children, className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) => {\n if (hasTextContent(children)) {\n return <DialogPrimitive.Title className={cn('text-2xl font-semibold leading-none', className)} data-slot='dialog-title' data-testid='spectral-dialog-title' {...props}>{children}</DialogPrimitive.Title>\n }\n\n if (isValidElement(children)) {\n return <DialogPrimitive.Title asChild data-slot='dialog-title' data-testid='spectral-dialog-title' {...props}>{children}</DialogPrimitive.Title>\n }\n\n return <DialogPrimitive.Title className={className} data-slot='dialog-title' data-testid='spectral-dialog-title' {...props}>{children}</DialogPrimitive.Title>\n}\n\nconst DialogDescription = ({ children, className, ...props }: ComponentProps<typeof DialogPrimitive.Description>) => {\n if (hasTextContent(children)) {\n return <DialogPrimitive.Description className={cn('text-muted-foreground text-sm', className)} data-slot='dialog-description' data-testid='spectral-dialog-description' {...props}>{children}</DialogPrimitive.Description>\n }\n\n if (isValidElement(children)) {\n return <DialogPrimitive.Description asChild data-slot='dialog-description' data-testid='spectral-dialog-description' {...props}>{children}</DialogPrimitive.Description>\n }\n\n return <DialogPrimitive.Description className={className} data-slot='dialog-description' data-testid='spectral-dialog-description' {...props}>{children}</DialogPrimitive.Description>\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger }\n"],"mappings":"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"}
package/dist/Drawer.d.ts CHANGED
@@ -7,14 +7,15 @@ interface DrawerProps {
7
7
  className?: string;
8
8
  children?: ReactNode;
9
9
  defaultOpen?: boolean;
10
- description?: string;
10
+ description?: ReactNode;
11
11
  direction?: 'left' | 'right' | 'top' | 'bottom';
12
12
  dismissible?: boolean;
13
+ dragBehavior?: 'surface' | 'handle' | 'none';
13
14
  modal?: boolean;
14
15
  onOpenChange?: (open: boolean) => void;
15
16
  open?: boolean;
16
17
  size?: string;
17
- title?: string;
18
+ title?: ReactNode;
18
19
  trigger: ReactNode;
19
20
  }
20
21
  declare const Drawer: ({
@@ -24,6 +25,7 @@ declare const Drawer: ({
24
25
  description,
25
26
  direction,
26
27
  dismissible,
28
+ dragBehavior,
27
29
  modal,
28
30
  onOpenChange,
29
31
  open,
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAKiB,WAAA;EACf,SAAA;EACA,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,SAAA;AAAA;AAAA,cAGE,MAAA;EAAM,QAAA;EAAA,SAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAA0K,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Drawer.d.ts","names":[],"sources":["../src/components/Drawer/Drawer.tsx"],"mappings":";;;;;UAKiB,WAAA;EACf,SAAA;EACA,QAAA,GAAW,SAAA;EACX,WAAA;EACA,WAAA,GAAc,SAAA;EACd,SAAA;EACA,WAAA;EACA,YAAA;EACA,KAAA;EACA,YAAA,IAAgB,IAAA;EAChB,IAAA;EACA,IAAA;EACA,KAAA,GAAQ,SAAA;EACR,OAAA,EAAS,SAAA;AAAA;AAAA,cAmBE,MAAA;EAAM,QAAA;EAAA,SAAA;EAAA,WAAA;EAAA,WAAA;EAAA,SAAA;EAAA,WAAA;EAAA,YAAA;EAAA,KAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA,KAAA;EAAA;AAAA,GAahB,WAAA,KAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/Drawer.js CHANGED
@@ -1,15 +1,28 @@
1
1
  'use client';
2
2
  import { cn } from "./utils/twUtils.js";
3
3
  import { SpectralProvider } from "./components/SpectralProvider/SpectralProvider.js";
4
- import "react";
5
- import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Fragment, isValidElement } from "react";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Drawer as Drawer$1 } from "vaul";
7
7
 
8
8
  //#region src/components/Drawer/Drawer.tsx
9
- const Drawer = ({ children, className, defaultOpen = false, description, direction = "right", dismissible = true, modal = true, onOpenChange, open, size = "380px", title, trigger }) => {
9
+ const hasRenderableText = (value) => typeof value === "string" ? value.trim().length > 0 : typeof value === "number";
10
+ const hasRenderableContent = (value) => {
11
+ if (hasRenderableText(value)) return true;
12
+ if (value === null || value === void 0 || typeof value === "boolean" || typeof value === "string") return false;
13
+ return true;
14
+ };
15
+ const isElementAndNotFragment = (element) => isValidElement(element) && element.type !== Fragment;
16
+ const Drawer = ({ children, className, defaultOpen = false, description, direction = "right", dismissible = true, dragBehavior = "surface", modal = true, onOpenChange, open, size = "380px", title, trigger }) => {
10
17
  const baseStyles = "font-sans! fixed";
11
- const hasTitle = typeof title === "string" && title.trim().length > 0;
12
- const hasDescription = typeof description === "string" && description.trim().length > 0;
18
+ const hasTitle = hasRenderableContent(title);
19
+ const hasDescription = hasRenderableContent(description);
20
+ const isTextTitle = hasRenderableText(title);
21
+ const isTextDescription = hasRenderableText(description);
22
+ const isCustomTitleElement = isElementAndNotFragment(title);
23
+ const isCustomDescriptionElement = isElementAndNotFragment(description);
24
+ const handleOnly = dragBehavior === "handle" || dragBehavior === "none";
25
+ const shouldRenderHandle = dragBehavior === "handle";
13
26
  const { className: directionClassName, style } = {
14
27
  left: {
15
28
  className: cn(baseStyles, "top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]"),
@@ -33,6 +46,7 @@ const Drawer = ({ children, className, defaultOpen = false, description, directi
33
46
  defaultOpen,
34
47
  direction,
35
48
  dismissible,
49
+ handleOnly,
36
50
  modal,
37
51
  onOpenChange,
38
52
  open,
@@ -53,16 +67,39 @@ const Drawer = ({ children, className, defaultOpen = false, description, directi
53
67
  className: "flex h-full min-h-0 flex-col",
54
68
  children: [
55
69
  /* @__PURE__ */ jsx(Drawer$1.Close, {}),
56
- hasTitle && /* @__PURE__ */ jsx(Drawer$1.Title, {
57
- className: "px-3 pt-4 text-lg font-medium text-text-primary",
58
- "data-testid": "spectral-drawer-title",
59
- children: title
60
- }),
61
- hasDescription && /* @__PURE__ */ jsx(Drawer$1.Description, {
62
- className: "mb-2 px-3 text-xs! text-text-secondary! uppercase",
63
- "data-testid": "spectral-drawer-description",
64
- children: description
65
- }),
70
+ shouldRenderHandle && /* @__PURE__ */ jsx(Drawer$1.Handle, { "data-testid": "spectral-drawer-handle" }),
71
+ hasTitle && /* @__PURE__ */ jsxs(Fragment$1, { children: [
72
+ isTextTitle && /* @__PURE__ */ jsx(Drawer$1.Title, {
73
+ className: "px-3 pt-4 text-xl font-semibold text-text-primary",
74
+ "data-testid": "spectral-drawer-title",
75
+ children: title
76
+ }),
77
+ !isTextTitle && isCustomTitleElement && /* @__PURE__ */ jsx(Drawer$1.Title, {
78
+ asChild: true,
79
+ "data-testid": "spectral-drawer-title",
80
+ children: title
81
+ }),
82
+ !isTextTitle && !isCustomTitleElement && /* @__PURE__ */ jsx(Drawer$1.Title, {
83
+ "data-testid": "spectral-drawer-title",
84
+ children: title
85
+ })
86
+ ] }),
87
+ hasDescription && /* @__PURE__ */ jsxs(Fragment$1, { children: [
88
+ isTextDescription && /* @__PURE__ */ jsx(Drawer$1.Description, {
89
+ className: "mb-2 px-3 text-xs! text-text-secondary! uppercase",
90
+ "data-testid": "spectral-drawer-description",
91
+ children: description
92
+ }),
93
+ !isTextDescription && isCustomDescriptionElement && /* @__PURE__ */ jsx(Drawer$1.Description, {
94
+ asChild: true,
95
+ "data-testid": "spectral-drawer-description",
96
+ children: description
97
+ }),
98
+ !isTextDescription && !isCustomDescriptionElement && /* @__PURE__ */ jsx(Drawer$1.Description, {
99
+ "data-testid": "spectral-drawer-description",
100
+ children: description
101
+ })
102
+ ] }),
66
103
  /* @__PURE__ */ jsx("div", {
67
104
  className: "py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 flex-1 min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain *:box-border",
68
105
  "data-testid": "spectral-drawer-body",
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { cn } from '@utils/twUtils'\nimport { type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n className?: string\n children?: ReactNode\n defaultOpen?: boolean\n description?: string\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: string\n trigger: ReactNode\n}\n\nexport const Drawer = ({ children, className, defaultOpen = false, description, direction = 'right', dismissible = true, modal = true, onOpenChange, open, size = '380px', title, trigger }: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = typeof title === 'string' && title.trim().length > 0\n const hasDescription = typeof description === 'string' && description.trim().length > 0\n\n const directionStyles = {\n left: {\n className: cn(baseStyles, 'top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n right: {\n className: cn(baseStyles, 'top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n top: {\n className: cn(baseStyles, 'top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n bottom: {\n className: cn(baseStyles, 'bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n }\n\n const { className: directionClassName, style } = directionStyles[direction]\n\n return (\n <SpectralProvider>\n <DrawerBase.Root data-testid='spectral-drawer' defaultOpen={defaultOpen} direction={direction} dismissible={dismissible} modal={modal} onOpenChange={onOpenChange} open={open}>\n <DrawerBase.Trigger asChild data-testid='spectral-drawer-trigger'>\n {trigger}\n </DrawerBase.Trigger>\n <DrawerBase.Portal>\n <DrawerBase.Overlay className='inset-0 fixed bg-transparent' data-testid='spectral-drawer-overlay' />\n <DrawerBase.Content\n asChild\n aria-label={!hasTitle && !hasDescription ? 'Drawer' : undefined}\n className={cn(\n 'z-10 flex flex-col overscroll-contain bg-drawer-bg focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent **:box-border',\n directionClassName,\n className,\n )}\n style={style}\n data-testid='spectral-drawer-content'\n >\n <div className='flex h-full min-h-0 flex-col'>\n <DrawerBase.Close />\n {hasTitle && (\n <DrawerBase.Title className='px-3 pt-4 text-lg font-medium text-text-primary' data-testid='spectral-drawer-title'>\n {title}\n </DrawerBase.Title>\n )}\n {hasDescription && (\n <DrawerBase.Description className='mb-2 px-3 text-xs! text-text-secondary! uppercase' data-testid='spectral-drawer-description'>\n {description}\n </DrawerBase.Description>\n )}\n <div className='py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 flex-1 min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain *:box-border' data-testid='spectral-drawer-body'>\n {children}\n </div>\n </div>\n </DrawerBase.Content>\n </DrawerBase.Portal>\n </DrawerBase.Root>\n </SpectralProvider>\n )\n}\n"],"mappings":";;;;;;;;AAoBA,MAAa,UAAU,EAAE,UAAU,WAAW,cAAc,OAAO,aAAa,YAAY,SAAS,cAAc,MAAM,QAAQ,MAAM,cAAc,MAAM,OAAO,SAAS,OAAO,cAA2B;CAC3M,MAAM,aAAa;CACnB,MAAM,WAAW,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS;CACpE,MAAM,iBAAiB,OAAO,gBAAgB,YAAY,YAAY,MAAM,CAAC,SAAS;CAqBtF,MAAM,EAAE,WAAW,oBAAoB,UAAU;EAlB/C,MAAM;GACJ,WAAW,GAAG,YAAY,mEAAmE;GAC7F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,OAAO;GACL,WAAW,GAAG,YAAY,qEAAqE;GAC/F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,KAAK;GACH,WAAW,GAAG,YAAY,kEAAkE;GAC5F,OAAO,EAAE,QAAQ,MAAM;GACxB;EACD,QAAQ;GACN,WAAW,GAAG,YAAY,sEAAsE;GAChG,OAAO,EAAE,QAAQ,MAAM;GACxB;EAG6D,CAAC;AAEjE,QACE,oBAAC,kBAAD,YACE,qBAACA,SAAW,MAAZ;EAAiB,eAAY;EAA+B;EAAwB;EAAwB;EAAoB;EAAqB;EAAoB;YAAzK,CACE,oBAACA,SAAW,SAAZ;GAAoB;GAAQ,eAAY;aACrC;GACkB,GACrB,qBAACA,SAAW,QAAZ,aACE,oBAACA,SAAW,SAAZ;GAAoB,WAAU;GAA+B,eAAY;GAA4B,GACrG,oBAACA,SAAW,SAAZ;GACE;GACA,cAAY,CAAC,YAAY,CAAC,iBAAiB,WAAW;GACtD,WAAW,GACT,2KACA,oBACA,UACD;GACM;GACP,eAAY;aAEZ,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,SAAW,OAAZ,EAAoB;KACnB,YACC,oBAACA,SAAW,OAAZ;MAAkB,WAAU;MAAkD,eAAY;gBACvF;MACgB;KAEpB,kBACC,oBAACA,SAAW,aAAZ;MAAwB,WAAU;MAAoD,eAAY;gBAC/F;MACsB;KAE3B,oBAAC,OAAD;MAAK,WAAU;MAAiI,eAAY;MACzJ;MACG;KACF;;GACa,EACH,IACJ;KACD"}
1
+ {"version":3,"file":"Drawer.js","names":["DrawerBase"],"sources":["../src/components/Drawer/Drawer.tsx"],"sourcesContent":["import { SpectralProvider } from '@components/SpectralProvider/SpectralProvider'\nimport { cn } from '@utils/twUtils'\nimport { Fragment, isValidElement, type ReactNode } from 'react'\nimport { Drawer as DrawerBase } from 'vaul'\n\nexport interface DrawerProps {\n className?: string\n children?: ReactNode\n defaultOpen?: boolean\n description?: ReactNode\n direction?: 'left' | 'right' | 'top' | 'bottom'\n dismissible?: boolean\n dragBehavior?: 'surface' | 'handle' | 'none'\n modal?: boolean\n onOpenChange?: (open: boolean) => void\n open?: boolean\n size?: string\n title?: ReactNode\n trigger: ReactNode\n}\n\nconst hasRenderableText = (value: ReactNode) => (typeof value === 'string' ? value.trim().length > 0 : typeof value === 'number')\n\nconst hasRenderableContent = (value: ReactNode) => {\n if (hasRenderableText(value)) {\n return true\n }\n\n if (value === null || value === undefined || typeof value === 'boolean' || typeof value === 'string') {\n return false\n }\n\n return true\n}\n\nconst isElementAndNotFragment = (element: ReactNode) => isValidElement(element) && element.type !== Fragment\n\nexport const Drawer = ({\n children,\n className,\n defaultOpen = false,\n description, direction = 'right',\n dismissible = true,\n dragBehavior = 'surface',\n modal = true,\n onOpenChange,\n open,\n size = '380px',\n title,\n trigger,\n}: DrawerProps) => {\n const baseStyles = 'font-sans! fixed'\n const hasTitle = hasRenderableContent(title)\n const hasDescription = hasRenderableContent(description)\n const isTextTitle = hasRenderableText(title)\n const isTextDescription = hasRenderableText(description)\n const isCustomTitleElement = isElementAndNotFragment(title)\n const isCustomDescriptionElement = isElementAndNotFragment(description)\n const handleOnly = dragBehavior === 'handle' || dragBehavior === 'none'\n const shouldRenderHandle = dragBehavior === 'handle'\n\n const directionStyles = {\n left: {\n className: cn(baseStyles, 'top-0 bottom-0 left-0 shadow-[20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n right: {\n className: cn(baseStyles, 'top-0 bottom-0 right-0 shadow-[-20px_0_20px_var(--color-black-40)]'),\n style: { width: size },\n },\n top: {\n className: cn(baseStyles, 'top-0 left-0 right-0 shadow-[0_20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n bottom: {\n className: cn(baseStyles, 'bottom-0 left-0 right-0 shadow-[0_-20px_20px_var(--color-black-40)]'),\n style: { height: size },\n },\n }\n\n const { className: directionClassName, style } = directionStyles[direction]\n\n return (\n <SpectralProvider>\n <DrawerBase.Root data-testid='spectral-drawer' defaultOpen={defaultOpen} direction={direction} dismissible={dismissible} handleOnly={handleOnly} modal={modal} onOpenChange={onOpenChange} open={open}>\n <DrawerBase.Trigger asChild data-testid='spectral-drawer-trigger'>\n {trigger}\n </DrawerBase.Trigger>\n <DrawerBase.Portal>\n <DrawerBase.Overlay className='inset-0 fixed bg-transparent' data-testid='spectral-drawer-overlay' />\n <DrawerBase.Content\n asChild\n aria-label={!hasTitle && !hasDescription ? 'Drawer' : undefined}\n className={cn(\n 'z-10 flex flex-col overscroll-contain bg-drawer-bg focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent **:box-border',\n directionClassName,\n className,\n )}\n style={style}\n data-testid='spectral-drawer-content'\n >\n <div className='flex h-full min-h-0 flex-col'>\n <DrawerBase.Close />\n {shouldRenderHandle && <DrawerBase.Handle data-testid='spectral-drawer-handle' />}\n {hasTitle && (\n <>\n {isTextTitle && (\n <DrawerBase.Title className='px-3 pt-4 text-xl font-semibold text-text-primary' data-testid='spectral-drawer-title'>\n {title}\n </DrawerBase.Title>\n )}\n {!isTextTitle && isCustomTitleElement && (\n <DrawerBase.Title asChild data-testid='spectral-drawer-title'>\n {title}\n </DrawerBase.Title>\n )}\n {!isTextTitle && !isCustomTitleElement && (\n <DrawerBase.Title data-testid='spectral-drawer-title'>\n {title}\n </DrawerBase.Title>\n )}\n </>\n )}\n {hasDescription && (\n <>\n {isTextDescription && (\n <DrawerBase.Description className='mb-2 px-3 text-xs! text-text-secondary! uppercase' data-testid='spectral-drawer-description'>\n {description}\n </DrawerBase.Description>\n )}\n {!isTextDescription && isCustomDescriptionElement && (\n <DrawerBase.Description asChild data-testid='spectral-drawer-description'>\n {description}\n </DrawerBase.Description>\n )}\n {!isTextDescription && !isCustomDescriptionElement && (\n <DrawerBase.Description data-testid='spectral-drawer-description'>\n {description}\n </DrawerBase.Description>\n )}\n </>\n )}\n <div className='py-2 px-3 min-w-0 [&>*]:min-w-0 [&_*]:min-w-0 flex-1 min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain *:box-border' data-testid='spectral-drawer-body'>\n {children}\n </div>\n </div>\n </DrawerBase.Content>\n </DrawerBase.Portal>\n </DrawerBase.Root>\n </SpectralProvider>\n )\n}\n"],"mappings":";;;;;;;;AAqBA,MAAM,qBAAqB,UAAsB,OAAO,UAAU,WAAW,MAAM,MAAM,CAAC,SAAS,IAAI,OAAO,UAAU;AAExH,MAAM,wBAAwB,UAAqB;AACjD,KAAI,kBAAkB,MAAM,CAC1B,QAAO;AAGT,KAAI,UAAU,QAAQ,UAAU,UAAa,OAAO,UAAU,aAAa,OAAO,UAAU,SAC1F,QAAO;AAGT,QAAO;;AAGT,MAAM,2BAA2B,YAAuB,eAAe,QAAQ,IAAI,QAAQ,SAAS;AAEpG,MAAa,UAAU,EACrB,UACA,WACA,cAAc,OACd,aAAa,YAAY,SACzB,cAAc,MACd,eAAe,WACf,QAAQ,MACR,cACA,MACA,OAAO,SACP,OACA,cACiB;CACjB,MAAM,aAAa;CACnB,MAAM,WAAW,qBAAqB,MAAM;CAC5C,MAAM,iBAAiB,qBAAqB,YAAY;CACxD,MAAM,cAAc,kBAAkB,MAAM;CAC5C,MAAM,oBAAoB,kBAAkB,YAAY;CACxD,MAAM,uBAAuB,wBAAwB,MAAM;CAC3D,MAAM,6BAA6B,wBAAwB,YAAY;CACvE,MAAM,aAAa,iBAAiB,YAAY,iBAAiB;CACjE,MAAM,qBAAqB,iBAAiB;CAqB5C,MAAM,EAAE,WAAW,oBAAoB,UAAU;EAlB/C,MAAM;GACJ,WAAW,GAAG,YAAY,mEAAmE;GAC7F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,OAAO;GACL,WAAW,GAAG,YAAY,qEAAqE;GAC/F,OAAO,EAAE,OAAO,MAAM;GACvB;EACD,KAAK;GACH,WAAW,GAAG,YAAY,kEAAkE;GAC5F,OAAO,EAAE,QAAQ,MAAM;GACxB;EACD,QAAQ;GACN,WAAW,GAAG,YAAY,sEAAsE;GAChG,OAAO,EAAE,QAAQ,MAAM;GACxB;EAG6D,CAAC;AAEjE,QACE,oBAAC,kBAAD,YACE,qBAACA,SAAW,MAAZ;EAAiB,eAAY;EAA+B;EAAwB;EAAwB;EAAyB;EAAmB;EAAqB;EAAoB;YAAjM,CACE,oBAACA,SAAW,SAAZ;GAAoB;GAAQ,eAAY;aACrC;GACkB,GACrB,qBAACA,SAAW,QAAZ,aACE,oBAACA,SAAW,SAAZ;GAAoB,WAAU;GAA+B,eAAY;GAA4B,GACrG,oBAACA,SAAW,SAAZ;GACE;GACA,cAAY,CAAC,YAAY,CAAC,iBAAiB,WAAW;GACtD,WAAW,GACT,2KACA,oBACA,UACD;GACM;GACP,eAAY;aAEZ,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAACA,SAAW,OAAZ,EAAoB;KACnB,sBAAsB,oBAACA,SAAW,QAAZ,EAAmB,eAAY,0BAA2B;KAChF,YACC;MACG,eACC,oBAACA,SAAW,OAAZ;OAAkB,WAAU;OAAoD,eAAY;iBACzF;OACgB;MAEpB,CAAC,eAAe,wBACf,oBAACA,SAAW,OAAZ;OAAkB;OAAQ,eAAY;iBACnC;OACgB;MAEpB,CAAC,eAAe,CAAC,wBAChB,oBAACA,SAAW,OAAZ;OAAkB,eAAY;iBAC3B;OACgB;MAEpB;KAEJ,kBACC;MACG,qBACC,oBAACA,SAAW,aAAZ;OAAwB,WAAU;OAAoD,eAAY;iBAC/F;OACsB;MAE1B,CAAC,qBAAqB,8BACrB,oBAACA,SAAW,aAAZ;OAAwB;OAAQ,eAAY;iBACzC;OACsB;MAE1B,CAAC,qBAAqB,CAAC,8BACtB,oBAACA,SAAW,aAAZ;OAAwB,eAAY;iBACjC;OACsB;MAE1B;KAEL,oBAAC,OAAD;MAAK,WAAU;MAAiI,eAAY;MACzJ;MACG;KACF;;GACa,EACH,IACJ;KACD"}
package/dist/InputOTP.js CHANGED
@@ -4,7 +4,7 @@ import { cn } from "./utils/twUtils.js";
4
4
  import { ErrorMessage } from "./FormFieldMessage.js";
5
5
  import { getErrorMessageId, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
6
6
  import { createContext, useContext } from "react";
7
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { OTPInput, REGEXP_ONLY_DIGITS } from "input-otp";
9
9
 
10
10
  //#region src/components/InputOTP/InputOTP.tsx
@@ -127,7 +127,7 @@ Slot.displayName = "InputOTP.Slot";
127
127
  const Slots = ({ start = 0, count, className }) => {
128
128
  const { maxLength = 0 } = useRoot();
129
129
  const end = count !== void 0 ? start + count : maxLength;
130
- return /* @__PURE__ */ jsx(Fragment, { children: Array.from({ length: end - start }, (_, i) => start + i).map((index) => /* @__PURE__ */ jsx(Slot, {
130
+ return /* @__PURE__ */ jsx(Fragment$1, { children: Array.from({ length: end - start }, (_, i) => start + i).map((index) => /* @__PURE__ */ jsx(Slot, {
131
131
  index,
132
132
  className
133
133
  }, index)) });
@@ -1 +1 @@
1
- {"version":3,"file":"InputOTP.js","names":[],"sources":["../src/components/InputOTP/InputOTP.tsx"],"sourcesContent":["import { MinusIcon } from '@components/Icons'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { OTPInput, REGEXP_ONLY_DIGITS, type OTPInputProps } from 'input-otp'\nimport { createContext, useContext, type ClipboardEvent, type ComponentPropsWithoutRef, type ComponentRef, type Ref } from 'react'\n\nexport interface InputOTPBaseProps extends Omit<OTPInputProps, 'textAlign' | 'pushPasswordManagerStrategy' | 'pasteTransformer' | 'noScriptCSSFallback' | 'placeholder' | 'containerClassName' | 'render' | 'pattern'> {\n onComplete?: (...args: unknown[]) => void\n className?: string\n errorMessage?: string | undefined\n inputMode?: 'numeric' | 'text' | 'decimal' | 'tel' | 'search' | 'email' | 'url'\n messageReserveLines?: number\n messageReserveSpace?: boolean\n /**\n * Regex pattern string to restrict allowed characters.\n * When `inputMode=\"numeric\"`, defaults to digits-only pattern.\n * Set to `undefined` to allow any characters.\n */\n pattern?: string | undefined\n separator?: boolean\n state?: FormFieldState\n variant?: 'outlined' | 'filled'\n}\n\nexport type InputOTPProps = InputOTPBaseProps & ({ value: number | string; onChange: (newValue: number | string) => void } | { value?: never; onChange?: never })\n\nconst InputOTPStateContext = createContext<{ isInvalid?: boolean }>({})\n\nconst OTPInputContext = createContext<{\n maxLength?: number\n slots?: { char: string | null; hasFakeCaret: boolean; isActive: boolean }[]\n variant?: 'outlined' | 'filled'\n} | null>(null)\n\nconst useRoot = () => {\n const context = useContext(OTPInputContext)\n if (!context) {\n throw new Error('useRoot must be used within an InputOTP')\n }\n return context\n}\n\nconst Root = ({\n autoFocus = false,\n children,\n className,\n errorMessage,\n id,\n inputMode = 'numeric',\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxLength,\n name,\n onChange,\n onComplete,\n pattern,\n ref,\n state = 'default',\n value,\n variant = 'outlined',\n ...props\n}: InputOTPProps & {\n ref?: Ref<ComponentRef<typeof OTPInput>>\n}) => {\n const inputId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(inputId)\n const { isInvalid } = useFormFieldState(false, state)\n\n // Apply digits-only pattern when inputMode is numeric (unless explicitly overridden)\n const effectivePattern = pattern ?? (inputMode === 'numeric' ? REGEXP_ONLY_DIGITS : undefined)\n\n const handlePaste = (e: ClipboardEvent<HTMLDivElement>): void => {\n let pasteData = e.clipboardData.getData('text/plain').trim().replaceAll('-', '')\n\n // Filter to digits only when in numeric mode\n if (inputMode === 'numeric') {\n pasteData = pasteData.replace(/\\D/g, '')\n }\n\n if (pasteData.length === maxLength && typeof onChange === 'function') {\n onChange(pasteData)\n }\n }\n\n return (\n <InputOTPStateContext.Provider value={{ isInvalid }}>\n <div className='gap-y-1 flex w-max flex-col'>\n <OTPInput\n /* eslint-disable-next-line jsx-a11y/no-autofocus -- intentional: consumers can opt in for OTP-first flows; defaults to false */\n autoFocus={autoFocus}\n containerClassName={cn('gap-2 flex items-center disabled:cursor-not-allowed has-[disabled]:opacity-50', className)}\n data-1p-ignore='true'\n data-dashlane-disabled-on-field='true'\n data-lpignore='true'\n data-protonpass-ignore='true'\n data-testid='spectral-input-otp'\n id={inputId}\n inputMode={inputMode}\n maxLength={maxLength}\n onChange={onChange}\n onComplete={onComplete}\n onPaste={handlePaste}\n pasteTransformer={(pasted) => pasted.replaceAll('-', '')}\n pattern={effectivePattern}\n pushPasswordManagerStrategy='none'\n ref={ref}\n aria-describedby={isInvalid && errorMessage ? errorMessageId : undefined}\n aria-invalid={isInvalid}\n textAlign='center'\n value={value}\n {...props}\n render={({ slots }) => (\n <OTPInputContext.Provider value={{ slots, variant, maxLength }}>\n {children ?? (\n <Group>\n <Slots />\n </Group>\n )}\n </OTPInputContext.Provider>\n )}\n />\n <ErrorMessage\n dataTestId='spectral-input-otp-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n </InputOTPStateContext.Provider>\n )\n}\nRoot.displayName = 'InputOTP'\n\nconst Group = ({\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<ComponentRef<'div'>>\n}) => <div className='gap-x-2 flex items-center justify-center' data-testid='spectral-input-otp-group' ref={ref} {...props} />\nGroup.displayName = 'InputOTP.Group'\n\nconst Slot = ({\n className,\n index,\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n index: number\n ref?: Ref<ComponentRef<'div'>>\n}) => {\n const { variant = 'outlined', slots = [] } = useRoot()\n const { isInvalid } = useContext(InputOTPStateContext)\n const slot = slots[index] || { char: '', hasFakeCaret: true, isActive: false }\n\n return (\n <div\n className={cn(\n 'h-12 w-10 relative z-10 flex items-center justify-center rounded-[8px] border tabular-nums transition duration-200 focus:outline-none',\n variant === 'filled' ? 'border-level-one bg-level-one' : 'border-input-otp-border bg-transparent',\n !isInvalid && 'border',\n isInvalid && 'border-2 border-danger-400',\n slot.isActive && !isInvalid && 'z-10 border-input-otp-border--focus',\n slot.isActive && isInvalid && 'z-10 border-danger-400 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-danger-400',\n className,\n )}\n data-index={index}\n data-testid='spectral-input-otp-slot'\n data-variant={variant}\n ref={ref}\n {...props}\n >\n {slot.char}\n {slot.hasFakeCaret && (\n <div className='inset-0 pointer-events-none absolute flex items-center justify-center motion-safe:animate-caret-blink'>\n <div className='h-8 w-px bg-input-otp-caret' />\n </div>\n )}\n </div>\n )\n}\nSlot.displayName = 'InputOTP.Slot'\n\ninterface SlotsProps {\n className?: string\n count?: number\n start?: number\n}\n\n/**\n * Helper component that automatically renders multiple InputOTP.Slot components.\n * Uses the maxLength from the parent InputOTP to determine how many slots to render.\n *\n * @example\n * // Render all 6 slots\n * <InputOTP maxLength={6}>\n * <InputOTP.Group>\n * <InputOTP.Slots />\n * </InputOTP.Group>\n * </InputOTP>\n *\n * @example\n * // Render slots in groups with a separator (3-3 split)\n * <InputOTP maxLength={6}>\n * <InputOTP.Group>\n * <InputOTP.Slots count={3} />\n * </InputOTP.Group>\n * <InputOTP.Separator />\n * <InputOTP.Group>\n * <InputOTP.Slots start={3} />\n * </InputOTP.Group>\n * </InputOTP>\n */\nconst Slots = ({ start = 0, count, className }: SlotsProps) => {\n const { maxLength = 0 } = useRoot()\n const end = count !== undefined ? start + count : maxLength\n const indices = Array.from({ length: end - start }, (_, i) => start + i)\n\n return (\n <>\n {indices.map((index) => (\n <Slot key={index} index={index} className={className} />\n ))}\n </>\n )\n}\nSlots.displayName = 'InputOTP.Slots'\n\nconst Separator = ({\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<ComponentRef<'div'>>\n}) => {\n const { variant = 'outlined' } = useRoot()\n\n return (\n <div ref={ref} role='separator' {...props} data-testid='spectral-input-otp-separator' data-variant={variant}>\n <MinusIcon size={24} color={variant === 'filled' ? 'var(--color-input-otp-filled-separator)' : 'var(--color-input-otp-border)'} />\n </div>\n )\n}\nSeparator.displayName = 'InputOTP.Separator'\n\nexport const InputOTP = Object.assign(Root, {\n Group,\n Slot,\n Slots,\n Separator,\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"InputOTP.js","names":[],"sources":["../src/components/InputOTP/InputOTP.tsx"],"sourcesContent":["import { MinusIcon } from '@components/Icons'\nimport { ErrorMessage, getErrorMessageId, useFormFieldId, useFormFieldState, type FormFieldState } from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { OTPInput, REGEXP_ONLY_DIGITS, type OTPInputProps } from 'input-otp'\nimport { createContext, useContext, type ClipboardEvent, type ComponentPropsWithoutRef, type ComponentRef, type Ref } from 'react'\n\nexport interface InputOTPBaseProps extends Omit<OTPInputProps, 'textAlign' | 'pushPasswordManagerStrategy' | 'pasteTransformer' | 'noScriptCSSFallback' | 'placeholder' | 'containerClassName' | 'render' | 'pattern'> {\n onComplete?: (...args: unknown[]) => void\n className?: string\n errorMessage?: string | undefined\n inputMode?: 'numeric' | 'text' | 'decimal' | 'tel' | 'search' | 'email' | 'url'\n messageReserveLines?: number\n messageReserveSpace?: boolean\n /**\n * Regex pattern string to restrict allowed characters.\n * When `inputMode=\"numeric\"`, defaults to digits-only pattern.\n * Set to `undefined` to allow any characters.\n */\n pattern?: string | undefined\n separator?: boolean\n state?: FormFieldState\n variant?: 'outlined' | 'filled'\n}\n\nexport type InputOTPProps = InputOTPBaseProps & ({ value: number | string; onChange: (newValue: number | string) => void } | { value?: never; onChange?: never })\n\nconst InputOTPStateContext = createContext<{ isInvalid?: boolean }>({})\n\nconst OTPInputContext = createContext<{\n maxLength?: number\n slots?: { char: string | null; hasFakeCaret: boolean; isActive: boolean }[]\n variant?: 'outlined' | 'filled'\n} | null>(null)\n\nconst useRoot = () => {\n const context = useContext(OTPInputContext)\n if (!context) {\n throw new Error('useRoot must be used within an InputOTP')\n }\n return context\n}\n\nconst Root = ({\n autoFocus = false,\n children,\n className,\n errorMessage,\n id,\n inputMode = 'numeric',\n messageReserveLines = 1,\n messageReserveSpace = false,\n maxLength,\n name,\n onChange,\n onComplete,\n pattern,\n ref,\n state = 'default',\n value,\n variant = 'outlined',\n ...props\n}: InputOTPProps & {\n ref?: Ref<ComponentRef<typeof OTPInput>>\n}) => {\n const inputId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(inputId)\n const { isInvalid } = useFormFieldState(false, state)\n\n // Apply digits-only pattern when inputMode is numeric (unless explicitly overridden)\n const effectivePattern = pattern ?? (inputMode === 'numeric' ? REGEXP_ONLY_DIGITS : undefined)\n\n const handlePaste = (e: ClipboardEvent<HTMLDivElement>): void => {\n let pasteData = e.clipboardData.getData('text/plain').trim().replaceAll('-', '')\n\n // Filter to digits only when in numeric mode\n if (inputMode === 'numeric') {\n pasteData = pasteData.replace(/\\D/g, '')\n }\n\n if (pasteData.length === maxLength && typeof onChange === 'function') {\n onChange(pasteData)\n }\n }\n\n return (\n <InputOTPStateContext.Provider value={{ isInvalid }}>\n <div className='gap-y-1 flex w-max flex-col'>\n <OTPInput\n /* eslint-disable-next-line jsx-a11y/no-autofocus -- intentional: consumers can opt in for OTP-first flows; defaults to false */\n autoFocus={autoFocus}\n containerClassName={cn('gap-2 flex items-center disabled:cursor-not-allowed has-[disabled]:opacity-50', className)}\n data-1p-ignore='true'\n data-dashlane-disabled-on-field='true'\n data-lpignore='true'\n data-protonpass-ignore='true'\n data-testid='spectral-input-otp'\n id={inputId}\n inputMode={inputMode}\n maxLength={maxLength}\n onChange={onChange}\n onComplete={onComplete}\n onPaste={handlePaste}\n pasteTransformer={(pasted) => pasted.replaceAll('-', '')}\n pattern={effectivePattern}\n pushPasswordManagerStrategy='none'\n ref={ref}\n aria-describedby={isInvalid && errorMessage ? errorMessageId : undefined}\n aria-invalid={isInvalid}\n textAlign='center'\n value={value}\n {...props}\n render={({ slots }) => (\n <OTPInputContext.Provider value={{ slots, variant, maxLength }}>\n {children ?? (\n <Group>\n <Slots />\n </Group>\n )}\n </OTPInputContext.Provider>\n )}\n />\n <ErrorMessage\n dataTestId='spectral-input-otp-error-message'\n id={errorMessageId}\n message={isInvalid ? errorMessage : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace}\n />\n </div>\n </InputOTPStateContext.Provider>\n )\n}\nRoot.displayName = 'InputOTP'\n\nconst Group = ({\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<ComponentRef<'div'>>\n}) => <div className='gap-x-2 flex items-center justify-center' data-testid='spectral-input-otp-group' ref={ref} {...props} />\nGroup.displayName = 'InputOTP.Group'\n\nconst Slot = ({\n className,\n index,\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n index: number\n ref?: Ref<ComponentRef<'div'>>\n}) => {\n const { variant = 'outlined', slots = [] } = useRoot()\n const { isInvalid } = useContext(InputOTPStateContext)\n const slot = slots[index] || { char: '', hasFakeCaret: true, isActive: false }\n\n return (\n <div\n className={cn(\n 'h-12 w-10 relative z-10 flex items-center justify-center rounded-[8px] border tabular-nums transition duration-200 focus:outline-none',\n variant === 'filled' ? 'border-level-one bg-level-one' : 'border-input-otp-border bg-transparent',\n !isInvalid && 'border',\n isInvalid && 'border-2 border-danger-400',\n slot.isActive && !isInvalid && 'z-10 border-input-otp-border--focus',\n slot.isActive && isInvalid && 'z-10 border-danger-400 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-danger-400',\n className,\n )}\n data-index={index}\n data-testid='spectral-input-otp-slot'\n data-variant={variant}\n ref={ref}\n {...props}\n >\n {slot.char}\n {slot.hasFakeCaret && (\n <div className='inset-0 pointer-events-none absolute flex items-center justify-center motion-safe:animate-caret-blink'>\n <div className='h-8 w-px bg-input-otp-caret' />\n </div>\n )}\n </div>\n )\n}\nSlot.displayName = 'InputOTP.Slot'\n\ninterface SlotsProps {\n className?: string\n count?: number\n start?: number\n}\n\n/**\n * Helper component that automatically renders multiple InputOTP.Slot components.\n * Uses the maxLength from the parent InputOTP to determine how many slots to render.\n *\n * @example\n * // Render all 6 slots\n * <InputOTP maxLength={6}>\n * <InputOTP.Group>\n * <InputOTP.Slots />\n * </InputOTP.Group>\n * </InputOTP>\n *\n * @example\n * // Render slots in groups with a separator (3-3 split)\n * <InputOTP maxLength={6}>\n * <InputOTP.Group>\n * <InputOTP.Slots count={3} />\n * </InputOTP.Group>\n * <InputOTP.Separator />\n * <InputOTP.Group>\n * <InputOTP.Slots start={3} />\n * </InputOTP.Group>\n * </InputOTP>\n */\nconst Slots = ({ start = 0, count, className }: SlotsProps) => {\n const { maxLength = 0 } = useRoot()\n const end = count !== undefined ? start + count : maxLength\n const indices = Array.from({ length: end - start }, (_, i) => start + i)\n\n return (\n <>\n {indices.map((index) => (\n <Slot key={index} index={index} className={className} />\n ))}\n </>\n )\n}\nSlots.displayName = 'InputOTP.Slots'\n\nconst Separator = ({\n ref,\n ...props\n}: ComponentPropsWithoutRef<'div'> & {\n ref?: Ref<ComponentRef<'div'>>\n}) => {\n const { variant = 'outlined' } = useRoot()\n\n return (\n <div ref={ref} role='separator' {...props} data-testid='spectral-input-otp-separator' data-variant={variant}>\n <MinusIcon size={24} color={variant === 'filled' ? 'var(--color-input-otp-filled-separator)' : 'var(--color-input-otp-border)'} />\n </div>\n )\n}\nSeparator.displayName = 'InputOTP.Separator'\n\nexport const InputOTP = Object.assign(Root, {\n Group,\n Slot,\n Slots,\n Separator,\n})\n"],"mappings":"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"}
@@ -17,6 +17,7 @@ interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'
17
17
  onChange?: (value: string) => void;
18
18
  onCreate?: (query: string) => void;
19
19
  onValueChange?: (value: string) => void;
20
+ openOnFocus?: boolean;
20
21
  options: InputSearchOption[];
21
22
  placeholder?: string;
22
23
  renderOption?: (option: InputSearchOption) => ReactNode;
@@ -44,6 +45,7 @@ declare function InputSearch({
44
45
  onChange,
45
46
  onCreate,
46
47
  onValueChange,
48
+ openOnFocus,
47
49
  options,
48
50
  placeholder,
49
51
  ref,