@spear-ai/spectral 1.21.0 → 1.21.2

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.
Files changed (84) hide show
  1. package/dist/ButtonGroup/ButtonGroupButton.d.ts.map +1 -1
  2. package/dist/ButtonGroup/ButtonGroupButton.js +6 -5
  3. package/dist/ButtonGroup/ButtonGroupButton.js.map +1 -1
  4. package/dist/ButtonGroup.js +1 -1
  5. package/dist/ButtonGroup.js.map +1 -1
  6. package/dist/ButtonIcon.js +2 -2
  7. package/dist/ButtonIcon.js.map +1 -1
  8. package/dist/Checkbox.d.ts +1 -0
  9. package/dist/Checkbox.d.ts.map +1 -1
  10. package/dist/Checkbox.js +3 -3
  11. package/dist/Checkbox.js.map +1 -1
  12. package/dist/Combobox.d.ts.map +1 -1
  13. package/dist/Combobox.js +2 -2
  14. package/dist/Combobox.js.map +1 -1
  15. package/dist/DateTimePicker/Calendar.d.ts +13 -1
  16. package/dist/DateTimePicker/Calendar.d.ts.map +1 -1
  17. package/dist/DateTimePicker/Calendar.js +11 -4
  18. package/dist/DateTimePicker/Calendar.js.map +1 -1
  19. package/dist/DateTimePicker/DateTimeDisplayInput.d.ts +2 -2
  20. package/dist/DateTimePicker/DateTimeDisplayInput.d.ts.map +1 -1
  21. package/dist/DateTimePicker/DateTimeDisplayInput.js +3 -3
  22. package/dist/DateTimePicker/DateTimeDisplayInput.js.map +1 -1
  23. package/dist/DateTimePicker.d.ts +17 -4
  24. package/dist/DateTimePicker.d.ts.map +1 -1
  25. package/dist/DateTimePicker.js +48 -33
  26. package/dist/DateTimePicker.js.map +1 -1
  27. package/dist/Input.d.ts +1 -1
  28. package/dist/Input.d.ts.map +1 -1
  29. package/dist/Input.js +24 -17
  30. package/dist/Input.js.map +1 -1
  31. package/dist/InputOTP.d.ts +2 -0
  32. package/dist/InputOTP.d.ts.map +1 -1
  33. package/dist/InputOTP.js +52 -40
  34. package/dist/InputOTP.js.map +1 -1
  35. package/dist/InputSearch.d.ts +2 -2
  36. package/dist/InputSearch.d.ts.map +1 -1
  37. package/dist/InputSearch.js +6 -5
  38. package/dist/InputSearch.js.map +1 -1
  39. package/dist/Kbd.d.ts.map +1 -1
  40. package/dist/Kbd.js.map +1 -1
  41. package/dist/MultiSelect/MultiSelectBase.d.ts.map +1 -1
  42. package/dist/MultiSelect/MultiSelectBase.js +6 -5
  43. package/dist/MultiSelect/MultiSelectBase.js.map +1 -1
  44. package/dist/RadialMenu.d.ts.map +1 -1
  45. package/dist/RadialMenu.js +3 -4
  46. package/dist/RadialMenu.js.map +1 -1
  47. package/dist/RadioButton.js +1 -1
  48. package/dist/RadioButton.js.map +1 -1
  49. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts +1 -1
  50. package/dist/RadioButtonGroup/RadioButtonGroupBase.d.ts.map +1 -1
  51. package/dist/RadioButtonGroup/RadioButtonGroupBase.js +3 -3
  52. package/dist/RadioButtonGroup/RadioButtonGroupBase.js.map +1 -1
  53. package/dist/RadioButtonGroup.d.ts +1 -1
  54. package/dist/RadioGroup.d.ts +6 -5
  55. package/dist/RadioGroup.d.ts.map +1 -1
  56. package/dist/RadioGroup.js +18 -14
  57. package/dist/RadioGroup.js.map +1 -1
  58. package/dist/Select.d.ts +1 -0
  59. package/dist/Select.d.ts.map +1 -1
  60. package/dist/Select.js +3 -3
  61. package/dist/Select.js.map +1 -1
  62. package/dist/Slider.js +1 -1
  63. package/dist/Slider.js.map +1 -1
  64. package/dist/Switch.d.ts +3 -3
  65. package/dist/Switch.d.ts.map +1 -1
  66. package/dist/Switch.js +5 -5
  67. package/dist/Switch.js.map +1 -1
  68. package/dist/Textarea.d.ts +3 -3
  69. package/dist/Textarea.d.ts.map +1 -1
  70. package/dist/Textarea.js +4 -3
  71. package/dist/Textarea.js.map +1 -1
  72. package/dist/primitives/input.d.ts.map +1 -1
  73. package/dist/primitives/input.js +2 -0
  74. package/dist/primitives/input.js.map +1 -1
  75. package/dist/primitives/textarea.d.ts.map +1 -1
  76. package/dist/primitives/textarea.js +2 -0
  77. package/dist/primitives/textarea.js.map +1 -1
  78. package/dist/styles/horizon/colors.css +5 -3
  79. package/dist/styles/spectral.css +1 -1
  80. package/dist/utils/formFieldUtils.d.ts +9 -1
  81. package/dist/utils/formFieldUtils.d.ts.map +1 -1
  82. package/dist/utils/formFieldUtils.js +19 -2
  83. package/dist/utils/formFieldUtils.js.map +1 -1
  84. package/package.json +1 -1
@@ -21,6 +21,7 @@ interface InputOTPBaseProps extends Omit<OTPInputProps, 'textAlign' | 'pushPassw
21
21
  separator?: boolean;
22
22
  state?: FormFieldState;
23
23
  variant?: 'outlined' | 'filled';
24
+ warningMessage?: string | undefined;
24
25
  }
