@inzumer/ui-library 1.0.2 → 1.2.0

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 (58) hide show
  1. package/dist/{chunk-HCLY7B4H.js → chunk-2YBZCUME.js} +39 -6
  2. package/dist/chunk-2YBZCUME.js.map +1 -0
  3. package/dist/{chunk-PVDRNAYK.js → chunk-3YRDRHO3.js} +33 -22
  4. package/dist/chunk-3YRDRHO3.js.map +1 -0
  5. package/dist/chunk-53YMHM24.js +20 -0
  6. package/dist/chunk-53YMHM24.js.map +1 -0
  7. package/dist/{chunk-LK2EJ4H6.js → chunk-A26UWAU4.js} +12 -6
  8. package/dist/chunk-A26UWAU4.js.map +1 -0
  9. package/dist/chunk-CX3GARWU.js +142 -0
  10. package/dist/chunk-CX3GARWU.js.map +1 -0
  11. package/dist/chunk-DP274HDM.js +34 -0
  12. package/dist/chunk-DP274HDM.js.map +1 -0
  13. package/dist/chunk-FFKHEBQ7.js +41 -0
  14. package/dist/chunk-FFKHEBQ7.js.map +1 -0
  15. package/dist/chunk-GQMA2AQI.js +3 -0
  16. package/dist/chunk-GQMA2AQI.js.map +1 -0
  17. package/dist/{chunk-KWSZ2S34.js → chunk-KL6I2JFC.js} +44 -13
  18. package/dist/chunk-KL6I2JFC.js.map +1 -0
  19. package/dist/chunk-QT62VC36.js +50 -0
  20. package/dist/chunk-QT62VC36.js.map +1 -0
  21. package/dist/{chunk-K35XIA25.js → chunk-RRIE5LFQ.js} +12 -6
  22. package/dist/chunk-RRIE5LFQ.js.map +1 -0
  23. package/dist/chunk-WUEVXL76.js +91 -0
  24. package/dist/chunk-WUEVXL76.js.map +1 -0
  25. package/dist/components/atoms/Button/index.d.ts +9 -1
  26. package/dist/components/atoms/Button/index.js +3 -1
  27. package/dist/components/atoms/Image/index.d.ts +2 -2
  28. package/dist/components/atoms/Input/index.d.ts +2 -2
  29. package/dist/components/atoms/Input/index.js +2 -1
  30. package/dist/components/atoms/RichText/index.d.ts +2 -2
  31. package/dist/components/atoms/Select/index.d.ts +29 -0
  32. package/dist/components/atoms/Select/index.js +6 -0
  33. package/dist/components/atoms/Select/index.js.map +1 -0
  34. package/dist/components/atoms/Switch/index.d.ts +1 -1
  35. package/dist/components/atoms/Textarea/index.d.ts +28 -0
  36. package/dist/components/atoms/Textarea/index.js +6 -0
  37. package/dist/components/atoms/Textarea/index.js.map +1 -0
  38. package/dist/components/molecules/BottomSheet/index.js +4 -2
  39. package/dist/components/molecules/Drawer/index.d.ts +44 -0
  40. package/dist/components/molecules/Drawer/index.js +11 -0
  41. package/dist/components/molecules/Drawer/index.js.map +1 -0
  42. package/dist/components/molecules/Language/index.d.ts +5 -0
  43. package/dist/components/molecules/Language/index.js +1 -1
  44. package/dist/components/molecules/Modal/index.js +4 -2
  45. package/dist/hooks/useFocusTrap/index.d.ts +9 -0
  46. package/dist/hooks/useFocusTrap/index.js +3 -0
  47. package/dist/hooks/useFocusTrap/index.js.map +1 -0
  48. package/dist/hooks/useScrollLock/index.d.ts +4 -0
  49. package/dist/hooks/useScrollLock/index.js +3 -0
  50. package/dist/hooks/useScrollLock/index.js.map +1 -0
  51. package/dist/index.d.ts +6 -1
  52. package/dist/index.js +16 -9
  53. package/package.json +23 -3
  54. package/dist/chunk-HCLY7B4H.js.map +0 -1
  55. package/dist/chunk-K35XIA25.js.map +0 -1
  56. package/dist/chunk-KWSZ2S34.js.map +0 -1
  57. package/dist/chunk-LK2EJ4H6.js.map +0 -1
  58. package/dist/chunk-PVDRNAYK.js.map +0 -1
@@ -19,10 +19,14 @@ var languageOptionStyles = cva(
19
19
  }
20
20
  }
21
21
  );