25
26
  type InputOTPProps = InputOTPBaseProps & ({
26
27
  value: number | string;
@@ -53,6 +54,7 @@ declare const InputOTP: {
53
54
  state,
54
55
  value,
55
56
  variant,
57
+ warningMessage,
56
58
  ...props
57
59
  }: InputOTPProps & {
58
60
  ref?: Ref<ComponentRef<typeof OTPInput>>;
@@ -1 +1 @@
1
- {"version":3,"file":"InputOTP.d.ts","names":[],"sources":["../src/components/InputOTP/InputOTP.tsx"],"mappings":";;;;;;;UAMiB,iBAAA,SAA0B,IAAA,CAAK,aAAA;EAC9C,UAAA,OAAiB,IAAA;EACjB,SAAA;EACA,YAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EAQQ;;;;;EAFR,OAAA;EACA,SAAA;EACA,KAAA,GAAQ,cAAA;EACR,OAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,iBAAA;EAAuB,KAAA;EAAwB,QAAA,GAAW,QAAA;AAAA;EAAyC,KAAA;EAAe,QAAA;AAAA;AAAA,UA+JpI,UAAA;EACR,SAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,cA0DW,QAAA;EAAA;;;;;;;;;;;;;;;;;;;KAvLV,aAAA;IACD,GAAA,GAAM,GAAA,CAAI,YAAA,QAAoB,QAAA;EAAA,IAC/B,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;OA0EE,wBAAA;MACD,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;OAQE,wBAAA;MACD,KAAA;MACA,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;OA+D+C,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;OAkBvD,wBAAA;MACD,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"InputOTP.d.ts","names":[],"sources":["../src/components/InputOTP/InputOTP.tsx"],"mappings":";;;;;;;UAMiB,iBAAA,SAA0B,IAAA,CAAK,aAAA;EAC9C,UAAA,OAAiB,IAAA;EACjB,SAAA;EACA,YAAA;EACA,SAAA;EACA,mBAAA;EACA,mBAAA;EAQQ;;;;;EAFR,OAAA;EACA,SAAA;EACA,KAAA,GAAQ,cAAA;EACR,OAAA;EACA,cAAA;AAAA;AAAA,KAGU,aAAA,GAAgB,iBAAA;EAAuB,KAAA;EAAwB,QAAA,GAAW,QAAA;AAAA;EAAyC,KAAA;EAAe,QAAA;AAAA;AAAA,UA0KpI,UAAA;EACR,SAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,cA0DW,QAAA;EAAA;;;;;;;;;;;;;;;;;;;;KAjMV,aAAA;IACD,GAAA,GAAM,GAAA,CAAI,YAAA,QAAoB,QAAA;EAAA,IAC/B,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;OAoFE,wBAAA;MACD,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;;OAQE,wBAAA;MACD,KAAA;MACA,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;;OA+D+C,UAAA,GAAU,oBAAA,CAAA,GAAA,CAAA,OAAA;;;;;;;OAkBvD,wBAAA;MACD,GAAA,GAAM,GAAA,CAAI,YAAA;IAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/InputOTP.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
  import { MinusIcon } from "./Icons/MinusIcon.js";
3
3
  import { cn } from "./utils/twUtils.js";
4
- import { ErrorMessage } from "./FormFieldMessage.js";
5
- import { getErrorMessageId, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
4
+ import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
5
+ import { getErrorMessageId, getWarningMessageId, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
6
6
  import { createContext, useContext } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { OTPInput, REGEXP_ONLY_DIGITS } from "input-otp";
@@ -15,11 +15,13 @@ const useRoot = () => {
15
15
  if (!context) throw new Error("useRoot must be used within an InputOTP");
16
16
  return context;
17
17
  };
18
- const Root = ({ autoFocus = false, children, className, errorMessage, id, inputMode = "numeric", messageReserveLines = 1, messageReserveSpace = false, maxLength, name, onChange, onComplete, pattern, ref, state = "default", value, variant = "outlined", ...props }) => {
18
+ const Root = ({ autoFocus = false, children, className, errorMessage, id, inputMode = "numeric", messageReserveLines = 1, messageReserveSpace = false, maxLength, name, onChange, onComplete, pattern, ref, state = "default", value, variant = "outlined", warningMessage, ...props }) => {
19
19
  const inputId = useFormFieldId(id, name);
20
20
  const errorMessageId = getErrorMessageId(inputId);
21
+ const warningMessageId = getWarningMessageId(inputId);
21
22
  const { isInvalid } = useFormFieldState(false, state);
22
23
  const effectivePattern = pattern ?? (inputMode === "numeric" ? REGEXP_ONLY_DIGITS : void 0);
24
+ const describedBy = [isInvalid && errorMessage ? errorMessageId : void 0, state === "warning" && warningMessage ? warningMessageId : void 0].filter(Boolean).join(" ") || void 0;
23
25
  const handlePaste = (e) => {
24
26
  let pasteData = e.clipboardData.getData("text/plain").trim().replaceAll("-", "");
25
27
  if (inputMode === "numeric") pasteData = pasteData.replace(/\D/g, "");
@@ -29,43 +31,53 @@ const Root = ({ autoFocus = false, children, className, errorMessage, id, inputM
29
31
  value: { isInvalid },
30
32
  children: /* @__PURE__ */ jsxs("div", {
31
33
  className: "gap-y-1 flex w-max flex-col",
32
- children: [/* @__PURE__ */ jsx(OTPInput, {
33
- autoFocus,
34
- containerClassName: cn("gap-2 flex items-center disabled:cursor-not-allowed has-[disabled]:opacity-50", className),
35
- "data-1p-ignore": "true",
36
- "data-dashlane-disabled-on-field": "true",
37
- "data-lpignore": "true",
38
- "data-protonpass-ignore": "true",
39
- id: inputId,
40
- inputMode,
41
- maxLength,
42
- onChange,
43
- onComplete,
44
- onPaste: handlePaste,
45
- pasteTransformer: (pasted) => pasted.replaceAll("-", ""),
46
- pattern: effectivePattern,
47
- pushPasswordManagerStrategy: "none",
48
- ref,
49
- "aria-describedby": isInvalid && errorMessage ? errorMessageId : void 0,
50
- "aria-invalid": isInvalid,
51
- textAlign: "center",
52
- value,
53
- ...props,
54
- render: ({ slots }) => /* @__PURE__ */ jsx(OTPInputContext.Provider, {
55
- value: {
56
- slots,
57
- variant,
58
- maxLength
59
- },
60
- children: children ?? /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Slots, {}) })
34
+ children: [
35
+ /* @__PURE__ */ jsx(OTPInput, {
36
+ "aria-describedby": describedBy,
37
+ "aria-invalid": isInvalid,
38
+ autoFocus,
39
+ containerClassName: cn("gap-2 flex items-center has-[:disabled]:cursor-not-allowed has-[disabled]:opacity-50", className),
40
+ "data-1p-ignore": "true",
41
+ "data-dashlane-disabled-on-field": "true",
42
+ "data-lpignore": "true",
43
+ "data-protonpass-ignore": "true",
44
+ id: inputId,
45
+ inputMode,
46
+ maxLength,
47
+ onChange,
48
+ onComplete,
49
+ onPaste: handlePaste,
50
+ pasteTransformer: (pasted) => pasted.replaceAll("-", ""),
51
+ pattern: effectivePattern,
52
+ pushPasswordManagerStrategy: "none",
53
+ ref,
54
+ textAlign: "center",
55
+ value,
56
+ ...props,
57
+ render: ({ slots }) => /* @__PURE__ */ jsx(OTPInputContext.Provider, {
58
+ value: {
59
+ slots,
60
+ variant,
61
+ maxLength
62
+ },
63
+ children: children ?? /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Slots, {}) })
64
+ })
65
+ }),
66
+ /* @__PURE__ */ jsx(ErrorMessage, {
67
+ dataTestId: "spectral-input-otp-error-message",
68
+ id: errorMessageId,
69
+ message: isInvalid ? errorMessage : null,
70
+ messageReserveLines,
71
+ messageReserveSpace
72
+ }),
73
+ /* @__PURE__ */ jsx(WarningMessage, {
74
+ dataTestId: "spectral-input-otp-warning-message",
75
+ id: warningMessageId,
76
+ message: state === "warning" ? warningMessage : null,
77
+ messageReserveLines,
78
+ messageReserveSpace
61
79
  })
62
- }), /* @__PURE__ */ jsx(ErrorMessage, {
63
- dataTestId: "spectral-input-otp-error-message",
64
- id: errorMessageId,
65
- message: isInvalid ? errorMessage : null,
66
- messageReserveLines,
67
- messageReserveSpace
68
- })]
80
+ ]
69
81
  })
70
82
  });
71
83
  };
@@ -85,7 +97,7 @@ const Slot = ({ className, index, ref, ...props }) => {
85
97
  isActive: false
86
98
  };
87
99
  return /* @__PURE__ */ jsxs("div", {
88
- className: cn("h-12 w-10 relative z-10 flex items-center justify-center rounded-[8px] border tabular-nums transition duration-200 focus:outline-none", variant === "filled" ? "border-level-one bg-level-one" : "border-input-otp-border bg-transparent", !isInvalid && "border", isInvalid && "border-2 border-danger-400", slot.isActive && !isInvalid && "z-10 border-input-otp-border--focus", slot.isActive && isInvalid && "z-10 border-danger-400 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-danger-400", className),
100
+ className: cn("h-12 w-10 relative z-10 flex items-center justify-center rounded-[8px] border tabular-nums transition duration-200 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent", variant === "filled" ? "border-level-one bg-level-one" : "border-input-otp-border bg-transparent", !isInvalid && "border", isInvalid && "border-2 border-danger-400", slot.isActive && !isInvalid && "z-10 border-input-otp-border--focus border-2", slot.isActive && isInvalid && "z-10 border-danger-400 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-danger-400", className),
89
101
  "data-index": index,
90
102
  "data-variant": variant,
91
103
  ref,
@@ -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, getWarningMessageId, useFormFieldId, useFormFieldState, WarningMessage, 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 warningMessage?: string | undefined\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 warningMessage,\n ...props\n}: InputOTPProps & {\n ref?: Ref<ComponentRef<typeof OTPInput>>\n}) => {\n const inputId = useFormFieldId(id, name)\n const errorMessageId = getErrorMessageId(inputId)\n const warningMessageId = getWarningMessageId(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 describedBy = [isInvalid && errorMessage ? errorMessageId : undefined, state === 'warning' && warningMessage ? warningMessageId : undefined].filter(Boolean).join(' ') || 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 aria-describedby={describedBy}\n aria-invalid={isInvalid}\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 has-[: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 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 <WarningMessage\n dataTestId='spectral-input-otp-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? warningMessage : 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 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent',\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 border-2',\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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"}
@@ -12,6 +12,7 @@ interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'
12
12
  defaultValue?: string;
13
13
  dropdownWidth?: DropdownWidth;
14
14
  emptyMessage?: string;
15
+ hideSearchIcon?: boolean;
15
16
  isCreating?: boolean;
16
17
  labelClassName?: string;
17
18
  onChange?: (value: string) => void;
@@ -21,7 +22,6 @@ interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'
21
22
  options: InputSearchOption[];
22
23
  placeholder?: string;
23
24
  renderOption?: (option: InputSearchOption) => ReactNode;
24
- showSearchIcon?: boolean;
25
25
  state?: Exclude<FormFieldState, 'disabled'>;
26
26
  value?: string;
27
27
  warningMessage?: BaseFormFieldProps['errorMessage'];
@@ -35,6 +35,7 @@ declare function InputSearch({
35
35
  dropdownWidth,
36
36
  emptyMessage,
37
37
  errorMessage,
38
+ hideSearchIcon,
38
39
  id,
39
40
  isCreating,
40
41
  label,
@@ -51,7 +52,6 @@ declare function InputSearch({
51
52
  ref,
52
53
  renderOption,
53
54
  required,
54
- showSearchIcon,
55
55
  state,
56
56
  value: valueProp,
57
57
  warningMessage,
@@ -1 +1 @@
1
- {"version":3,"file":"InputSearch.d.ts","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"mappings":";;;;;;KA0BY,iBAAA,GAAoB,UAAA;AAAA,UAEf,gBAAA,SAAyB,IAAA,CAAK,kBAAA;EAC7C,SAAA;EACA,iBAAA,IAAqB,KAAA,aAAkB,SAAA;EACvC,aAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,UAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EACZ,QAAA,IAAY,KAAA;EACZ,aAAA,IAAiB,KAAA;EACjB,WAAA;EACA,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,YAAA,IAAgB,MAAA,EAAQ,iBAAA,KAAsB,SAAA;EAC9C,cAAA;EACA,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAajB,SAAA;EACA,iBAAA;EACA,aAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,EAAA;EACA,UAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;EACA,cAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,gBAAA;EAAqB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"InputSearch.d.ts","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"mappings":";;;;;;KA4BY,iBAAA,GAAoB,UAAA;AAAA,UAEf,gBAAA,SAAyB,IAAA,CAAK,kBAAA;EAC7C,SAAA;EACA,iBAAA,IAAqB,KAAA,aAAkB,SAAA;EACvC,aAAA;EACA,YAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,cAAA;EACA,UAAA;EACA,cAAA;EACA,QAAA,IAAY,KAAA;EACZ,QAAA,IAAY,KAAA;EACZ,aAAA,IAAiB,KAAA;EACjB,WAAA;EACA,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,YAAA,IAAgB,MAAA,EAAQ,iBAAA,KAAsB,SAAA;EAC9C,KAAA,GAAQ,OAAA,CAAQ,cAAA;EAChB,KAAA;EACA,cAAA,GAAiB,kBAAA;AAAA;AAAA;EAajB,SAAA;EACA,iBAAA;EACA,aAAA;EACA,YAAA;EACA,QAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,cAAA;EACA,EAAA;EACA,UAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,YAAA;EACA,QAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,oBACoB,eAAA;EAAA,cACN;AAAA,GACb,gBAAA;EAAqB,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA,IAAiB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
@@ -7,7 +7,7 @@ import { SearchIcon } from "./Icons/SearchIcon.js";
7
7
  import { WarningIcon } from "./Icons/WarningIcon.js";
8
8
  import { cn } from "./utils/twUtils.js";
9
9
  import { ErrorMessage, WarningMessage } from "./FormFieldMessage.js";
10
- import { EmptyState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getFormFieldCSSProperties, getInputClasses, getOptionClasses, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
10
+ import { EmptyState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getFormFieldCSSProperties, getInputClasses, getOptionClasses, getPasswordManagerIgnoreProps, getWarningMessageId, useFormFieldId, useFormFieldState } from "./utils/formFieldUtils.js";
11
11
  import { useUncontrolledState } from "./hooks/useUncontrolledState.js";
12
12
  import { Label } from "./Label.js";
13
13
  import { useAutoDropdownHorizontalShift } from "./utils/dropdownPositioning.js";
@@ -30,12 +30,12 @@ const defaultCreateOptionLabel = (query) => /* @__PURE__ */ jsxs(Fragment$1, { c
30
30
  ]
31
31
  })]
32
32
  })] });
33
- const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel, creatingLabel = "Creating…", defaultValue = "", disabled, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, id, isCreating = false, label, labelClassName, messageReserveLines = 1, messageReserveSpace = false, name, onChange, onCreate, onValueChange, openOnFocus = false, options, placeholder = "Search…", ref, renderOption, required, showSearchIcon = true, state = "default", value: valueProp, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel }) => {
33
+ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel, creatingLabel = "Creating…", defaultValue = "", disabled, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, hideSearchIcon = false, id, isCreating = false, label, labelClassName, messageReserveLines = 1, messageReserveSpace = false, name, onChange, onCreate, onValueChange, openOnFocus = false, options, placeholder = "Search…", ref, renderOption, required, state = "default", value: valueProp, warningMessage, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel }) => {
34
34
  if (!label && !ariaLabel) console.warn("InputSearch: provide either `label` or `aria-label` for an accessible name.");
35
35
  const fieldId = useFormFieldId(id, name);
36
36
  const listboxId = `${fieldId}-listbox`;
37
37
  const errorMessageId = getErrorMessageId(fieldId);
38
- const warningMessageId = `${fieldId}-warning`;
38
+ const warningMessageId = getWarningMessageId(fieldId);
39
39
  const messageId = state === "error" ? errorMessageId : state === "warning" && warningMessage ? warningMessageId : void 0;
40
40
  const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state);
41
41
  const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId);
@@ -197,7 +197,7 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
197
197
  dropdownWidth,
198
198
  triggerWidth: "100%"
199
199
  });