22
+ var NEXT_KEYS = /* @__PURE__ */ new Set(["ArrowRight", "ArrowDown"]);
23
+ var PREVIOUS_KEYS = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowUp"]);
22
24
  var Language = forwardRef(
23
25
  ({ options, value, onChange, className, ...props }, ref) => {
24
26
  const buttonRefs = useRef(/* @__PURE__ */ new Map());
25
27
  const [indicator, setIndicator] = useState(null);
28
+ const selectedIndex = options.findIndex((option) => option.value === value);
29
+ const focusableIndex = selectedIndex === -1 ? 0 : selectedIndex;
26
30
  useLayoutEffect(() => {
27
31
  const activeButton = buttonRefs.current.get(value);
28
32
  if (!activeButton) {
@@ -35,11 +39,38 @@ var Language = forwardRef(
35
39
  height: activeButton.offsetHeight
36
40
  });
37
41
  }, [value, options]);
42
+ const select = (index) => {
43
+ const option = options[index];
44
+ if (!option) {
45
+ return;
46
+ }
47
+ buttonRefs.current.get(option.value)?.focus();
48
+ if (option.value !== value) {
49
+ onChange(option.value);
50
+ }
51
+ };
52
+ const handleKeyDown = (event) => {
53
+ const last = options.length - 1;
54
+ let target = null;
55
+ if (NEXT_KEYS.has(event.key)) {
56
+ target = focusableIndex === last ? 0 : focusableIndex + 1;
57
+ } else if (PREVIOUS_KEYS.has(event.key)) {
58
+ target = focusableIndex === 0 ? last : focusableIndex - 1;
59
+ } else if (event.key === "Home") {
60
+ target = 0;
61
+ } else if (event.key === "End") {
62
+ target = last;
63
+ }
64
+ if (target !== null) {
65
+ event.preventDefault();
66
+ select(target);
67
+ }
68
+ };
38
69
  return /* @__PURE__ */ jsxs(
39
70
  "div",
40
71
  {
41
72
  ref,
42
- role: "listbox",
73
+ role: "radiogroup",
43
74
  "aria-label": "Language selector",
44
75
  className: cn(languageStyles, className),
45
76
  ...props,
@@ -56,7 +87,7 @@ var Language = forwardRef(
56
87
  }
57
88
  }
58
89
  ),
59
- options.map((option) => {
90
+ options.map((option, index) => {
60
91
  const selected = option.value === value;
61
92
  return /* @__PURE__ */ jsx(
62
93
  "button",
@@ -69,9 +100,11 @@ var Language = forwardRef(
69
100
  }
70
101
  },
71
102
  type: "button",
72
- role: "option",
73
- "aria-selected": selected,
103
+ role: "radio",
104
+ "aria-checked": selected,
105
+ tabIndex: index === focusableIndex ? 0 : -1,
74
106
  onClick: () => onChange(option.value),
107
+ onKeyDown: handleKeyDown,
75
108
  className: languageOptionStyles({ selected }),
76
109
  children: option.label
77
110
  },
@@ -86,5 +119,5 @@ var Language = forwardRef(
86
119
  Language.displayName = "Language";
87
120
 
88
121
  export { Language };
89
- //# sourceMappingURL=chunk-HCLY7B4H.js.map
90
- //# sourceMappingURL=chunk-HCLY7B4H.js.map
122
+ //# sourceMappingURL=chunk-2YBZCUME.js.map
123
+ //# sourceMappingURL=chunk-2YBZCUME.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/molecules/Language/Language.styles.ts","../src/components/molecules/Language/Language.tsx"],"names":[],"mappings":"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","file":"chunk-2YBZCUME.js","sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const languageStyles =\n 'relative inline-flex items-center gap-1 rounded-md border border-[var(--border-default)] bg-[var(--surface-secondary)] p-1';\n\nexport const languageIndicatorStyles =\n 'absolute left-0 top-0 rounded bg-[var(--btn-primary-bg)] transition-[transform,width,height] duration-200 ease-out';\n\nexport const languageOptionStyles = cva(\n 'relative z-10 rounded px-2.5 py-1 text-xs font-semibold uppercase transition-colors duration-200 ease-out',\n {\n variants: {\n selected: {\n true: 'text-[var(--btn-primary-text)]',\n false: 'text-[var(--text-secondary)] hover:text-[var(--text-primary)]',\n },\n },\n defaultVariants: {\n selected: false,\n },\n },\n);\n","import { cn } from '@utils';\nimport {\n forwardRef,\n useLayoutEffect,\n useRef,\n useState,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react';\nimport { languageIndicatorStyles, languageOptionStyles, languageStyles } from './Language.styles';\n\nexport interface LanguageOption {\n value: string;\n label: string;\n}\n\nexport type LanguageProps = Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> & {\n options: LanguageOption[];\n value: string;\n onChange: (value: string) => void;\n};\n\ntype IndicatorRect = { left: number; top: number; width: number; height: number };\n\nconst NEXT_KEYS = new Set(['ArrowRight', 'ArrowDown']);\nconst PREVIOUS_KEYS = new Set(['ArrowLeft', 'ArrowUp']);\n\n/**\n * Single-choice segmented switch, following the WAI-ARIA radio group pattern: one Tab stop,\n * arrow keys (and Home/End) move the selection. Name it with `aria-label` (defaults to\n * \"Language selector\") or `aria-labelledby`.\n */\nexport const Language = forwardRef<HTMLDivElement, LanguageProps>(\n ({ options, value, onChange, className, ...props }, ref) => {\n const buttonRefs = useRef(new Map<string, HTMLButtonElement>());\n const [indicator, setIndicator] = useState<IndicatorRect | null>(null);\n const selectedIndex = options.findIndex((option) => option.value === value);\n const focusableIndex = selectedIndex === -1 ? 0 : selectedIndex;\n\n useLayoutEffect(() => {\n const activeButton = buttonRefs.current.get(value);\n if (!activeButton) {\n return;\n }\n\n setIndicator({\n left: activeButton.offsetLeft,\n top: activeButton.offsetTop,\n width: activeButton.offsetWidth,\n height: activeButton.offsetHeight,\n });\n }, [value, options]);\n\n const select = (index: number) => {\n const option = options[index];\n if (!option) {\n return;\n }\n buttonRefs.current.get(option.value)?.focus();\n if (option.value !== value) {\n onChange(option.value);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n const last = options.length - 1;\n let target: number | null = null;\n if (NEXT_KEYS.has(event.key)) {\n target = focusableIndex === last ? 0 : focusableIndex + 1;\n } else if (PREVIOUS_KEYS.has(event.key)) {\n target = focusableIndex === 0 ? last : focusableIndex - 1;\n } else if (event.key === 'Home') {\n target = 0;\n } else if (event.key === 'End') {\n target = last;\n }\n if (target !== null) {\n event.preventDefault();\n select(target);\n }\n };\n\n return (\n <div\n ref={ref}\n role=\"radiogroup\"\n aria-label=\"Language selector\"\n className={cn(languageStyles, className)}\n {...props}\n >\n {indicator && (\n <span\n aria-hidden\n className={languageIndicatorStyles}\n style={{\n width: indicator.width,\n height: indicator.height,\n transform: `translate(${indicator.left}px, ${indicator.top}px)`,\n }}\n />\n )}\n {options.map((option, index) => {\n const selected = option.value === value;\n\n return (\n <button\n key={option.value}\n ref={(node) => {\n if (node) {\n buttonRefs.current.set(option.value, node);\n } else {\n buttonRefs.current.delete(option.value);\n }\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n tabIndex={index === focusableIndex ? 0 : -1}\n onClick={() => onChange(option.value)}\n onKeyDown={handleKeyDown}\n className={languageOptionStyles({ selected })}\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n },\n);\n\nLanguage.displayName = 'Language';\n"]}
@@ -1,21 +1,20 @@
1
+ import { inputLabelStyles, inputErrorStyles, inputHintStyles } from './chunk-FFKHEBQ7.js';
1
2
  import { RichText } from './chunk-P4CV2EPR.js';
2
3
  import { cn } from './chunk-6LLGTBM6.js';
3
4
  import { forwardRef, useId } from 'react';
4
5
  import { cva } from 'class-variance-authority';
5
6
  import { jsxs, jsx } from 'react/jsx-runtime';
6
7
 
7
- var inputStyles = cva(
8
+ var textareaStyles = cva(
8
9
  [
9
- "flex w-full rounded-md px-3 py-2",
10
- "text-sm text-[var(--input-text)]",
11
- "bg-[var(--input-bg)]",
10
+ "flex min-h-24 w-full rounded-md px-3 py-2",
11
+ "text-[var(--input-text)] bg-[var(--input-bg)]",
12
12
  "border border-[var(--input-border)]",
13
13
  "placeholder:text-[var(--input-placeholder)]",
14
14
  "transition-colors duration-150 ease-in-out",
15
15
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-0",
16
16
  "focus-visible:border-[var(--input-border-focus)]",
17
- "disabled:cursor-not-allowed disabled:opacity-50",
18
- "file:border-0 file:bg-transparent file:text-sm file:font-medium"
17
+ "disabled:cursor-not-allowed disabled:opacity-50"
19
18
  ],
20
19
  {
21
20
  variants: {
@@ -24,45 +23,57 @@ var inputStyles = cva(
24
23
  error: "border-[var(--input-border-error)] focus-visible:ring-[var(--border-error)]"
25
24
  },
26
25
  inputSize: {
27
- sm: "h-8 px-2 text-xs",
28
- md: "h-10 px-3 text-sm",
29
- lg: "h-12 px-4 text-base"
26
+ sm: "text-xs",
27
+ md: "text-sm",
28
+ lg: "text-base"
29
+ },
30
+ resize: {
31
+ vertical: "resize-y",
32
+ none: "resize-none"
30
33
  }
31
34
  },
32
35
  defaultVariants: {
33
36
  state: "default",
34
- inputSize: "md"
37
+ inputSize: "md",
38
+ resize: "vertical"
35
39
  }
36
40
  }
37
41
  );
38
- var inputLabelStyles = "text-sm font-medium text-[var(--text-primary)]";
39
- var inputErrorStyles = "text-xs text-[var(--border-error)]";
40
- var inputHintStyles = "text-xs text-[var(--text-secondary)]";
41
- var Input = forwardRef(
42
- ({ className, state, inputSize, label, hint, error, id: idProp, ...props }, ref) => {
42
+ var Textarea = forwardRef(
43
+ ({ className, state, inputSize, resize, label, hint, error, id: idProp, ...props }, ref) => {
43
44
  const generatedId = useId();
44
45
  const id = idProp ?? generatedId;
45
46
  const resolvedState = error ? "error" : state;
46
47
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
47
48
  label && /* @__PURE__ */ jsx("label", { htmlFor: id, children: /* @__PURE__ */ jsx(RichText, { as: "span", variant: "p3", className: inputLabelStyles, children: label }) }),
48
49
  /* @__PURE__ */ jsx(
49
- "input",
50
+ "textarea",
50
51
  {
51
52
  ref,
52
53
  id,
53
54
  "aria-describedby": error ? `${id}-error` : hint ? `${id}-hint` : void 0,
54
55
  "aria-invalid": error ? "true" : void 0,
55
- className: cn(inputStyles({ state: resolvedState, inputSize }), className),
56
+ className: cn(textareaStyles({ state: resolvedState, inputSize, resize }), className),
56
57
  ...props
57
58
  }
58
59
  ),
59
- error && /* @__PURE__ */ jsx(RichText, { as: "p", id: `${id}-error`, role: "alert", variant: "p4", className: inputErrorStyles, children: error }),
60
+ error && /* @__PURE__ */ jsx(
61
+ RichText,
62
+ {
63
+ as: "p",
64
+ id: `${id}-error`,
65
+ role: "alert",
66
+ variant: "p4",
67
+ className: inputErrorStyles,
68
+ children: error
69
+ }
70
+ ),
60
71
  !error && hint && /* @__PURE__ */ jsx(RichText, { as: "p", id: `${id}-hint`, variant: "p4", className: inputHintStyles, children: hint })
61
72
  ] });
62
73
  }
63
74
  );
64
- Input.displayName = "Input";
75
+ Textarea.displayName = "Textarea";
65
76
 
66
- export { Input };
67
- //# sourceMappingURL=chunk-PVDRNAYK.js.map
68
- //# sourceMappingURL=chunk-PVDRNAYK.js.map
77
+ export { Textarea };
78
+ //# sourceMappingURL=chunk-3YRDRHO3.js.map
79
+ //# sourceMappingURL=chunk-3YRDRHO3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/atoms/Textarea/Textarea.styles.ts","../src/components/atoms/Textarea/Textarea.tsx"],"names":[],"mappings":";;;;;;;AAEO,IAAM,cAAA,GAAiB,GAAA;AAAA,EAC5B;AAAA,IACE,2CAAA;AAAA,IACA,+CAAA;AAAA,IACA,qCAAA;AAAA,IACA,6CAAA;AAAA,IACA,4CAAA;AAAA,IACA,sHAAA;AAAA,IACA,kDAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,EAAA;AAAA,QACT,KAAA,EAAO;AAAA,OACT;AAAA,MACA,SAAA,EAAW;AAAA,QACT,EAAA,EAAI,SAAA;AAAA,QACJ,EAAA,EAAI,SAAA;AAAA,QACJ,EAAA,EAAI;AAAA,OACN;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,QAAA,EAAU,UAAA;AAAA,QACV,IAAA,EAAM;AAAA;AACR,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,KAAA,EAAO,SAAA;AAAA,MACP,SAAA,EAAW,IAAA;AAAA,MACX,MAAA,EAAQ;AAAA;AACV;AAEJ,CAAA;AChBO,IAAM,QAAA,GAAW,UAAA;AAAA,EACtB,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,WAAW,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,GAAG,KAAA,IAAS,GAAA,KAAQ;AAC1F,IAAA,MAAM,cAAc,KAAA,EAAM;AAC1B,IAAA,MAAM,KAAK,MAAA,IAAU,WAAA;AACrB,IAAA,MAAM,aAAA,GAAgB,QAAQ,OAAA,GAAU,KAAA;AAExC,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EACZ,QAAA,EAAA;AAAA,MAAA,KAAA,oBACC,GAAA,CAAC,OAAA,EAAA,EAAM,OAAA,EAAS,EAAA,EACd,QAAA,kBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAG,MAAA,EAAO,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,gBAAA,EACzC,iBACH,CAAA,EACF,CAAA;AAAA,sBAEF,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,GAAA;AAAA,UACA,EAAA;AAAA,UACA,kBAAA,EAAkB,QAAQ,CAAA,EAAG,EAAE,WAAW,IAAA,GAAO,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,GAAU,MAAA;AAAA,UAChE,cAAA,EAAc,QAAQ,MAAA,GAAS,MAAA;AAAA,UAC/B,SAAA,EAAW,EAAA,CAAG,cAAA,CAAe,EAAE,KAAA,EAAO,eAAe,SAAA,EAAW,MAAA,EAAQ,CAAA,EAAG,SAAS,CAAA;AAAA,UACnF,GAAG;AAAA;AAAA,OACN;AAAA,MACC,KAAA,oBACC,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,EAAA,EAAG,GAAA;AAAA,UACH,EAAA,EAAI,GAAG,EAAE,CAAA,MAAA,CAAA;AAAA,UACT,IAAA,EAAK,OAAA;AAAA,UACL,OAAA,EAAQ,IAAA;AAAA,UACR,SAAA,EAAW,gBAAA;AAAA,UAEV,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,MAED,CAAC,KAAA,IAAS,IAAA,oBACT,GAAA,CAAC,YAAS,EAAA,EAAG,GAAA,EAAI,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,EAAS,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,iBACxD,QAAA,EAAA,IAAA,EACH;AAAA,KAAA,EAEJ,CAAA;AAAA,EAEJ;AACF;AAEA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-3YRDRHO3.js","sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const textareaStyles = cva(\n [\n 'flex min-h-24 w-full rounded-md px-3 py-2',\n 'text-[var(--input-text)] bg-[var(--input-bg)]',\n 'border border-[var(--input-border)]',\n 'placeholder:text-[var(--input-placeholder)]',\n 'transition-colors duration-150 ease-in-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-0',\n 'focus-visible:border-[var(--input-border-focus)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n ],\n {\n variants: {\n state: {\n default: '',\n error: 'border-[var(--input-border-error)] focus-visible:ring-[var(--border-error)]',\n },\n inputSize: {\n sm: 'text-xs',\n md: 'text-sm',\n lg: 'text-base',\n },\n resize: {\n vertical: 'resize-y',\n none: 'resize-none',\n },\n },\n defaultVariants: {\n state: 'default',\n inputSize: 'md',\n resize: 'vertical',\n },\n },\n);\n","import { RichText } from '@components';\nimport { cn } from '@utils';\nimport type { VariantProps } from 'class-variance-authority';\nimport { forwardRef, useId, type TextareaHTMLAttributes } from 'react';\nimport {\n inputErrorStyles,\n inputHintStyles,\n inputLabelStyles,\n} from '@components/atoms/Input/Input.styles';\nimport { textareaStyles } from './Textarea.styles';\n\nexport type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement> &\n VariantProps<typeof textareaStyles> & {\n label?: string;\n hint?: string;\n error?: string;\n };\n\n/** Multi-line text entry with the same label / hint / error contract and look as `Input`. */\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, state, inputSize, resize, label, hint, error, id: idProp, ...props }, ref) => {\n const generatedId = useId();\n const id = idProp ?? generatedId;\n const resolvedState = error ? 'error' : state;\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n {label && (\n <label htmlFor={id}>\n <RichText as=\"span\" variant=\"p3\" className={inputLabelStyles}>\n {label}\n </RichText>\n </label>\n )}\n <textarea\n ref={ref}\n id={id}\n aria-describedby={error ? `${id}-error` : hint ? `${id}-hint` : undefined}\n aria-invalid={error ? 'true' : undefined}\n className={cn(textareaStyles({ state: resolvedState, inputSize, resize }), className)}\n {...props}\n />\n {error && (\n <RichText\n as=\"p\"\n id={`${id}-error`}\n role=\"alert\"\n variant=\"p4\"\n className={inputErrorStyles}\n >\n {error}\n </RichText>\n )}\n {!error && hint && (\n <RichText as=\"p\" id={`${id}-hint`} variant=\"p4\" className={inputHintStyles}>\n {hint}\n </RichText>\n )}\n </div>\n );\n },\n);\n\nTextarea.displayName = 'Textarea';\n"]}
@@ -0,0 +1,20 @@
1
+ import { useEffect } from 'react';
2
+
3
+ // src/hooks/useScrollLock/useScrollLock.ts
4
+ var useScrollLock = (active) => {
5
+ useEffect(() => {
6
+ if (!active) {
7
+ return;
8
+ }
9
+ const { style } = document.body;
10
+ const previous = style.overflow;
11
+ style.overflow = "hidden";
12
+ return () => {
13
+ style.overflow = previous;
14
+ };
15
+ }, [active]);
16
+ };
17
+
18
+ export { useScrollLock };
19
+ //# sourceMappingURL=chunk-53YMHM24.js.map
20
+ //# sourceMappingURL=chunk-53YMHM24.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useScrollLock/useScrollLock.ts"],"names":[],"mappings":";;;AAGO,IAAM,aAAA,GAAgB,CAAC,MAAA,KAA0B;AACtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AACA,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,QAAA,CAAS,IAAA;AAC3B,IAAA,MAAM,WAAW,KAAA,CAAM,QAAA;AACvB,IAAA,KAAA,CAAM,QAAA,GAAW,QAAA;AACjB,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,CAAM,QAAA,GAAW,QAAA;AAAA,IACnB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACb","file":"chunk-53YMHM24.js","sourcesContent":["import { useEffect } from 'react';\n\n/** Prevents the page behind an open overlay from scrolling; restores the previous value on release. */\nexport const useScrollLock = (active: boolean): void => {\n useEffect(() => {\n if (!active) {\n return;\n }\n const { style } = document.body;\n const previous = style.overflow;\n style.overflow = 'hidden';\n return () => {\n style.overflow = previous;\n };\n }, [active]);\n};\n"]}
@@ -1,9 +1,11 @@
1
+ import { useDelayedUnmount } from './chunk-BNEEI7S5.js';
1
2
  import { useDismissableLayer } from './chunk-JCJP427C.js';
3
+ import { useFocusTrap } from './chunk-QT62VC36.js';
4
+ import { useScrollLock } from './chunk-53YMHM24.js';
2
5
  import { useMergedRef } from './chunk-P4Z7HH66.js';
3
- import { useDelayedUnmount } from './chunk-BNEEI7S5.js';
4
6
  import { RichText } from './chunk-P4CV2EPR.js';
5
7
  import { cn } from './chunk-6LLGTBM6.js';
6
- import { forwardRef, useRef } from 'react';
8
+ import { forwardRef, useRef, useId } from 'react';
7
9
  import { cva } from 'class-variance-authority';
8
10
  import { jsx, jsxs } from 'react/jsx-runtime';
9
11
 
@@ -48,8 +50,11 @@ var Modal = forwardRef(
48
50
  ({ open, onClose, title, footer, closeOnBackdropClick = true, className, children, ...props }, ref) => {
49
51
  const panelRef = useRef(null);
50
52
  const setPanelRef = useMergedRef(ref, panelRef);
53
+ const titleId = useId();
51
54
  const { mounted, visible } = useDelayedUnmount(open, EXIT_DURATION_MS);
52
55
  useDismissableLayer(open, onClose, panelRef, closeOnBackdropClick);
56
+ useFocusTrap(open && mounted, panelRef);
57
+ useScrollLock(open);
53
58
  if (!mounted) {
54
59
  return null;
55
60
  }
@@ -59,11 +64,12 @@ var Modal = forwardRef(
59
64
  ref: setPanelRef,
60
65
  role: "dialog",
61
66
  "aria-modal": "true",
62
- "aria-labelledby": title ? "modal-title" : void 0,
67
+ "aria-labelledby": title ? titleId : void 0,
68
+ tabIndex: -1,
63
69
  className: cn(modalPanelStyles({ visible }), className),
64
70
  ...props,
65
71
  children: [
66
- title && /* @__PURE__ */ jsx(RichText, { as: "h2", id: "modal-title", variant: "s1", className: modalTitleStyles, children: title }),
72
+ title && /* @__PURE__ */ jsx(RichText, { as: "h2", id: titleId, variant: "s1", className: modalTitleStyles, children: title }),
67
73
  children,
68
74
  footer && /* @__PURE__ */ jsx("div", { className: modalFooterStyles, children: footer })
69
75
  ]
@@ -74,5 +80,5 @@ var Modal = forwardRef(
74
80
  Modal.displayName = "Modal";
75
81
 
76
82
  export { Modal };
77
- //# sourceMappingURL=chunk-LK2EJ4H6.js.map
78
- //# sourceMappingURL=chunk-LK2EJ4H6.js.map
83
+ //# sourceMappingURL=chunk-A26UWAU4.js.map
84
+ //# sourceMappingURL=chunk-A26UWAU4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/molecules/Modal/Modal.styles.ts","../src/components/molecules/Modal/Modal.tsx"],"names":[],"mappings":";;;;;;;;;;;AAEO,IAAM,kBAAA,GAAqB,GAAA;AAAA,EAChC;AAAA,IACE,qFAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,aAAA;AAAA,QACN,KAAA,EAAO;AAAA;AACT,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,OAAA,EAAS;AAAA;AACX;AAEJ,CAAA;AAEO,IAAM,gBAAA,GAAmB,GAAA;AAAA,EAC9B;AAAA,IACE,8GAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,OAAA,EAAS;AAAA,QACP,IAAA,EAAM,uBAAA;AAAA,QACN,KAAA,EAAO;AAAA;AACT,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,OAAA,EAAS;AAAA;AACX;AAEJ,CAAA;AAEO,IAAM,gBAAA,GAAmB,uDAAA;AAEzB,IAAM,iBAAA,GAAoB,0CAAA;ACvBjC,IAAM,gBAAA,GAAmB,GAAA;AAUlB,IAAM,KAAA,GAAQ,UAAA;AAAA,EACnB,CACE,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,oBAAA,GAAuB,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,GAAG,KAAA,IACrF,GAAA,KACG;AACH,IAAA,MAAM,QAAA,GAAW,OAA8B,IAAI,CAAA;AACnD,IAAA,MAAM,WAAA,GAAc,YAAA,CAAa,GAAA,EAAK,QAAQ,CAAA;AAC9C,IAAA,MAAM,UAAU,KAAA,EAAM;AACtB,IAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,iBAAA,CAAkB,MAAM,gBAAgB,CAAA;AAErE,IAAA,mBAAA,CAAoB,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,oBAAoB,CAAA;AAEjE,IAAA,YAAA,CAAa,IAAA,IAAQ,SAAS,QAAQ,CAAA;AACtC,IAAA,aAAA,CAAc,IAAI,CAAA;AAElB,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,2BACG,KAAA,EAAA,EAAI,SAAA,EAAW,mBAAmB,EAAE,OAAA,EAAS,CAAA,EAC5C,QAAA,kBAAA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,WAAA;AAAA,QACL,IAAA,EAAK,QAAA;AAAA,QACL,YAAA,EAAW,MAAA;AAAA,QACX,iBAAA,EAAiB,QAAQ,OAAA,GAAU,MAAA;AAAA,QACnC,QAAA,EAAU,EAAA;AAAA,QACV,WAAW,EAAA,CAAG,gBAAA,CAAiB,EAAE,OAAA,EAAS,GAAG,SAAS,CAAA;AAAA,QACrD,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,KAAA,oBACC,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAG,IAAA,EAAK,EAAA,EAAI,SAAS,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,gBAAA,EACpD,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,UAED,QAAA;AAAA,UACA,MAAA,oBAAU,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,mBAAoB,QAAA,EAAA,MAAA,EAAO;AAAA;AAAA;AAAA,KACxD,EACF,CAAA;AAAA,EAEJ;AACF;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-A26UWAU4.js","sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const modalOverlayStyles = cva(\n [\n 'fixed inset-0 z-50 flex items-center justify-center bg-[var(--surface-overlay)] p-4',\n 'transition-opacity duration-200 ease-out',\n ],\n {\n variants: {\n visible: {\n true: 'opacity-100',\n false: 'opacity-0',\n },\n },\n defaultVariants: {\n visible: false,\n },\n },\n);\n\nexport const modalPanelStyles = cva(\n [\n 'w-full max-w-md rounded-xl border border-[var(--border-default)] bg-[var(--surface-secondary)] p-6 shadow-lg',\n 'transition-all duration-200 ease-out',\n ],\n {\n variants: {\n visible: {\n true: 'scale-100 opacity-100',\n false: 'scale-95 opacity-0',\n },\n },\n defaultVariants: {\n visible: false,\n },\n },\n);\n\nexport const modalTitleStyles = 'mb-4 text-lg font-semibold text-[var(--text-primary)]';\n\nexport const modalFooterStyles = 'mt-6 flex items-center justify-end gap-2';\n","import { forwardRef, useId, useRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { RichText } from '@components';\nimport {\n useDelayedUnmount,\n useDismissableLayer,\n useFocusTrap,\n useMergedRef,\n useScrollLock,\n} from '@hooks';\nimport { cn } from '@utils';\nimport {\n modalFooterStyles,\n modalOverlayStyles,\n modalPanelStyles,\n modalTitleStyles,\n} from './Modal.styles';\n\nconst EXIT_DURATION_MS = 200;\n\nexport type ModalProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n footer?: ReactNode;\n closeOnBackdropClick?: boolean;\n};\n\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(\n (\n { open, onClose, title, footer, closeOnBackdropClick = true, className, children, ...props },\n ref,\n ) => {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const setPanelRef = useMergedRef(ref, panelRef);\n const titleId = useId();\n const { mounted, visible } = useDelayedUnmount(open, EXIT_DURATION_MS);\n\n useDismissableLayer(open, onClose, panelRef, closeOnBackdropClick);\n // The panel mounts one render after `open` flips, so the trap starts once it exists.\n useFocusTrap(open && mounted, panelRef);\n useScrollLock(open);\n\n if (!mounted) {\n return null;\n }\n\n return (\n <div className={modalOverlayStyles({ visible })}>\n <div\n ref={setPanelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n tabIndex={-1}\n className={cn(modalPanelStyles({ visible }), className)}\n {...props}\n >\n {title && (\n <RichText as=\"h2\" id={titleId} variant=\"s1\" className={modalTitleStyles}>\n {title}\n </RichText>\n )}\n {children}\n {footer && <div className={modalFooterStyles}>{footer}</div>}\n </div>\n </div>\n );\n },\n);\n\nModal.displayName = 'Modal';\n"]}
@@ -0,0 +1,142 @@
1
+ import { useDelayedUnmount } from './chunk-BNEEI7S5.js';
2
+ import { useDismissableLayer } from './chunk-JCJP427C.js';
3
+ import { useFocusTrap } from './chunk-QT62VC36.js';
4
+ import { useScrollLock } from './chunk-53YMHM24.js';
5
+ import { Button } from './chunk-KL6I2JFC.js';
6
+ import { useMergedRef } from './chunk-P4Z7HH66.js';
7
+ import { RichText } from './chunk-P4CV2EPR.js';
8
+ import { cn } from './chunk-6LLGTBM6.js';
9
+ import { forwardRef, useRef, useId } from 'react';
10
+ import { cva } from 'class-variance-authority';
11
+ import { jsxs, jsx } from 'react/jsx-runtime';
12
+
13
+ var drawerOverlayStyles = cva(
14
+ "absolute inset-0 bg-[var(--surface-overlay)] transition-opacity duration-200 ease-out",
15
+ {
16
+ variants: {
17
+ visible: {
18
+ true: "opacity-100",
19
+ false: "opacity-0"
20
+ }
21
+ },
22
+ defaultVariants: {
23
+ visible: false
24
+ }
25
+ }
26
+ );
27
+ var drawerPanelStyles = cva(
28
+ [
29
+ "absolute inset-y-0 flex w-full max-w-80 flex-col gap-6 overflow-y-auto",
30
+ "border-[var(--border-default)] bg-[var(--surface-primary)] p-6 shadow-xl",
31
+ "transition-transform duration-200 ease-out focus:outline-none"
32
+ ],
33
+ {
34
+ variants: {
35
+ side: {
36
+ left: "left-0 border-r",
37
+ right: "right-0 border-l"
38
+ },
39
+ visible: {
40
+ true: "translate-x-0",
41
+ false: ""
42
+ }
43
+ },
44
+ compoundVariants: [
45
+ { side: "left", visible: false, className: "-translate-x-full" },
46
+ { side: "right", visible: false, className: "translate-x-full" }
47
+ ],
48
+ defaultVariants: {
49
+ side: "right",
50
+ visible: false
51
+ }
52
+ }
53
+ );
54
+ var drawerHeaderStyles = "flex items-center justify-between gap-4";
55
+ var drawerTitleStyles = "text-lg font-semibold text-[var(--text-primary)]";
56
+ var drawerFooterStyles = "mt-auto flex flex-col gap-4";
57
+ var EXIT_DURATION_MS = 200;
58
+ var Drawer = forwardRef(
59
+ ({
60
+ open,
61
+ onClose,
62
+ side,
63
+ title,
64
+ titleClassName,
65
+ closeLabel,
66
+ footer,
67
+ closeOnBackdropClick = true,
68
+ className,
69
+ children,
70
+ ...props
71
+ }, ref) => {
72
+ const panelRef = useRef(null);
73
+ const setPanelRef = useMergedRef(ref, panelRef);
74
+ const titleId = useId();
75
+ const { mounted, visible } = useDelayedUnmount(open, EXIT_DURATION_MS);
76
+ useDismissableLayer(open, onClose, panelRef, closeOnBackdropClick);
77
+ useFocusTrap(open && mounted, panelRef);
78
+ useScrollLock(open);
79
+ if (!mounted) {
80
+ return null;
81
+ }
82
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50", children: [
83
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: drawerOverlayStyles({ visible }) }),
84
+ /* @__PURE__ */ jsxs(
85
+ "div",
86
+ {
87
+ ref: setPanelRef,
88
+ role: "dialog",
89
+ "aria-modal": "true",
90
+ "aria-labelledby": title ? titleId : void 0,
91
+ tabIndex: -1,
92
+ className: cn(drawerPanelStyles({ side, visible }), className),
93
+ ...props,
94
+ children: [
95
+ (title || closeLabel) && /* @__PURE__ */ jsxs("div", { className: drawerHeaderStyles, children: [
96
+ title && /* @__PURE__ */ jsx(
97
+ RichText,
98
+ {
99
+ as: "h2",
100
+ id: titleId,
101
+ variant: "s1",
102
+ className: cn(drawerTitleStyles, titleClassName),
103
+ children: title
104
+ }
105
+ ),
106
+ closeLabel && /* @__PURE__ */ jsx(
107
+ Button,
108
+ {
109
+ variant: "ghost",
110
+ size: "icon",
111
+ "aria-label": closeLabel,
112
+ onClick: onClose,
113
+ className: "ml-auto size-11",
114
+ children: /* @__PURE__ */ jsx(
115
+ "svg",
116
+ {
117
+ "aria-hidden": true,
118
+ viewBox: "0 0 24 24",
119
+ fill: "none",
120
+ stroke: "currentColor",
121
+ strokeWidth: 2,
122
+ strokeLinecap: "round",
123
+ className: "size-6",
124
+ children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6L6 18" })
125
+ }
126
+ )
127
+ }
128
+ )
129
+ ] }),
130
+ children,
131
+ footer && /* @__PURE__ */ jsx("div", { className: drawerFooterStyles, children: footer })
132
+ ]
133
+ }
134
+ )
135
+ ] });
136
+ }
137
+ );
138
+ Drawer.displayName = "Drawer";
139
+
140
+ export { Drawer };
141
+ //# sourceMappingURL=chunk-CX3GARWU.js.map
142
+ //# sourceMappingURL=chunk-CX3GARWU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/molecules/Drawer/Drawer.styles.ts","../src/components/molecules/Drawer/Drawer.tsx"],"names":[],"mappings":"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","file":"chunk-CX3GARWU.js","sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const drawerOverlayStyles = cva(\n 'absolute inset-0 bg-[var(--surface-overlay)] transition-opacity duration-200 ease-out',\n {\n variants: {\n visible: {\n true: 'opacity-100',\n false: 'opacity-0',\n },\n },\n defaultVariants: {\n visible: false,\n },\n },\n);\n\nexport const drawerPanelStyles = cva(\n [\n 'absolute inset-y-0 flex w-full max-w-80 flex-col gap-6 overflow-y-auto',\n 'border-[var(--border-default)] bg-[var(--surface-primary)] p-6 shadow-xl',\n 'transition-transform duration-200 ease-out focus:outline-none',\n ],\n {\n variants: {\n side: {\n left: 'left-0 border-r',\n right: 'right-0 border-l',\n },\n visible: {\n true: 'translate-x-0',\n false: '',\n },\n },\n compoundVariants: [\n { side: 'left', visible: false, className: '-translate-x-full' },\n { side: 'right', visible: false, className: 'translate-x-full' },\n ],\n defaultVariants: {\n side: 'right',\n visible: false,\n },\n },\n);\n\nexport const drawerHeaderStyles = 'flex items-center justify-between gap-4';\n\nexport const drawerTitleStyles = 'text-lg font-semibold text-[var(--text-primary)]';\n\nexport const drawerFooterStyles = 'mt-auto flex flex-col gap-4';\n","import { Button, RichText } from '@components';\nimport {\n useDelayedUnmount,\n useDismissableLayer,\n useFocusTrap,\n useMergedRef,\n useScrollLock,\n} from '@hooks';\nimport { cn } from '@utils';\nimport type { VariantProps } from 'class-variance-authority';\nimport { forwardRef, useId, useRef, type HTMLAttributes, type ReactNode } from 'react';\nimport {\n drawerFooterStyles,\n drawerHeaderStyles,\n drawerOverlayStyles,\n drawerPanelStyles,\n drawerTitleStyles,\n} from './Drawer.styles';\n\nconst EXIT_DURATION_MS = 200;\n\nexport type DrawerProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> &\n Pick<VariantProps<typeof drawerPanelStyles>, 'side'> & {\n open: boolean;\n onClose: () => void;\n title?: ReactNode;\n /** Extra classes for the title (e.g. a display font). */\n titleClassName?: string;\n /** Accessible name of the close button; the button is only rendered when this is set. */\n closeLabel?: string;\n /** Pinned to the bottom of the panel (preferences, actions). */\n footer?: ReactNode;\n closeOnBackdropClick?: boolean;\n };\n\n/**\n * A side panel (navigation menus, filters, settings) that slides in from the left or right.\n * Modal dialog semantics: focus moves inside and is trapped, Escape and backdrop clicks close it,\n * the page behind doesn't scroll, and focus returns to the trigger when it closes.\n */\nexport const Drawer = forwardRef<HTMLDivElement, DrawerProps>(\n (\n {\n open,\n onClose,\n side,\n title,\n titleClassName,\n closeLabel,\n footer,\n closeOnBackdropClick = true,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const panelRef = useRef<HTMLDivElement | null>(null);\n const setPanelRef = useMergedRef(ref, panelRef);\n const titleId = useId();\n const { mounted, visible } = useDelayedUnmount(open, EXIT_DURATION_MS);\n\n useDismissableLayer(open, onClose, panelRef, closeOnBackdropClick);\n // The panel mounts one render after `open` flips, so the trap starts once it exists.\n useFocusTrap(open && mounted, panelRef);\n useScrollLock(open);\n\n if (!mounted) {\n return null;\n }\n\n return (\n <div className=\"fixed inset-0 z-50\">\n <div aria-hidden=\"true\" className={drawerOverlayStyles({ visible })} />\n <div\n ref={setPanelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title ? titleId : undefined}\n tabIndex={-1}\n className={cn(drawerPanelStyles({ side, visible }), className)}\n {...props}\n >\n {(title || closeLabel) && (\n <div className={drawerHeaderStyles}>\n {title && (\n <RichText\n as=\"h2\"\n id={titleId}\n variant=\"s1\"\n className={cn(drawerTitleStyles, titleClassName)}\n >\n {title}\n </RichText>\n )}\n {closeLabel && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={closeLabel}\n onClick={onClose}\n className=\"ml-auto size-11\"\n >\n <svg\n aria-hidden\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n className=\"size-6\"\n >\n <path d=\"M6 6l12 12M18 6L6 18\" />\n </svg>\n </Button>\n )}\n </div>\n )}\n {children}\n {footer && <div className={drawerFooterStyles}>{footer}</div>}\n </div>\n </div>\n );\n },\n);\n\nDrawer.displayName = 'Drawer';\n"]}
@@ -0,0 +1,34 @@
1
+ import { inputLabelStyles, inputStyles, inputErrorStyles, inputHintStyles } from './chunk-FFKHEBQ7.js';
2
+ import { RichText } from './chunk-P4CV2EPR.js';
3
+ import { cn } from './chunk-6LLGTBM6.js';
4
+ import { forwardRef, useId } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var Input = forwardRef(
8
+ ({ className, state, inputSize, label, hint, error, id: idProp, ...props }, ref) => {
9
+ const generatedId = useId();
10
+ const id = idProp ?? generatedId;
11
+ const resolvedState = error ? "error" : state;
12
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
13
+ label && /* @__PURE__ */ jsx("label", { htmlFor: id, children: /* @__PURE__ */ jsx(RichText, { as: "span", variant: "p3", className: inputLabelStyles, children: label }) }),
14
+ /* @__PURE__ */ jsx(
15
+ "input",
16
+ {
17
+ ref,
18
+ id,
19
+ "aria-describedby": error ? `${id}-error` : hint ? `${id}-hint` : void 0,
20
+ "aria-invalid": error ? "true" : void 0,
21
+ className: cn(inputStyles({ state: resolvedState, inputSize }), className),
22
+ ...props
23
+ }
24
+ ),
25
+ error && /* @__PURE__ */ jsx(RichText, { as: "p", id: `${id}-error`, role: "alert", variant: "p4", className: inputErrorStyles, children: error }),
26
+ !error && hint && /* @__PURE__ */ jsx(RichText, { as: "p", id: `${id}-hint`, variant: "p4", className: inputHintStyles, children: hint })
27
+ ] });
28
+ }
29
+ );
30
+ Input.displayName = "Input";
31
+
32
+ export { Input };
33
+ //# sourceMappingURL=chunk-DP274HDM.js.map
34
+ //# sourceMappingURL=chunk-DP274HDM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/atoms/Input/Input.tsx"],"names":[],"mappings":";;;;;;AAkBO,IAAM,KAAA,GAAQ,UAAA;AAAA,EACnB,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,GAAG,KAAA,IAAS,GAAA,KAAQ;AAClF,IAAA,MAAM,cAAc,KAAA,EAAM;AAC1B,IAAA,MAAM,KAAK,MAAA,IAAU,WAAA;AACrB,IAAA,MAAM,aAAA,GAAgB,QAAQ,OAAA,GAAU,KAAA;AAExC,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EACZ,QAAA,EAAA;AAAA,MAAA,KAAA,oBACC,GAAA,CAAC,OAAA,EAAA,EAAM,OAAA,EAAS,EAAA,EACd,QAAA,kBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAG,MAAA,EAAO,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,gBAAA,EACzC,iBACH,CAAA,EACF,CAAA;AAAA,sBAEF,GAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,GAAA;AAAA,UACA,EAAA;AAAA,UACA,kBAAA,EAAkB,QAAQ,CAAA,EAAG,EAAE,WAAW,IAAA,GAAO,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,GAAU,MAAA;AAAA,UAChE,cAAA,EAAc,QAAQ,MAAA,GAAS,MAAA;AAAA,UAC/B,SAAA,EAAW,GAAG,WAAA,CAAY,EAAE,OAAO,aAAA,EAAe,SAAA,EAAW,CAAA,EAAG,SAAS,CAAA;AAAA,UACxE,GAAG;AAAA;AAAA,OACN;AAAA,MACC,KAAA,oBACC,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAG,KAAI,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,MAAA,CAAA,EAAU,MAAK,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,kBACtE,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,MAED,CAAC,KAAA,IAAS,IAAA,oBACT,GAAA,CAAC,YAAS,EAAA,EAAG,GAAA,EAAI,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,EAAS,OAAA,EAAQ,IAAA,EAAK,SAAA,EAAW,iBACxD,QAAA,EAAA,IAAA,EACH;AAAA,KAAA,EAEJ,CAAA;AAAA,EAEJ;AACF;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-DP274HDM.js","sourcesContent":["import type { VariantProps } from 'class-variance-authority';\nimport { forwardRef, useId, type InputHTMLAttributes } from 'react';\nimport { RichText } from '@components';\nimport { cn } from '@utils';\nimport {\n inputErrorStyles,\n inputHintStyles,\n inputLabelStyles,\n inputStyles,\n} from './Input.styles';\n\nexport type InputProps = InputHTMLAttributes<HTMLInputElement> &\n VariantProps<typeof inputStyles> & {\n label?: string;\n hint?: string;\n error?: string;\n };\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, state, inputSize, label, hint, error, id: idProp, ...props }, ref) => {\n const generatedId = useId();\n const id = idProp ?? generatedId;\n const resolvedState = error ? 'error' : state;\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n {label && (\n <label htmlFor={id}>\n <RichText as=\"span\" variant=\"p3\" className={inputLabelStyles}>\n {label}\n </RichText>\n </label>\n )}\n <input\n ref={ref}\n id={id}\n aria-describedby={error ? `${id}-error` : hint ? `${id}-hint` : undefined}\n aria-invalid={error ? 'true' : undefined}\n className={cn(inputStyles({ state: resolvedState, inputSize }), className)}\n {...props}\n />\n {error && (\n <RichText as=\"p\" id={`${id}-error`} role=\"alert\" variant=\"p4\" className={inputErrorStyles}>\n {error}\n </RichText>\n )}\n {!error && hint && (\n <RichText as=\"p\" id={`${id}-hint`} variant=\"p4\" className={inputHintStyles}>\n {hint}\n </RichText>\n )}\n </div>\n );\n },\n);\n\nInput.displayName = 'Input';\n"]}
@@ -0,0 +1,41 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ // src/components/atoms/Input/Input.styles.ts
4
+ var inputStyles = cva(
5
+ [
6
+ "flex w-full rounded-md px-3 py-2",
7
+ "text-sm text-[var(--input-text)]",
8
+ "bg-[var(--input-bg)]",
9
+ "border border-[var(--input-border)]",
10
+ "placeholder:text-[var(--input-placeholder)]",
11
+ "transition-colors duration-150 ease-in-out",
12
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-0",
13
+ "focus-visible:border-[var(--input-border-focus)]",
14
+ "disabled:cursor-not-allowed disabled:opacity-50",
15
+ "file:border-0 file:bg-transparent file:text-sm file:font-medium"
16
+ ],
17
+ {
18
+ variants: {
19
+ state: {
20
+ default: "",
21
+ error: "border-[var(--input-border-error)] focus-visible:ring-[var(--border-error)]"
22
+ },
23
+ inputSize: {
24
+ sm: "h-8 px-2 text-xs",
25
+ md: "h-10 px-3 text-sm",
26
+ lg: "h-12 px-4 text-base"
27
+ }
28
+ },
29
+ defaultVariants: {
30
+ state: "default",
31
+ inputSize: "md"
32
+ }
33
+ }
34
+ );
35
+ var inputLabelStyles = "text-sm font-medium text-[var(--text-primary)]";
36
+ var inputErrorStyles = "text-xs text-[var(--border-error)]";
37
+ var inputHintStyles = "text-xs text-[var(--text-secondary)]";
38
+
39
+ export { inputErrorStyles, inputHintStyles, inputLabelStyles, inputStyles };
40
+ //# sourceMappingURL=chunk-FFKHEBQ7.js.map
41
+ //# sourceMappingURL=chunk-FFKHEBQ7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/atoms/Input/Input.styles.ts"],"names":[],"mappings":";;;AAEO,IAAM,WAAA,GAAc,GAAA;AAAA,EACzB;AAAA,IACE,kCAAA;AAAA,IACA,kCAAA;AAAA,IACA,sBAAA;AAAA,IACA,qCAAA;AAAA,IACA,6CAAA;AAAA,IACA,4CAAA;AAAA,IACA,sHAAA;AAAA,IACA,kDAAA;AAAA,IACA,iDAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,EAAA;AAAA,QACT,KAAA,EAAO;AAAA,OACT;AAAA,MACA,SAAA,EAAW;AAAA,QACT,EAAA,EAAI,kBAAA;AAAA,QACJ,EAAA,EAAI,mBAAA;AAAA,QACJ,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,KAAA,EAAO,SAAA;AAAA,MACP,SAAA,EAAW;AAAA;AACb;AAEJ;AAEO,IAAM,gBAAA,GAAmB;AACzB,IAAM,gBAAA,GAAmB;AACzB,IAAM,eAAA,GAAkB","file":"chunk-FFKHEBQ7.js","sourcesContent":["import { cva } from 'class-variance-authority';\n\nexport const inputStyles = cva(\n [\n 'flex w-full rounded-md px-3 py-2',\n 'text-sm text-[var(--input-text)]',\n 'bg-[var(--input-bg)]',\n 'border border-[var(--input-border)]',\n 'placeholder:text-[var(--input-placeholder)]',\n 'transition-colors duration-150 ease-in-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--border-focus)] focus-visible:ring-offset-0',\n 'focus-visible:border-[var(--input-border-focus)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'file:border-0 file:bg-transparent file:text-sm file:font-medium',\n ],\n {\n variants: {\n state: {\n default: '',\n error: 'border-[var(--input-border-error)] focus-visible:ring-[var(--border-error)]',\n },\n inputSize: {\n sm: 'h-8 px-2 text-xs',\n md: 'h-10 px-3 text-sm',\n lg: 'h-12 px-4 text-base',\n },\n },\n defaultVariants: {\n state: 'default',\n inputSize: 'md',\n },\n },\n);\n\nexport const inputLabelStyles = 'text-sm font-medium text-[var(--text-primary)]';\nexport const inputErrorStyles = 'text-xs text-[var(--border-error)]';\nexport const inputHintStyles = 'text-xs text-[var(--text-secondary)]';\n"]}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-GQMA2AQI.js.map
3
+ //# sourceMappingURL=chunk-GQMA2AQI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-GQMA2AQI.js"}
@@ -1,6 +1,7 @@
1
+ import { useMergedRef } from './chunk-P4Z7HH66.js';
1
2
  import { cn } from './chunk-6LLGTBM6.js';
2
- import { forwardRef } from 'react';
3
3
  import { cva } from 'class-variance-authority';
4
+ import { forwardRef, Children, isValidElement, cloneElement } from 'react';
4
5
  import { jsx } from 'react/jsx-runtime';
5
6
 
6
7
  var buttonStyles = cva(
@@ -57,20 +58,50 @@ var buttonStyles = cva(
57
58
  }
58
59
  }
59
60
  );
61
+ var isHandler = (key, value) => /^on[A-Z]/.test(key) && typeof value === "function";
62
+ var mergeProps = (slotProps, childProps) => {
63
+ const merged = { ...slotProps, ...childProps };
64
+ for (const [key, slotValue] of Object.entries(slotProps)) {
65
+ const childValue = childProps[key];
66
+ if (isHandler(key, slotValue) && isHandler(key, childValue)) {
67
+ merged[key] = (...args) => {
68
+ childValue(...args);
69
+ slotValue(...args);
70
+ };
71
+ }
72
+ }
73
+ merged["className"] = cn(slotProps["className"], childProps["className"]);
74
+ merged["style"] = {
75
+ ...slotProps["style"],
76
+ ...childProps["style"]
77
+ };
78
+ return merged;
79
+ };
80
+ var Slot = forwardRef(
81
+ ({ children, ...slotProps }, forwardedRef) => {
82
+ const child = Children.count(children) === 1 ? Children.toArray(children)[0] : null;
83
+ const childProps = isValidElement(child) ? child.props : {};
84
+ const childRef = childProps["ref"] ?? child?.ref;
85
+ const ref = useMergedRef(forwardedRef, childRef);
86
+ if (!isValidElement(child)) {
87
+ return null;
88
+ }
89
+ return cloneElement(child, { ...mergeProps(slotProps, childProps), ref });
90
+ }
91
+ );
92
+ Slot.displayName = "Slot";
60
93
  var Button = forwardRef(
61
- ({ className, variant, size, fullWidth, ...props }, ref) => {
62
- return /* @__PURE__ */ jsx(
63
- "button",
64
- {
65
- ref,
66
- className: cn(buttonStyles({ variant, size, fullWidth }), className),
67
- ...props
68
- }
69
- );
94
+ ({ className, variant, size, fullWidth, asChild = false, ...props }, ref) => {
95
+ const classes = cn(buttonStyles({ variant, size, fullWidth }), className);
96
+ if (asChild) {
97
+ const slotRef = ref;
98
+ return /* @__PURE__ */ jsx(Slot, { ref: slotRef, className: classes, ...props });
99
+ }
100
+ return /* @__PURE__ */ jsx("button", { ref, className: classes, ...props });
70
101
  }
71
102
  );
72
103
  Button.displayName = "Button";
73
104
 
74
- export { Button };
75
- //# sourceMappingURL=chunk-KWSZ2S34.js.map
76
- //# sourceMappingURL=chunk-KWSZ2S34.js.map
105
+ export { Button, buttonStyles };
106
+ //# sourceMappingURL=chunk-KL6I2JFC.js.map
107
+ //# sourceMappingURL=chunk-KL6I2JFC.js.map