200
- const inputClasses = cn(getInputClasses(state, className), "pe-4", showSearchIcon && "ps-11", showClearButton && "pe-10!", state === "loading" && "cursor-wait");
200
+ const inputClasses = cn(getInputClasses(state, className), "pe-4", !hideSearchIcon && "ps-11", showClearButton && "pe-10!", state === "loading" && "cursor-wait");
201
201
  return /* @__PURE__ */ jsxs("div", {
202
202
  className: "flex w-full flex-col",
203
203
  ref,
@@ -213,7 +213,7 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
213
213
  children: /* @__PURE__ */ jsxs("div", {
214
214
  className: "relative",
215
215
  children: [
216
- showSearchIcon && /* @__PURE__ */ jsx("span", {
216
+ !hideSearchIcon && /* @__PURE__ */ jsx("span", {
217
217
  "aria-hidden": "true",
218
218
  className: cn("left-4 text-input-icon absolute top-1/2 -translate-y-1/2", isDisabled && "text-input-text--disabled"),
219
219
  children: /* @__PURE__ */ jsx(SearchIcon, { size: 20 })
@@ -245,6 +245,7 @@ const InputSearch = ({ className, createOptionLabel = defaultCreateOptionLabel,
245
245
  style: getFormFieldCSSProperties(),
246
246
  type: "text",
247
247
  value: query,
248
+ ...getPasswordManagerIgnoreProps("text"),
248
249
  ...ariaProps
249
250
  }),
250
251
  showClearButton ? /* @__PURE__ */ jsx("button", {
@@ -1 +1 @@
1
- {"version":3,"file":"InputSearch.js","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"sourcesContent":["import { CloseCircleIcon, ErrorIcon, LoaderIcon, PlusIcon, SearchIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n WarningMessage,\n getAriaProps,\n getDropdownSurfaceClasses,\n getDropdownWidthStyles,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getInputClasses,\n getOptionClasses,\n useFormFieldId,\n useFormFieldState,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type InputSearchOption = BaseOption\n\nexport interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n createOptionLabel?: (query: string) => ReactNode\n creatingLabel?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n isCreating?: boolean\n labelClassName?: string\n onChange?: (value: string) => void\n onCreate?: (query: string) => void\n onValueChange?: (value: string) => void\n openOnFocus?: boolean\n options: InputSearchOption[]\n placeholder?: string\n renderOption?: (option: InputSearchOption) => ReactNode\n showSearchIcon?: boolean\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst defaultCreateOptionLabel = (query: string): ReactNode => (\n <>\n <PlusIcon size={16} className='shrink-0' />\n <span className='truncate'>\n Create <span className='font-semibold'>&ldquo;{query}&rdquo;</span>\n </span>\n </>\n)\n\nexport const InputSearch = ({\n className,\n createOptionLabel = defaultCreateOptionLabel,\n creatingLabel = 'Creating…',\n defaultValue = '',\n disabled,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n id,\n isCreating = false,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onCreate,\n onValueChange,\n openOnFocus = false,\n options,\n placeholder = 'Search…',\n ref,\n renderOption,\n required,\n showSearchIcon = true,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: InputSearchProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n // eslint-disable-next-line no-console\n console.warn('InputSearch: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const fieldId = useFormFieldId(id, name)\n const listboxId = `${fieldId}-listbox`\n const errorMessageId = getErrorMessageId(fieldId)\n const warningMessageId = `${fieldId}-warning`\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const [query, setQuery] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number; width: number } | null>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n const blurTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const triggerRef = useRef<HTMLDivElement>(null)\n\n const selectedOption = useMemo(() => options.find((option) => option.value === value) ?? null, [options, value])\n\n useEffect(() => {\n if (!isFocused) {\n setQuery(selectedOption?.label ?? '')\n }\n }, [selectedOption, isFocused])\n\n const trimmedQuery = query.trim()\n\n const filteredOptions = useMemo(() => {\n if (trimmedQuery.length === 0) return options\n const lower = trimmedQuery.toLowerCase()\n return options.filter((option) => option.label.toLowerCase().includes(lower))\n }, [trimmedQuery, options])\n\n const exactMatch = useMemo(() => options.some((option) => option.label.toLowerCase() === trimmedQuery.toLowerCase()), [options, trimmedQuery])\n\n const showCreateOption = onCreate !== undefined && trimmedQuery.length > 0 && !exactMatch\n const createOptionIndex = showCreateOption ? filteredOptions.length : -1\n const totalItems = filteredOptions.length + (showCreateOption ? 1 : 0)\n const showDropdown = isFocused && !isDisabled && !isLoading && (openOnFocus || trimmedQuery.length > 0)\n const showEmptyState = showDropdown && totalItems === 0\n\n const { dropdownShiftStyle, recalculateDropdownPosition, setDropdownElement } = useAutoDropdownHorizontalShift(showDropdown)\n\n const updateDropdownPosition = useCallback(() => {\n const trigger = triggerRef.current\n if (!trigger) return\n const rect = trigger.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width,\n })\n recalculateDropdownPosition()\n }, [recalculateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) {\n setDropdownPosition(null)\n return\n }\n updateDropdownPosition()\n const handle = () => updateDropdownPosition()\n window.addEventListener('scroll', handle, true)\n window.addEventListener('resize', handle)\n return () => {\n window.removeEventListener('scroll', handle, true)\n window.removeEventListener('resize', handle)\n }\n }, [showDropdown, updateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) return\n updateDropdownPosition()\n }, [showDropdown, updateDropdownPosition, filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n setHighlightedIndex(-1)\n }, [filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n if (highlightedIndex < 0 || !listRef.current) return\n const element = listRef.current.querySelector<HTMLElement>(`[data-index='${highlightedIndex}']`)\n element?.scrollIntoView({ block: 'nearest' })\n }, [highlightedIndex])\n\n useEffect(\n () => () => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n },\n [],\n )\n\n const commitSelection = useCallback(\n (option: InputSearchOption) => {\n if (option.disabled) return\n setValue(option.value)\n setQuery(option.label)\n setIsFocused(false)\n setHighlightedIndex(-1)\n inputRef.current?.blur()\n },\n [setValue],\n )\n\n const commitCreate = useCallback(() => {\n if (!onCreate || isCreating || trimmedQuery.length === 0) return\n onCreate(trimmedQuery)\n }, [onCreate, isCreating, trimmedQuery])\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case 'ArrowDown': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev < totalItems - 1 ? prev + 1 : prev))\n break\n }\n case 'ArrowUp': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : 0))\n break\n }\n case 'Enter': {\n if (totalItems === 0) return\n event.preventDefault()\n if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {\n const option = filteredOptions[highlightedIndex]\n if (option) commitSelection(option)\n } else if (highlightedIndex === createOptionIndex && !isCreating) {\n commitCreate()\n }\n break\n }\n case 'Escape': {\n event.preventDefault()\n setIsFocused(false)\n setHighlightedIndex(-1)\n if (selectedOption) setQuery(selectedOption.label)\n inputRef.current?.blur()\n break\n }\n default:\n break\n }\n },\n [totalItems, filteredOptions, highlightedIndex, createOptionIndex, commitSelection, commitCreate, isCreating, selectedOption],\n )\n\n const handleFocus = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n blurTimeoutRef.current = null\n }\n setIsFocused(true)\n setQuery('')\n }, [])\n\n const handleBlur = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n blurTimeoutRef.current = setTimeout(() => {\n blurTimeoutRef.current = null\n // Don't write to `query` here — the useEffect tied to selectedOption + isFocused\n // is the single source of truth for the visible query when the field isn't focused.\n // Setting it from this stale closure causes off-by-one display after selection.\n setIsFocused(false)\n setHighlightedIndex(-1)\n }, 150)\n }, [])\n\n const handleClear = useCallback(() => {\n setValue('')\n setQuery('')\n inputRef.current?.focus()\n }, [setValue])\n\n const showClearButton = !isLoading && !isDisabled && (value.length > 0 || (isFocused && query.length > 0))\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: '100%',\n })\n\n const inputClasses = cn(getInputClasses(state, className), 'pe-4', showSearchIcon && 'ps-11', showClearButton && 'pe-10!', state === 'loading' && 'cursor-wait')\n\n return (\n <div className='flex w-full flex-col' data-testid='spectral-input-search-container' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled')} data-testid='spectral-input-search-label' htmlFor={fieldId}>\n {label}\n </Label>\n )}\n\n <div className='relative' data-testid='spectral-input-search-wrapper' ref={triggerRef}>\n <div className='relative'>\n {showSearchIcon && (\n <span aria-hidden='true' className={cn('left-4 text-input-icon absolute top-1/2 -translate-y-1/2', isDisabled && 'text-input-text--disabled')} data-testid='spectral-input-search-icon'>\n <SearchIcon size={20} />\n </span>\n )}\n\n <input\n aria-activedescendant={highlightedIndex >= 0 ? `${fieldId}-option-${highlightedIndex}` : undefined}\n aria-autocomplete='list'\n aria-controls={listboxId}\n aria-expanded={showDropdown}\n // oxlint-disable-next-line jsx-a11y/role-supports-aria-props -- Valid per WAI-ARIA 1.2 Combobox pattern\n aria-haspopup='listbox'\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input-search'\n disabled={isDisabled || isLoading}\n id={fieldId}\n name={name}\n onBlur={handleBlur}\n onChange={(event) => {\n setQuery(event.target.value)\n if (!isFocused) setIsFocused(true)\n }}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n ref={inputRef}\n required={required}\n role='combobox'\n style={getFormFieldCSSProperties() as CSSProperties}\n type='text'\n value={query}\n {...ariaProps}\n />\n\n {showClearButton ? (\n <button\n aria-label={`Clear ${label ?? 'search'}`}\n className='right-4 text-input-icon hover:text-input-icon--hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus rounded-sm absolute top-1/2 -translate-y-1/2 cursor-pointer'\n data-testid='spectral-input-search-clear-button'\n onClick={handleClear}\n // Prevent input blur from firing before click resolves\n onMouseDown={(event) => event.preventDefault()}\n type='button'\n >\n <CloseCircleIcon size={20} />\n </button>\n ) : state === 'loading' ? (\n <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-loading-icon'>\n <LoaderIcon className='motion-safe:animate-spin' size={20} />\n </div>\n ) : state === 'error' ? (\n <div className='right-4 text-danger-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-error-icon'>\n <ErrorIcon size={20} />\n </div>\n ) : state === 'warning' ? (\n <div className='right-4 text-warning-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-warning-icon'>\n <WarningIcon size={20} />\n </div>\n ) : null}\n </div>\n\n </div>\n\n {showDropdown && dropdownPosition && typeof document !== 'undefined'\n ? createPortal(\n <div\n className={cn('origin-top p-1 z-50 fixed', getDropdownSurfaceClasses(), 'max-h-72 overflow-hidden', 'motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:slide-in-from-top-2')}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-input-search-content'\n ref={setDropdownElement}\n style={{\n top: `${dropdownPosition.top}px`,\n left: `${dropdownPosition.left}px`,\n ...(dropdownWidthMode === 'trigger' ? { width: `${dropdownPosition.width}px` } : (dropdownWidthStyle as CSSProperties)),\n ...dropdownShiftStyle,\n }}\n >\n <div\n className='max-h-[17.5rem] overflow-y-auto'\n id={listboxId}\n ref={listRef}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- WAI-ARIA combobox pattern requires role='listbox' on the popup\n role='listbox'\n >\n {showEmptyState ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <>\n {filteredOptions.map((option, index) => {\n const isHighlighted = index === highlightedIndex\n const isSelected = option.value === value\n return (\n <button\n aria-selected={isSelected}\n className={cn(getOptionClasses(!!option.disabled, isHighlighted, isSelected), 'text-left')}\n data-highlighted={isHighlighted ? '' : undefined}\n data-index={index}\n data-testid='spectral-input-search-item'\n disabled={option.disabled}\n id={`${fieldId}-option-${index}`}\n key={option.value}\n onMouseDown={(event) => {\n event.preventDefault()\n commitSelection(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n <span className='min-w-0 flex-1 truncate'>{renderOption ? renderOption(option) : option.label}</span>\n </button>\n )\n })}\n\n {showCreateOption && (\n <button\n aria-selected={createOptionIndex === highlightedIndex}\n className={cn(getOptionClasses(isCreating, createOptionIndex === highlightedIndex, false), 'gap-2 text-left text-accent font-medium')}\n data-highlighted={createOptionIndex === highlightedIndex ? '' : undefined}\n data-index={createOptionIndex}\n data-testid='spectral-input-search-create-option'\n disabled={isCreating}\n id={`${fieldId}-option-${createOptionIndex}`}\n onMouseDown={(event) => {\n event.preventDefault()\n commitCreate()\n }}\n onMouseEnter={() => setHighlightedIndex(createOptionIndex)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n {isCreating ? (\n <span className='gap-2 flex items-center'>\n <LoaderIcon className='shrink-0 motion-safe:animate-spin' size={16} />\n <span>{creatingLabel}</span>\n </span>\n ) : (\n <span className='gap-2 flex items-center min-w-0'>{createOptionLabel(trimmedQuery)}</span>\n )}\n </button>\n )}\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n\n <ErrorMessage\n dataTestId='spectral-input-search-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-input-search-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nInputSearch.displayName = 'InputSearch'\n"],"mappings":"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"}
1
+ {"version":3,"file":"InputSearch.js","names":[],"sources":["../src/components/InputSearch/InputSearch.tsx"],"sourcesContent":["import { CloseCircleIcon, ErrorIcon, LoaderIcon, PlusIcon, SearchIcon, WarningIcon } from '@components/Icons'\nimport { Label } from '@components/Label/Label'\nimport { useUncontrolledState } from '@hooks/useUncontrolledState'\nimport { useAutoDropdownHorizontalShift } from '@utils/dropdownPositioning'\nimport {\n EmptyState,\n ErrorMessage,\n WarningMessage,\n getAriaProps,\n getDropdownSurfaceClasses,\n getDropdownWidthStyles,\n getErrorMessageId,\n getFormFieldCSSProperties,\n getInputClasses,\n getOptionClasses,\n getPasswordManagerIgnoreProps,\n getWarningMessageId,\n useFormFieldId,\n useFormFieldState,\n type BaseFormFieldProps,\n type BaseOption,\n type DropdownWidth,\n type FormFieldState,\n} from '@utils/formFieldUtils'\nimport { cn } from '@utils/twUtils'\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent, type ReactNode, type Ref } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport type InputSearchOption = BaseOption\n\nexport interface InputSearchProps extends Omit<BaseFormFieldProps, 'onChange' | 'state'> {\n className?: string\n createOptionLabel?: (query: string) => ReactNode\n creatingLabel?: string\n defaultValue?: string\n dropdownWidth?: DropdownWidth\n emptyMessage?: string\n hideSearchIcon?: boolean\n isCreating?: boolean\n labelClassName?: string\n onChange?: (value: string) => void\n onCreate?: (query: string) => void\n onValueChange?: (value: string) => void\n openOnFocus?: boolean\n options: InputSearchOption[]\n placeholder?: string\n renderOption?: (option: InputSearchOption) => ReactNode\n state?: Exclude<FormFieldState, 'disabled'>\n value?: string\n warningMessage?: BaseFormFieldProps['errorMessage']\n}\n\nconst defaultCreateOptionLabel = (query: string): ReactNode => (\n <>\n <PlusIcon size={16} className='shrink-0' />\n <span className='truncate'>\n Create <span className='font-semibold'>&ldquo;{query}&rdquo;</span>\n </span>\n </>\n)\n\nexport const InputSearch = ({\n className,\n createOptionLabel = defaultCreateOptionLabel,\n creatingLabel = 'Creating…',\n defaultValue = '',\n disabled,\n dropdownWidth = 'trigger',\n emptyMessage = 'No options found',\n errorMessage,\n hideSearchIcon = false,\n id,\n isCreating = false,\n label,\n labelClassName,\n messageReserveLines = 1,\n messageReserveSpace = false,\n name,\n onChange,\n onCreate,\n onValueChange,\n openOnFocus = false,\n options,\n placeholder = 'Search…',\n ref,\n renderOption,\n required,\n state = 'default',\n value: valueProp,\n warningMessage,\n 'aria-describedby': ariaDescribedBy,\n 'aria-label': ariaLabel,\n}: InputSearchProps & { ref?: Ref<HTMLDivElement> }) => {\n if (process.env.NODE_ENV !== 'production' && !label && !ariaLabel) {\n // eslint-disable-next-line no-console\n console.warn('InputSearch: provide either `label` or `aria-label` for an accessible name.')\n }\n\n const fieldId = useFormFieldId(id, name)\n const listboxId = `${fieldId}-listbox`\n const errorMessageId = getErrorMessageId(fieldId)\n const warningMessageId = getWarningMessageId(fieldId)\n const messageId = state === 'error' ? errorMessageId : state === 'warning' && warningMessage ? warningMessageId : undefined\n const { isDisabled, isLoading, isInvalid } = useFormFieldState(disabled, state)\n const ariaProps = getAriaProps(state, ariaDescribedBy, required, messageId)\n\n const [value, setValue] = useUncontrolledState<string>({\n value: valueProp,\n defaultValue,\n onChange: (nextValue) => {\n if (onChange) {\n onChange(nextValue)\n } else {\n onValueChange?.(nextValue)\n }\n },\n })\n\n const [query, setQuery] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [highlightedIndex, setHighlightedIndex] = useState(-1)\n const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number; width: number } | null>(null)\n const inputRef = useRef<HTMLInputElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n const blurTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const triggerRef = useRef<HTMLDivElement>(null)\n\n const selectedOption = useMemo(() => options.find((option) => option.value === value) ?? null, [options, value])\n\n useEffect(() => {\n if (!isFocused) {\n setQuery(selectedOption?.label ?? '')\n }\n }, [selectedOption, isFocused])\n\n const trimmedQuery = query.trim()\n\n const filteredOptions = useMemo(() => {\n if (trimmedQuery.length === 0) return options\n const lower = trimmedQuery.toLowerCase()\n return options.filter((option) => option.label.toLowerCase().includes(lower))\n }, [trimmedQuery, options])\n\n const exactMatch = useMemo(() => options.some((option) => option.label.toLowerCase() === trimmedQuery.toLowerCase()), [options, trimmedQuery])\n\n const showCreateOption = onCreate !== undefined && trimmedQuery.length > 0 && !exactMatch\n const createOptionIndex = showCreateOption ? filteredOptions.length : -1\n const totalItems = filteredOptions.length + (showCreateOption ? 1 : 0)\n const showDropdown = isFocused && !isDisabled && !isLoading && (openOnFocus || trimmedQuery.length > 0)\n const showEmptyState = showDropdown && totalItems === 0\n\n const { dropdownShiftStyle, recalculateDropdownPosition, setDropdownElement } = useAutoDropdownHorizontalShift(showDropdown)\n\n const updateDropdownPosition = useCallback(() => {\n const trigger = triggerRef.current\n if (!trigger) return\n const rect = trigger.getBoundingClientRect()\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width,\n })\n recalculateDropdownPosition()\n }, [recalculateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) {\n setDropdownPosition(null)\n return\n }\n updateDropdownPosition()\n const handle = () => updateDropdownPosition()\n window.addEventListener('scroll', handle, true)\n window.addEventListener('resize', handle)\n return () => {\n window.removeEventListener('scroll', handle, true)\n window.removeEventListener('resize', handle)\n }\n }, [showDropdown, updateDropdownPosition])\n\n useLayoutEffect(() => {\n if (!showDropdown) return\n updateDropdownPosition()\n }, [showDropdown, updateDropdownPosition, filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n setHighlightedIndex(-1)\n }, [filteredOptions.length, showCreateOption])\n\n useEffect(() => {\n if (highlightedIndex < 0 || !listRef.current) return\n const element = listRef.current.querySelector<HTMLElement>(`[data-index='${highlightedIndex}']`)\n element?.scrollIntoView({ block: 'nearest' })\n }, [highlightedIndex])\n\n useEffect(\n () => () => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n },\n [],\n )\n\n const commitSelection = useCallback(\n (option: InputSearchOption) => {\n if (option.disabled) return\n setValue(option.value)\n setQuery(option.label)\n setIsFocused(false)\n setHighlightedIndex(-1)\n inputRef.current?.blur()\n },\n [setValue],\n )\n\n const commitCreate = useCallback(() => {\n if (!onCreate || isCreating || trimmedQuery.length === 0) return\n onCreate(trimmedQuery)\n }, [onCreate, isCreating, trimmedQuery])\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case 'ArrowDown': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev < totalItems - 1 ? prev + 1 : prev))\n break\n }\n case 'ArrowUp': {\n if (totalItems === 0) return\n event.preventDefault()\n setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : 0))\n break\n }\n case 'Enter': {\n if (totalItems === 0) return\n event.preventDefault()\n if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {\n const option = filteredOptions[highlightedIndex]\n if (option) commitSelection(option)\n } else if (highlightedIndex === createOptionIndex && !isCreating) {\n commitCreate()\n }\n break\n }\n case 'Escape': {\n event.preventDefault()\n setIsFocused(false)\n setHighlightedIndex(-1)\n if (selectedOption) setQuery(selectedOption.label)\n inputRef.current?.blur()\n break\n }\n default:\n break\n }\n },\n [totalItems, filteredOptions, highlightedIndex, createOptionIndex, commitSelection, commitCreate, isCreating, selectedOption],\n )\n\n const handleFocus = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n blurTimeoutRef.current = null\n }\n setIsFocused(true)\n setQuery('')\n }, [])\n\n const handleBlur = useCallback(() => {\n if (blurTimeoutRef.current !== null) {\n clearTimeout(blurTimeoutRef.current)\n }\n blurTimeoutRef.current = setTimeout(() => {\n blurTimeoutRef.current = null\n // Don't write to `query` here — the useEffect tied to selectedOption + isFocused\n // is the single source of truth for the visible query when the field isn't focused.\n // Setting it from this stale closure causes off-by-one display after selection.\n setIsFocused(false)\n setHighlightedIndex(-1)\n }, 150)\n }, [])\n\n const handleClear = useCallback(() => {\n setValue('')\n setQuery('')\n inputRef.current?.focus()\n }, [setValue])\n\n const showClearButton = !isLoading && !isDisabled && (value.length > 0 || (isFocused && query.length > 0))\n\n const { dropdownWidthMode, dropdownWidthStyle } = getDropdownWidthStyles({\n dropdownWidth,\n triggerWidth: '100%',\n })\n\n const inputClasses = cn(getInputClasses(state, className), 'pe-4', !hideSearchIcon && 'ps-11', showClearButton && 'pe-10!', state === 'loading' && 'cursor-wait')\n\n return (\n <div className='flex w-full flex-col' data-testid='spectral-input-search-container' ref={ref}>\n {label && (\n <Label className={cn('mb-2 block', labelClassName, isDisabled && 'cursor-not-allowed text-input-text--disabled')} data-testid='spectral-input-search-label' htmlFor={fieldId}>\n {label}\n </Label>\n )}\n\n <div className='relative' data-testid='spectral-input-search-wrapper' ref={triggerRef}>\n <div className='relative'>\n {!hideSearchIcon && (\n <span aria-hidden='true' className={cn('left-4 text-input-icon absolute top-1/2 -translate-y-1/2', isDisabled && 'text-input-text--disabled')} data-testid='spectral-input-search-icon'>\n <SearchIcon size={20} />\n </span>\n )}\n\n <input\n aria-activedescendant={highlightedIndex >= 0 ? `${fieldId}-option-${highlightedIndex}` : undefined}\n aria-autocomplete='list'\n aria-controls={listboxId}\n aria-expanded={showDropdown}\n // oxlint-disable-next-line jsx-a11y/role-supports-aria-props -- Valid per WAI-ARIA 1.2 Combobox pattern\n aria-haspopup='listbox'\n aria-label={ariaLabel ?? label}\n autoComplete='off'\n className={inputClasses}\n data-state={state}\n data-testid='spectral-input-search'\n disabled={isDisabled || isLoading}\n id={fieldId}\n name={name}\n onBlur={handleBlur}\n onChange={(event) => {\n setQuery(event.target.value)\n if (!isFocused) setIsFocused(true)\n }}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n ref={inputRef}\n required={required}\n role='combobox'\n style={getFormFieldCSSProperties() as CSSProperties}\n type='text'\n value={query}\n {...getPasswordManagerIgnoreProps('text')}\n {...ariaProps}\n />\n\n {showClearButton ? (\n <button\n aria-label={`Clear ${label ?? 'search'}`}\n className='right-4 text-input-icon hover:text-input-icon--hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-input-border--focus rounded-sm absolute top-1/2 -translate-y-1/2 cursor-pointer'\n data-testid='spectral-input-search-clear-button'\n onClick={handleClear}\n // Prevent input blur from firing before click resolves\n onMouseDown={(event) => event.preventDefault()}\n type='button'\n >\n <CloseCircleIcon size={20} />\n </button>\n ) : state === 'loading' ? (\n <div className='right-4 text-input-icon absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-loading-icon'>\n <LoaderIcon className='motion-safe:animate-spin' size={20} />\n </div>\n ) : state === 'error' ? (\n <div className='right-4 text-danger-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-error-icon'>\n <ErrorIcon size={20} />\n </div>\n ) : state === 'warning' ? (\n <div className='right-4 text-warning-400 absolute top-1/2 -translate-y-1/2' data-testid='spectral-input-search-warning-icon'>\n <WarningIcon size={20} />\n </div>\n ) : null}\n </div>\n\n </div>\n\n {showDropdown && dropdownPosition && typeof document !== 'undefined'\n ? createPortal(\n <div\n className={cn('origin-top p-1 z-50 fixed', getDropdownSurfaceClasses(), 'max-h-72 overflow-hidden', 'motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 motion-safe:slide-in-from-top-2')}\n data-dropdown-width-mode={dropdownWidthMode}\n data-dropdown-width-value={dropdownWidthMode === 'custom' ? dropdownWidth : undefined}\n data-testid='spectral-input-search-content'\n ref={setDropdownElement}\n style={{\n top: `${dropdownPosition.top}px`,\n left: `${dropdownPosition.left}px`,\n ...(dropdownWidthMode === 'trigger' ? { width: `${dropdownPosition.width}px` } : (dropdownWidthStyle as CSSProperties)),\n ...dropdownShiftStyle,\n }}\n >\n <div\n className='max-h-[17.5rem] overflow-y-auto'\n id={listboxId}\n ref={listRef}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- WAI-ARIA combobox pattern requires role='listbox' on the popup\n role='listbox'\n >\n {showEmptyState ? (\n <EmptyState message={emptyMessage} />\n ) : (\n <>\n {filteredOptions.map((option, index) => {\n const isHighlighted = index === highlightedIndex\n const isSelected = option.value === value\n return (\n <button\n aria-selected={isSelected}\n className={cn(getOptionClasses(!!option.disabled, isHighlighted, isSelected), 'text-left')}\n data-highlighted={isHighlighted ? '' : undefined}\n data-index={index}\n data-testid='spectral-input-search-item'\n disabled={option.disabled}\n id={`${fieldId}-option-${index}`}\n key={option.value}\n onMouseDown={(event) => {\n event.preventDefault()\n commitSelection(option)\n }}\n onMouseEnter={() => setHighlightedIndex(index)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n <span className='min-w-0 flex-1 truncate'>{renderOption ? renderOption(option) : option.label}</span>\n </button>\n )\n })}\n\n {showCreateOption && (\n <button\n aria-selected={createOptionIndex === highlightedIndex}\n className={cn(getOptionClasses(isCreating, createOptionIndex === highlightedIndex, false), 'gap-2 text-left text-accent font-medium')}\n data-highlighted={createOptionIndex === highlightedIndex ? '' : undefined}\n data-index={createOptionIndex}\n data-testid='spectral-input-search-create-option'\n disabled={isCreating}\n id={`${fieldId}-option-${createOptionIndex}`}\n onMouseDown={(event) => {\n event.preventDefault()\n commitCreate()\n }}\n onMouseEnter={() => setHighlightedIndex(createOptionIndex)}\n role='option'\n tabIndex={-1}\n type='button'\n >\n {isCreating ? (\n <span className='gap-2 flex items-center'>\n <LoaderIcon className='shrink-0 motion-safe:animate-spin' size={16} />\n <span>{creatingLabel}</span>\n </span>\n ) : (\n <span className='gap-2 flex items-center min-w-0'>{createOptionLabel(trimmedQuery)}</span>\n )}\n </button>\n )}\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n\n <ErrorMessage\n dataTestId='spectral-input-search-error-message'\n id={errorMessageId}\n message={isInvalid ? (errorMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'error'}\n />\n <WarningMessage\n dataTestId='spectral-input-search-warning-message'\n id={warningMessageId}\n message={state === 'warning' ? (warningMessage ?? null) : null}\n messageReserveLines={messageReserveLines}\n messageReserveSpace={messageReserveSpace && state === 'warning'}\n />\n </div>\n )\n}\nInputSearch.displayName = 'InputSearch'\n"],"mappings":"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"}
package/dist/Kbd.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Kbd.d.ts","names":[],"sources":["../src/components/Kbd/Kbd.tsx"],"mappings":";;;;;KAGY,SAAA;AAAA,UAEK,QAAA;EACf,SAAA;EACA,MAAA,GAAS,SAAA;EACT,cAAA;AAAA;AAAA,UAGe,aAAA;EACf,SAAA;AAAA;AAAA;EA2FoB,SAAA;EAAW,MAAA;EAAQ,cAAA;EAA0B,QAAA;EAAA,GAAa;AAAA,GAAS,QAAA,GAAW,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EA4B9F,SAAA;EAAA,GAAc;AAAA,GAAS,aAAA,GAAgB,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"Kbd.d.ts","names":[],"sources":["../src/components/Kbd/Kbd.tsx"],"mappings":";;;;;KAGY,SAAA;AAAA,UAEK,QAAA;EACf,SAAA;EACA,MAAA,GAAS,SAAA;EACT,cAAA;AAAA;AAAA,UAGe,aAAA;EACf,SAAA;AAAA;AAAA;EA2FoB,SAAA;EAAW,MAAA;EAAQ,cAAA;EAA0B,QAAA;EAAA,GAAa;AAAA,GAAS,QAAA,GAAW,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA;;;;EA6B9F,SAAA;EAAA,GAAc;AAAA,GAAS,aAAA,GAAgB,cAAA,UAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
package/dist/Kbd.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Kbd.js","names":[],"sources":["../src/components/Kbd/Kbd.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type KbdSymbol = 'arrowLeft' | 'arrowRight' | 'arrowUp' | 'arrowDown' | 'command' | 'option' | 'shift' | 'control' | 'return' | 'delete'\n\nexport interface KbdProps {\n className?: string\n symbol?: KbdSymbol\n symbolPosition?: 'start' | 'end'\n}\n\nexport interface KbdGroupProps {\n className?: string\n}\n\nconst symbolMap = {\n arrowLeft: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M10 5.75L3.75 12L10 18.25M4.5 12H20.25' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowRight: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M14 5.75L20.25 12L14 18.25M19.5 12H3.75' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowUp: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M5.75 10L12 3.75L18.25 10M12 20.25V4.5' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowDown: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M18 14L12 20L6 14M12 19V4' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n command: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M9.25 9.25V6.5C9.25 4.98122 8.01878 3.75 6.5 3.75C4.98122 3.75 3.75 4.98122 3.75 6.5C3.75 8.01878 4.98122 9.25 6.5 9.25H9.25ZM9.25 9.25H14.75M9.25 9.25V14.75M14.75 9.25V6.5C14.75 4.98122 15.9812 3.75 17.5 3.75C19.0188 3.75 20.25 4.98122 20.25 6.5C20.25 8.01878 19.0188 9.25 17.5 9.25H14.75ZM14.75 9.25V14.75M14.75 14.75H9.25M14.75 14.75V17.5C14.75 19.0188 15.9812 20.25 17.5 20.25C19.0188 20.25 20.25 19.0188 20.25 17.5C20.25 15.9812 19.0188 14.75 17.5 14.75H14.75ZM9.25 14.75V17.5C9.25 19.0188 8.01878 20.25 6.5 20.25C4.98122 20.25 3.75 19.0188 3.75 17.5C3.75 15.9812 4.98122 14.75 6.5 14.75H9.25Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='square'\n />\n </svg>\n ),\n option: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M3.75 4.75H7.40962C7.77384 4.75 8.10925 4.94802 8.2852 5.26692L15.7148 18.7331C15.8907 19.052 16.2262 19.25 16.5904 19.25H20.25M15.75 4.75H20.25' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n shift: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M2.91032 11.5511L11.2848 2.98182C11.6771 2.5804 12.3229 2.5804 12.7152 2.98182L21.0897 11.5511C21.7085 12.1843 21.2599 13.25 20.3745 13.25H17.1316V19.25C17.1316 19.8023 16.6839 20.25 16.1316 20.25H7.86842C7.31614 20.25 6.86842 19.8023 6.86842 19.25V13.25H3.62551C2.74013 13.25 2.2915 12.1843 2.91032 11.5511Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='square'\n strokeLinejoin='round'\n />\n </svg>\n ),\n control: (\n <svg className='-translate-y-0.5' width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M8 13.9999L11.6464 10.3535C11.8417 10.1582 12.1583 10.1582 12.3536 10.3535L16 13.9999' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n return: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n fillRule='evenodd'\n clipRule='evenodd'\n d='M20.25 4C19.8358 4 19.5 4.33579 19.5 4.75V14.25C19.5 14.3881 19.3881 14.5 19.25 14.5H5.56066L8.28033 11.7803C8.57322 11.4874 8.57322 11.0126 8.28033 10.7197C7.98744 10.4268 7.51256 10.4268 7.21967 10.7197L3.21967 14.7197C2.92678 15.0126 2.92678 15.4874 3.21967 15.7803L7.21967 19.7803C7.51256 20.0732 7.98744 20.0732 8.28033 19.7803C8.57322 19.4874 8.57322 19.0126 8.28033 18.7197L5.56066 16H19.25C20.2165 16 21 15.2165 21 14.25V4.75C21 4.33579 20.6642 4 20.25 4Z'\n fill='currentColor'\n />\n </svg>\n ),\n delete: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M14.9988 9.75L12.7488 12M12.7488 12L10.4988 14.25M12.7488 12L10.4988 9.75M12.7488 12L14.9988 14.25M6.55509 4.75H20.2488C20.8011 4.75 21.2488 5.19772 21.2488 5.75V18.25C21.2488 18.8023 20.8011 19.25 20.2488 19.25H6.55509C6.2092 19.25 5.88786 19.0712 5.70545 18.7774L1.82614 12.5274C1.62566 12.2044 1.62566 11.7956 1.82614 11.4726L5.70545 5.22264C5.88786 4.92875 6.2092 4.75 6.55509 4.75Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n </svg>\n ),\n} as const\n\nconst symbolLabelMap: Record<KbdSymbol, string> = {\n arrowLeft: 'Left Arrow',\n arrowRight: 'Right Arrow',\n arrowUp: 'Up Arrow',\n arrowDown: 'Down Arrow',\n command: 'Command',\n option: 'Option',\n shift: 'Shift',\n control: 'Control',\n return: 'Return',\n delete: 'Delete',\n}\n\nexport const Kbd = ({ className, symbol, symbolPosition = 'start', children, ...props }: KbdProps & ComponentProps<'kbd'>) => {\n const hasChildren = children !== undefined && children !== null && children !== ''\n const symbolElement = symbol && <span aria-hidden='true'>{symbolMap[symbol]}</span>\n\n // Derive aria-label from symbol when no children are provided, unless explicitly overridden\n const derivedAriaLabel = !hasChildren && symbol ? symbolLabelMap[symbol] : undefined\n const ariaLabel = props['aria-label'] ?? derivedAriaLabel\n\n return (\n <kbd\n className={cn(\n 'h-5 min-w-5 gap-1 rounded-sm px-1 text-xs font-medium pointer-events-none inline-flex w-fit items-center justify-center bg-kbd-bg font-mono! text-kbd-text select-none',\n `[&_svg:not([class*='size-'])]:size-3 in-data-[slot=tooltip-content]:bg-level-three`,\n className,\n )}\n data-slot='kbd'\n data-testid='spectral-kbd'\n {...props}\n aria-label={ariaLabel}\n >\n {symbolPosition === 'start' && symbolElement}\n {children}\n {symbolPosition === 'end' && symbolElement}\n </kbd>\n )\n}\nKbd.displayName = 'Kbd'\n\nexport const KbdGroup = ({ className, ...props }: KbdGroupProps & ComponentProps<'kbd'>) => {\n return <kbd className={cn('gap-1 inline-flex items-center', className)} data-slot='kbd-group' data-testid='spectral-kbd-group' {...props} />\n}\nKbdGroup.displayName = 'KbdGroup'\n"],"mappings":"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"}
1
+ {"version":3,"file":"Kbd.js","names":[],"sources":["../src/components/Kbd/Kbd.tsx"],"sourcesContent":["import { cn } from '@utils/twUtils'\nimport { type ComponentProps } from 'react'\n\nexport type KbdSymbol = 'arrowLeft' | 'arrowRight' | 'arrowUp' | 'arrowDown' | 'command' | 'option' | 'shift' | 'control' | 'return' | 'delete'\n\nexport interface KbdProps {\n className?: string\n symbol?: KbdSymbol\n symbolPosition?: 'start' | 'end'\n}\n\nexport interface KbdGroupProps {\n className?: string\n}\n\nconst symbolMap = {\n arrowLeft: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M10 5.75L3.75 12L10 18.25M4.5 12H20.25' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowRight: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M14 5.75L20.25 12L14 18.25M19.5 12H3.75' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowUp: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M5.75 10L12 3.75L18.25 10M12 20.25V4.5' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n arrowDown: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M18 14L12 20L6 14M12 19V4' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n command: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M9.25 9.25V6.5C9.25 4.98122 8.01878 3.75 6.5 3.75C4.98122 3.75 3.75 4.98122 3.75 6.5C3.75 8.01878 4.98122 9.25 6.5 9.25H9.25ZM9.25 9.25H14.75M9.25 9.25V14.75M14.75 9.25V6.5C14.75 4.98122 15.9812 3.75 17.5 3.75C19.0188 3.75 20.25 4.98122 20.25 6.5C20.25 8.01878 19.0188 9.25 17.5 9.25H14.75ZM14.75 9.25V14.75M14.75 14.75H9.25M14.75 14.75V17.5C14.75 19.0188 15.9812 20.25 17.5 20.25C19.0188 20.25 20.25 19.0188 20.25 17.5C20.25 15.9812 19.0188 14.75 17.5 14.75H14.75ZM9.25 14.75V17.5C9.25 19.0188 8.01878 20.25 6.5 20.25C4.98122 20.25 3.75 19.0188 3.75 17.5C3.75 15.9812 4.98122 14.75 6.5 14.75H9.25Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='square'\n />\n </svg>\n ),\n option: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M3.75 4.75H7.40962C7.77384 4.75 8.10925 4.94802 8.2852 5.26692L15.7148 18.7331C15.8907 19.052 16.2262 19.25 16.5904 19.25H20.25M15.75 4.75H20.25' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n shift: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M2.91032 11.5511L11.2848 2.98182C11.6771 2.5804 12.3229 2.5804 12.7152 2.98182L21.0897 11.5511C21.7085 12.1843 21.2599 13.25 20.3745 13.25H17.1316V19.25C17.1316 19.8023 16.6839 20.25 16.1316 20.25H7.86842C7.31614 20.25 6.86842 19.8023 6.86842 19.25V13.25H3.62551C2.74013 13.25 2.2915 12.1843 2.91032 11.5511Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='square'\n strokeLinejoin='round'\n />\n </svg>\n ),\n control: (\n <svg className='-translate-y-0.5' width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path d='M8 13.9999L11.6464 10.3535C11.8417 10.1582 12.1583 10.1582 12.3536 10.3535L16 13.9999' stroke='currentColor' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round' />\n </svg>\n ),\n return: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n fillRule='evenodd'\n clipRule='evenodd'\n d='M20.25 4C19.8358 4 19.5 4.33579 19.5 4.75V14.25C19.5 14.3881 19.3881 14.5 19.25 14.5H5.56066L8.28033 11.7803C8.57322 11.4874 8.57322 11.0126 8.28033 10.7197C7.98744 10.4268 7.51256 10.4268 7.21967 10.7197L3.21967 14.7197C2.92678 15.0126 2.92678 15.4874 3.21967 15.7803L7.21967 19.7803C7.51256 20.0732 7.98744 20.0732 8.28033 19.7803C8.57322 19.4874 8.57322 19.0126 8.28033 18.7197L5.56066 16H19.25C20.2165 16 21 15.2165 21 14.25V4.75C21 4.33579 20.6642 4 20.25 4Z'\n fill='currentColor'\n />\n </svg>\n ),\n delete: (\n <svg width='14' height='14' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'>\n <path\n d='M14.9988 9.75L12.7488 12M12.7488 12L10.4988 14.25M12.7488 12L10.4988 9.75M12.7488 12L14.9988 14.25M6.55509 4.75H20.2488C20.8011 4.75 21.2488 5.19772 21.2488 5.75V18.25C21.2488 18.8023 20.8011 19.25 20.2488 19.25H6.55509C6.2092 19.25 5.88786 19.0712 5.70545 18.7774L1.82614 12.5274C1.62566 12.2044 1.62566 11.7956 1.82614 11.4726L5.70545 5.22264C5.88786 4.92875 6.2092 4.75 6.55509 4.75Z'\n stroke='currentColor'\n strokeWidth='1.5'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n </svg>\n ),\n} as const\n\nconst symbolLabelMap: Record<KbdSymbol, string> = {\n arrowLeft: 'Left Arrow',\n arrowRight: 'Right Arrow',\n arrowUp: 'Up Arrow',\n arrowDown: 'Down Arrow',\n command: 'Command',\n option: 'Option',\n shift: 'Shift',\n control: 'Control',\n return: 'Return',\n delete: 'Delete',\n}\n\nexport const Kbd = ({ className, symbol, symbolPosition = 'start', children, ...props }: KbdProps & ComponentProps<'kbd'>) => {\n const hasChildren = children !== undefined && children !== null && children !== ''\n const symbolElement = symbol && <span aria-hidden='true'>{symbolMap[symbol]}</span>\n\n // Derive aria-label from symbol when no children are provided, unless explicitly overridden\n const derivedAriaLabel = !hasChildren && symbol ? symbolLabelMap[symbol] : undefined\n const ariaLabel = props['aria-label'] ?? derivedAriaLabel\n\n return (\n <kbd\n className={cn(\n 'h-5 min-w-5 gap-1 rounded-sm px-1 text-xs font-medium pointer-events-none inline-flex w-fit items-center justify-center bg-kbd-bg font-mono! text-kbd-text select-none',\n `[&_svg:not([class*='size-'])]:size-3 in-data-[slot=tooltip-content]:bg-level-three`,\n className,\n )}\n data-slot='kbd'\n data-testid='spectral-kbd'\n {...props}\n aria-label={ariaLabel}\n >\n {symbolPosition === 'start' && symbolElement}\n {children}\n {symbolPosition === 'end' && symbolElement}\n </kbd>\n )\n}\n\nKbd.displayName = 'Kbd'\n\nexport const KbdGroup = ({ className, ...props }: KbdGroupProps & ComponentProps<'kbd'>) => {\n return <kbd className={cn('gap-1 inline-flex items-center', className)} data-slot='kbd-group' data-testid='spectral-kbd-group' {...props} />\n}\n\nKbdGroup.displayName = 'KbdGroup'\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelectBase.d.ts","names":[],"sources":["../../src/components/MultiSelect/MultiSelectBase.tsx"],"mappings":";;;;;;KASY,gBAAA,GAAmB,OAAA,CAAQ,cAAA;AAAA,UAEtB,iBAAA;EACf,QAAA;EACA,KAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,UAGe,oBAAA,SAA6B,IAAA,CAAK,oBAAA,CAAqB,iBAAA;EACtE,aAAA;EACA,aAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,YAAA,GAAe,kBAAA;EACf,EAAA;EACA,KAAA;EACA,cAAA;EACA,QAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,YAAA;EACA,QAAA,IAAY,KAAA;EACZ,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,QAAA;EACA,iBAAA;EACA,YAAA;EACA,UAAA;EACA,aAAA;EACA,cAAA;EACA,kBAAA;EACA,KAAA,GAAQ,gBAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;EACjB,YAAA;EACA,kBAAA;AAAA;AAAA;EA6MA,SAAA;EACA,aAAA;EACA,aAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,EAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,iBAAA;EACA,cAAA;EACA,YAAA;EACA,UAAA;EACA,aAAA;EACA,kBAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,cACc,SAAA;EAAA,oBACM,eAAA;EAAA,GACjB;AAAA,GACF,oBAAA;EACD,GAAA,GAAM,GAAA,CAAI,iBAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
1
+ {"version":3,"file":"MultiSelectBase.d.ts","names":[],"sources":["../../src/components/MultiSelect/MultiSelectBase.tsx"],"mappings":";;;;;;KAyBY,gBAAA,GAAmB,OAAA,CAAQ,cAAA;AAAA,UAEtB,iBAAA;EACf,QAAA;EACA,KAAA;EACA,KAAA;EACA,KAAA;AAAA;AAAA,UAGe,oBAAA,SAA6B,IAAA,CAAK,oBAAA,CAAqB,iBAAA;EACtE,aAAA;EACA,aAAA;EACA,aAAA,GAAgB,aAAA;EAChB,YAAA;EACA,YAAA,GAAe,kBAAA;EACf,EAAA;EACA,KAAA;EACA,cAAA;EACA,QAAA;EACA,mBAAA;EACA,mBAAA;EACA,IAAA;EACA,YAAA;EACA,QAAA,IAAY,KAAA;EACZ,OAAA,EAAS,iBAAA;EACT,WAAA;EACA,QAAA;EACA,iBAAA;EACA,YAAA;EACA,UAAA;EACA,aAAA;EACA,cAAA;EACA,kBAAA;EACA,KAAA,GAAQ,gBAAA;EACR,KAAA;EACA,cAAA,GAAiB,kBAAA;EACjB,YAAA;EACA,kBAAA;AAAA;AAAA;EA4MA,SAAA;EACA,aAAA;EACA,aAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;EACA,YAAA;EACA,QAAA;EACA,EAAA;EACA,KAAA;EACA,cAAA;EACA,mBAAA;EACA,mBAAA;EACA,QAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,WAAA;EACA,GAAA;EACA,iBAAA;EACA,cAAA;EACA,YAAA;EACA,UAAA;EACA,aAAA;EACA,kBAAA;EACA,KAAA;EACA,KAAA,EAAO,SAAA;EACP,cAAA;EAAA,cACc,SAAA;EAAA,oBACM,eAAA;EAAA,GACjB;AAAA,GACF,oBAAA;EACD,GAAA,GAAM,GAAA,CAAI,iBAAA;AAAA,IACX,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA"}
@@ -5,7 +5,7 @@ import { CloseIcon } from "../Icons/CloseIcon.js";
5
5
  import { SearchIcon } from "../Icons/SearchIcon.js";
6
6
  import { cn } from "../utils/twUtils.js";
7
7
  import { ErrorMessage, WarningMessage } from "../FormFieldMessage.js";
8
- import { EmptyState, LoadingState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getTriggerClasses, useFormFieldId } from "../utils/formFieldUtils.js";
8
+ import { EmptyState, LoadingState, getAriaProps, getDropdownSurfaceClasses, getDropdownWidthStyles, getErrorMessageId, getPasswordManagerIgnoreProps, getTriggerClasses, getWarningMessageId, useFormFieldId } from "../utils/formFieldUtils.js";
9
9
  import { useUncontrolledState } from "../hooks/useUncontrolledState.js";
10
10
  import { Label } from "../Label.js";
11
11
  import { useAutoDropdownHorizontalShift } from "../utils/dropdownPositioning.js";
@@ -16,7 +16,7 @@ import * as Popover from "@radix-ui/react-popover";
16
16
  //#region src/components/MultiSelect/MultiSelectBase.tsx
17
17
  const ICON_SIZE = "h-4 w-4";
18
18
  const getDropdownClasses = () => {
19
- return cn("max-h-80 z-50 overflow-hidden", getDropdownSurfaceClasses(), "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in", "motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0", "motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95", "motion-safe:data-[side=bottom]:slide-in-from-top-2", "motion-safe:data-[side=top]:slide-in-from-bottom-2", "origin-(--radix-popover-content-transform-origin)");
19
+ return cn("max-h-80 z-50 overflow-hidden", getDropdownSurfaceClasses(), "motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:animate-in", "motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0", "motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95", "motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=top]:slide-in-from-bottom-2", "origin-(--radix-popover-content-transform-origin)");
20
20
  };
21
21
  const useKeyboardNavigation = (options, onClearAll, onClose, onSelect, onSelectAll, searchInputRef, showSearch, showSelectAll, showClearAll) => {
22
22
  const [focusedIndex, setFocusedIndex] = useState(-1);
@@ -136,12 +136,12 @@ const useKeyboardNavigation = (options, onClearAll, onClose, onSelect, onSelectA
136
136
  }, [focusedIndex, focusableItems])
137
137
  };
138
138
  };
139
- const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect = false, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, defaultValue = [], disabled, id, label, loadingMessage = "Loading options…", messageReserveLines = 1, messageReserveSpace = false, maxCount = 3, name, onChange, options = [], placeholder = "Select options", ref, searchPlaceholder = "Search options…", selectAllLabel = "Select all", showClearAll = true, showSearch = true, showSelectAll = true, sortAlphabetically = false, state = "default", value: valueProp, warningMessage, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, ...props }) => {
139
+ const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect = false, dropdownWidth = "trigger", emptyMessage = "No options found", errorMessage, defaultValue = [], disabled, id, label, loadingMessage = "Loading options…", messageReserveLines = 1, messageReserveSpace = false, maxCount = 3, name, onChange, options, placeholder = "Select options", ref, searchPlaceholder = "Search options…", selectAllLabel = "Select all", showClearAll = true, showSearch = true, showSelectAll = true, sortAlphabetically = false, state = "default", value: valueProp, warningMessage, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, ...props }) => {
140
140
  const generatedId = useId();
141
141
  const multiSelectId = useFormFieldId(id, name ?? `multiselect-${generatedId}`);
142
142
  const listboxId = `${multiSelectId}-listbox`;
143
143
  const errorMessageId = getErrorMessageId(multiSelectId);
144
- const warningMessageId = `${multiSelectId}-warning`;
144
+ const warningMessageId = getWarningMessageId(multiSelectId);
145
145
  const messageId = state === "error" ? errorMessageId : state === "warning" && warningMessage ? warningMessageId : void 0;
146
146
  const [isOpen, setIsOpen] = useState(false);
147
147
  const { dropdownShiftStyle, setDropdownElement } = useAutoDropdownHorizontalShift(isOpen);
@@ -368,7 +368,8 @@ const MultiSelectBase = ({ className, clearAllLabel = "Clear all", closeOnSelect
368
368
  placeholder: searchPlaceholder,
369
369
  ref: searchInputRef,
370
370
  type: "text",
371
- value: searchValue
371
+ value: searchValue,
372
+ ...getPasswordManagerIgnoreProps("text")
372
373
  })]
373
374
  }), /* @__PURE__ */ jsx("div", {
374
375
  "aria-multiselectable": "true",