@diwauhris/ui 1.0.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 (272) hide show
  1. package/README.md +75 -0
  2. package/lib/assets/ui.css +154 -0
  3. package/lib/index.cjs +183 -0
  4. package/lib/index.mjs +65 -0
  5. package/lib/index10.cjs +33 -0
  6. package/lib/index10.cjs.map +1 -0
  7. package/lib/index10.mjs +33 -0
  8. package/lib/index10.mjs.map +1 -0
  9. package/lib/index11.cjs +16 -0
  10. package/lib/index11.cjs.map +1 -0
  11. package/lib/index11.mjs +16 -0
  12. package/lib/index11.mjs.map +1 -0
  13. package/lib/index12.cjs +16 -0
  14. package/lib/index12.cjs.map +1 -0
  15. package/lib/index12.mjs +15 -0
  16. package/lib/index12.mjs.map +1 -0
  17. package/lib/index13.cjs +57 -0
  18. package/lib/index13.cjs.map +1 -0
  19. package/lib/index13.mjs +57 -0
  20. package/lib/index13.mjs.map +1 -0
  21. package/lib/index14.cjs +10 -0
  22. package/lib/index14.cjs.map +1 -0
  23. package/lib/index14.mjs +10 -0
  24. package/lib/index14.mjs.map +1 -0
  25. package/lib/index15.cjs +30 -0
  26. package/lib/index15.cjs.map +1 -0
  27. package/lib/index15.mjs +30 -0
  28. package/lib/index15.mjs.map +1 -0
  29. package/lib/index16.cjs +28 -0
  30. package/lib/index16.cjs.map +1 -0
  31. package/lib/index16.mjs +26 -0
  32. package/lib/index16.mjs.map +1 -0
  33. package/lib/index17.cjs +43 -0
  34. package/lib/index17.cjs.map +1 -0
  35. package/lib/index17.mjs +43 -0
  36. package/lib/index17.mjs.map +1 -0
  37. package/lib/index18.cjs +59 -0
  38. package/lib/index18.cjs.map +1 -0
  39. package/lib/index18.mjs +59 -0
  40. package/lib/index18.mjs.map +1 -0
  41. package/lib/index19.cjs +67 -0
  42. package/lib/index19.cjs.map +1 -0
  43. package/lib/index19.mjs +67 -0
  44. package/lib/index19.mjs.map +1 -0
  45. package/lib/index2.cjs +33 -0
  46. package/lib/index2.mjs +13 -0
  47. package/lib/index20.cjs +79 -0
  48. package/lib/index20.cjs.map +1 -0
  49. package/lib/index20.mjs +79 -0
  50. package/lib/index20.mjs.map +1 -0
  51. package/lib/index21.cjs +105 -0
  52. package/lib/index21.cjs.map +1 -0
  53. package/lib/index21.mjs +104 -0
  54. package/lib/index21.mjs.map +1 -0
  55. package/lib/index22.cjs +50 -0
  56. package/lib/index22.cjs.map +1 -0
  57. package/lib/index22.mjs +50 -0
  58. package/lib/index22.mjs.map +1 -0
  59. package/lib/index23.cjs +143 -0
  60. package/lib/index23.cjs.map +1 -0
  61. package/lib/index23.mjs +143 -0
  62. package/lib/index23.mjs.map +1 -0
  63. package/lib/index25.cjs +177 -0
  64. package/lib/index25.cjs.map +1 -0
  65. package/lib/index25.mjs +175 -0
  66. package/lib/index25.mjs.map +1 -0
  67. package/lib/index26.cjs +108 -0
  68. package/lib/index26.cjs.map +1 -0
  69. package/lib/index26.mjs +108 -0
  70. package/lib/index26.mjs.map +1 -0
  71. package/lib/index27.cjs +120 -0
  72. package/lib/index27.cjs.map +1 -0
  73. package/lib/index27.mjs +120 -0
  74. package/lib/index27.mjs.map +1 -0
  75. package/lib/index28.cjs +54 -0
  76. package/lib/index28.cjs.map +1 -0
  77. package/lib/index28.mjs +54 -0
  78. package/lib/index28.mjs.map +1 -0
  79. package/lib/index29.cjs +100 -0
  80. package/lib/index29.cjs.map +1 -0
  81. package/lib/index29.mjs +100 -0
  82. package/lib/index29.mjs.map +1 -0
  83. package/lib/index3.cjs +38 -0
  84. package/lib/index3.cjs.map +1 -0
  85. package/lib/index3.mjs +38 -0
  86. package/lib/index3.mjs.map +1 -0
  87. package/lib/index30.cjs +27 -0
  88. package/lib/index30.cjs.map +1 -0
  89. package/lib/index30.mjs +27 -0
  90. package/lib/index30.mjs.map +1 -0
  91. package/lib/index31.cjs +72 -0
  92. package/lib/index31.cjs.map +1 -0
  93. package/lib/index31.mjs +72 -0
  94. package/lib/index31.mjs.map +1 -0
  95. package/lib/index32.cjs +19 -0
  96. package/lib/index32.cjs.map +1 -0
  97. package/lib/index32.mjs +19 -0
  98. package/lib/index32.mjs.map +1 -0
  99. package/lib/index33.cjs +25 -0
  100. package/lib/index33.cjs.map +1 -0
  101. package/lib/index33.mjs +25 -0
  102. package/lib/index33.mjs.map +1 -0
  103. package/lib/index34.cjs +55 -0
  104. package/lib/index34.cjs.map +1 -0
  105. package/lib/index34.mjs +51 -0
  106. package/lib/index34.mjs.map +1 -0
  107. package/lib/index35.cjs +25 -0
  108. package/lib/index35.cjs.map +1 -0
  109. package/lib/index35.mjs +25 -0
  110. package/lib/index35.mjs.map +1 -0
  111. package/lib/index36.cjs +54 -0
  112. package/lib/index36.cjs.map +1 -0
  113. package/lib/index36.mjs +49 -0
  114. package/lib/index36.mjs.map +1 -0
  115. package/lib/index37.cjs +130 -0
  116. package/lib/index37.cjs.map +1 -0
  117. package/lib/index37.mjs +128 -0
  118. package/lib/index37.mjs.map +1 -0
  119. package/lib/index38.cjs +106 -0
  120. package/lib/index38.cjs.map +1 -0
  121. package/lib/index38.mjs +102 -0
  122. package/lib/index38.mjs.map +1 -0
  123. package/lib/index39.cjs +137 -0
  124. package/lib/index39.cjs.map +1 -0
  125. package/lib/index39.mjs +137 -0
  126. package/lib/index39.mjs.map +1 -0
  127. package/lib/index4.cjs +24 -0
  128. package/lib/index4.cjs.map +1 -0
  129. package/lib/index4.mjs +24 -0
  130. package/lib/index4.mjs.map +1 -0
  131. package/lib/index40.cjs +130 -0
  132. package/lib/index40.cjs.map +1 -0
  133. package/lib/index40.mjs +126 -0
  134. package/lib/index40.mjs.map +1 -0
  135. package/lib/index41.cjs +60 -0
  136. package/lib/index41.cjs.map +1 -0
  137. package/lib/index41.mjs +58 -0
  138. package/lib/index41.mjs.map +1 -0
  139. package/lib/index42.cjs +105 -0
  140. package/lib/index42.cjs.map +1 -0
  141. package/lib/index42.mjs +105 -0
  142. package/lib/index42.mjs.map +1 -0
  143. package/lib/index43.cjs +47 -0
  144. package/lib/index43.cjs.map +1 -0
  145. package/lib/index43.mjs +42 -0
  146. package/lib/index43.mjs.map +1 -0
  147. package/lib/index44.cjs +40 -0
  148. package/lib/index44.cjs.map +1 -0
  149. package/lib/index44.mjs +35 -0
  150. package/lib/index44.mjs.map +1 -0
  151. package/lib/index45.cjs +91 -0
  152. package/lib/index45.cjs.map +1 -0
  153. package/lib/index45.mjs +91 -0
  154. package/lib/index45.mjs.map +1 -0
  155. package/lib/index46.cjs +180 -0
  156. package/lib/index46.cjs.map +1 -0
  157. package/lib/index46.mjs +180 -0
  158. package/lib/index46.mjs.map +1 -0
  159. package/lib/index47.cjs +61 -0
  160. package/lib/index47.cjs.map +1 -0
  161. package/lib/index47.mjs +61 -0
  162. package/lib/index47.mjs.map +1 -0
  163. package/lib/index48.cjs +165 -0
  164. package/lib/index48.cjs.map +1 -0
  165. package/lib/index48.mjs +161 -0
  166. package/lib/index48.mjs.map +1 -0
  167. package/lib/index49.cjs +83 -0
  168. package/lib/index49.cjs.map +1 -0
  169. package/lib/index49.mjs +83 -0
  170. package/lib/index49.mjs.map +1 -0
  171. package/lib/index5.cjs +39 -0
  172. package/lib/index5.cjs.map +1 -0
  173. package/lib/index5.mjs +39 -0
  174. package/lib/index5.mjs.map +1 -0
  175. package/lib/index50.cjs +100 -0
  176. package/lib/index50.cjs.map +1 -0
  177. package/lib/index50.mjs +100 -0
  178. package/lib/index50.mjs.map +1 -0
  179. package/lib/index51.cjs +116 -0
  180. package/lib/index51.cjs.map +1 -0
  181. package/lib/index51.mjs +113 -0
  182. package/lib/index51.mjs.map +1 -0
  183. package/lib/index52.cjs +93 -0
  184. package/lib/index52.cjs.map +1 -0
  185. package/lib/index52.mjs +93 -0
  186. package/lib/index52.mjs.map +1 -0
  187. package/lib/index53.cjs +120 -0
  188. package/lib/index53.cjs.map +1 -0
  189. package/lib/index53.mjs +120 -0
  190. package/lib/index53.mjs.map +1 -0
  191. package/lib/index54.cjs +53 -0
  192. package/lib/index54.cjs.map +1 -0
  193. package/lib/index54.mjs +50 -0
  194. package/lib/index54.mjs.map +1 -0
  195. package/lib/index55.cjs +130 -0
  196. package/lib/index55.cjs.map +1 -0
  197. package/lib/index55.mjs +127 -0
  198. package/lib/index55.mjs.map +1 -0
  199. package/lib/index56.cjs +36 -0
  200. package/lib/index56.cjs.map +1 -0
  201. package/lib/index56.mjs +35 -0
  202. package/lib/index56.mjs.map +1 -0
  203. package/lib/index57.cjs +47 -0
  204. package/lib/index57.cjs.map +1 -0
  205. package/lib/index57.mjs +47 -0
  206. package/lib/index57.mjs.map +1 -0
  207. package/lib/index58.cjs +97 -0
  208. package/lib/index58.cjs.map +1 -0
  209. package/lib/index58.mjs +97 -0
  210. package/lib/index58.mjs.map +1 -0
  211. package/lib/index59.cjs +120 -0
  212. package/lib/index59.cjs.map +1 -0
  213. package/lib/index59.mjs +116 -0
  214. package/lib/index59.mjs.map +1 -0
  215. package/lib/index6.cjs +29 -0
  216. package/lib/index6.cjs.map +1 -0
  217. package/lib/index6.mjs +29 -0
  218. package/lib/index6.mjs.map +1 -0
  219. package/lib/index60.cjs +34 -0
  220. package/lib/index60.cjs.map +1 -0
  221. package/lib/index60.mjs +34 -0
  222. package/lib/index60.mjs.map +1 -0
  223. package/lib/index61.cjs +62 -0
  224. package/lib/index61.cjs.map +1 -0
  225. package/lib/index61.mjs +62 -0
  226. package/lib/index61.mjs.map +1 -0
  227. package/lib/index62.cjs +213 -0
  228. package/lib/index62.cjs.map +1 -0
  229. package/lib/index62.mjs +213 -0
  230. package/lib/index62.mjs.map +1 -0
  231. package/lib/index63.cjs +42 -0
  232. package/lib/index63.cjs.map +1 -0
  233. package/lib/index63.mjs +42 -0
  234. package/lib/index63.mjs.map +1 -0
  235. package/lib/index64.cjs +86 -0
  236. package/lib/index64.cjs.map +1 -0
  237. package/lib/index64.mjs +86 -0
  238. package/lib/index64.mjs.map +1 -0
  239. package/lib/index65.cjs +156 -0
  240. package/lib/index65.cjs.map +1 -0
  241. package/lib/index65.mjs +156 -0
  242. package/lib/index65.mjs.map +1 -0
  243. package/lib/index66.cjs +107 -0
  244. package/lib/index66.cjs.map +1 -0
  245. package/lib/index66.mjs +106 -0
  246. package/lib/index66.mjs.map +1 -0
  247. package/lib/index67.cjs +52 -0
  248. package/lib/index67.cjs.map +1 -0
  249. package/lib/index67.mjs +52 -0
  250. package/lib/index67.mjs.map +1 -0
  251. package/lib/index68.cjs +125 -0
  252. package/lib/index68.cjs.map +1 -0
  253. package/lib/index68.mjs +115 -0
  254. package/lib/index68.mjs.map +1 -0
  255. package/lib/index69.cjs +34 -0
  256. package/lib/index69.cjs.map +1 -0
  257. package/lib/index69.mjs +29 -0
  258. package/lib/index69.mjs.map +1 -0
  259. package/lib/index7.cjs +17 -0
  260. package/lib/index7.cjs.map +1 -0
  261. package/lib/index7.mjs +17 -0
  262. package/lib/index7.mjs.map +1 -0
  263. package/lib/index8.cjs +86 -0
  264. package/lib/index8.cjs.map +1 -0
  265. package/lib/index8.mjs +86 -0
  266. package/lib/index8.mjs.map +1 -0
  267. package/lib/index9.cjs +29 -0
  268. package/lib/index9.cjs.map +1 -0
  269. package/lib/index9.mjs +29 -0
  270. package/lib/index9.mjs.map +1 -0
  271. package/lib/types/index.d.ts +1 -0
  272. package/package.json +68 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index22.cjs","names":[],"sources":["../src/ui-library/gallery/switch/Switch.tsx"],"sourcesContent":["/**\n * Switch — Design System Component\n *\n * Communicates an immediate on/off toggle — not a form checkbox.\n * Use Switch when the action takes effect immediately (e.g. toggling a setting).\n * Use Checkbox when the value is submitted as part of a form.\n *\n * Role: switch (ARIA) — announces as \"on\"/\"off\" to screen readers.\n */\n\nimport type { ReactNode } from 'react';\nimport { useId } from 'react';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n label?: ReactNode;\n description?: string;\n disabled?: boolean;\n /** Show a loading spinner in place of the thumb */\n loading?: boolean;\n id?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n description,\n disabled = false,\n loading = false,\n id: externalId,\n}: SwitchProps) {\n const generatedId = useId();\n const id = externalId ?? generatedId;\n const labelId = label ? `${id}-label` : undefined;\n const isInteractive = !disabled && !loading;\n\n return (\n <div className=\"flex items-start gap-3\">\n {/* Track + thumb */}\n <button\n id={id}\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-labelledby={labelId}\n aria-disabled={!isInteractive || undefined}\n disabled={!isInteractive}\n onClick={() => isInteractive && onChange(!checked)}\n className={[\n 'relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 focus-visible:ring-offset-1',\n checked ? 'bg-brand-blue' : 'bg-slate-200',\n !isInteractive ? 'cursor-not-allowed opacity-60' : 'cursor-pointer',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Thumb */}\n <span\n aria-hidden=\"true\"\n className={[\n 'inline-block h-5 w-5 rounded-full bg-white shadow-sm ring-0 transition-transform duration-200',\n checked ? 'translate-x-5' : 'translate-x-0',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Loading spinner inside thumb */}\n {loading && (\n <span className=\"flex h-full w-full items-center justify-center\">\n <span className=\"h-2.5 w-2.5 animate-spin rounded-full border-2 border-slate-300 border-t-brand-blue\" />\n </span>\n )}\n </span>\n </button>\n\n {/* Label + description */}\n {(label || description) && (\n <div className=\"min-w-0 pt-0.5\">\n {label && (\n <span\n id={labelId}\n className={`block text-sm font-semibold ${disabled ? 'text-slate-400' : 'text-slate-800'}`}\n >\n {label}\n </span>\n )}\n {description && (\n <span className=\"block text-xs font-medium leading-relaxed text-slate-400\">\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;AAwBA,SAAgB,OAAO,EACrB,SACA,UACA,OACA,aACA,WAAW,OACX,UAAU,OACV,IAAI,cACU;CACd,MAAM,eAAA,GAAc,MAAA,MAAA,CAAM;CAC1B,MAAM,KAAK,cAAc;CACzB,MAAM,UAAU,QAAQ,GAAG,GAAG,UAAU,KAAA;CACxC,MAAM,gBAAgB,CAAC,YAAY,CAAC;CAEpC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CAEE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;GACM;GACJ,MAAK;GACL,MAAK;GACL,gBAAc;GACd,mBAAiB;GACjB,iBAAe,CAAC,iBAAiB,KAAA;GACjC,UAAU,CAAC;GACX,eAAe,iBAAiB,SAAS,CAAC,OAAO;GACjD,WAAW;IACT;IACA;IACA,UAAU,kBAAkB;IAC5B,CAAC,gBAAgB,kCAAkC;GACrD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;GAGX,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IACE,eAAY;IACZ,WAAW,CACT,iGACA,UAAU,kBAAkB,eAC9B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;IAGV,UAAA,WACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;KACd,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAU,sFAAuF,CAAA;IACnG,CAAA;GAEJ,CAAA;EACA,CAAA,IAGN,SAAS,gBACT,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,SACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IACE,IAAI;IACJ,WAAW,+BAA+B,WAAW,mBAAmB;IAEvE,UAAA;GACG,CAAA,GAEP,eACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,CAEL;EAEJ,CAAA,CAAA;;AAET"}
@@ -0,0 +1,50 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
3
+ //#region src/ui-library/gallery/switch/Switch.tsx
4
+ function Switch({ checked, onChange, label, description, disabled = false, loading = false, id: externalId }) {
5
+ const generatedId = useId();
6
+ const id = externalId ?? generatedId;
7
+ const labelId = label ? `${id}-label` : void 0;
8
+ const isInteractive = !disabled && !loading;
9
+ return /* @__PURE__ */ jsxs("div", {
10
+ className: "flex items-start gap-3",
11
+ children: [/* @__PURE__ */ jsx("button", {
12
+ id,
13
+ type: "button",
14
+ role: "switch",
15
+ "aria-checked": checked,
16
+ "aria-labelledby": labelId,
17
+ "aria-disabled": !isInteractive || void 0,
18
+ disabled: !isInteractive,
19
+ onClick: () => isInteractive && onChange(!checked),
20
+ className: [
21
+ "relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200",
22
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 focus-visible:ring-offset-1",
23
+ checked ? "bg-brand-blue" : "bg-slate-200",
24
+ !isInteractive ? "cursor-not-allowed opacity-60" : "cursor-pointer"
25
+ ].filter(Boolean).join(" "),
26
+ children: /* @__PURE__ */ jsx("span", {
27
+ "aria-hidden": "true",
28
+ className: ["inline-block h-5 w-5 rounded-full bg-white shadow-sm ring-0 transition-transform duration-200", checked ? "translate-x-5" : "translate-x-0"].filter(Boolean).join(" "),
29
+ children: loading && /* @__PURE__ */ jsx("span", {
30
+ className: "flex h-full w-full items-center justify-center",
31
+ children: /* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 animate-spin rounded-full border-2 border-slate-300 border-t-brand-blue" })
32
+ })
33
+ })
34
+ }), (label || description) && /* @__PURE__ */ jsxs("div", {
35
+ className: "min-w-0 pt-0.5",
36
+ children: [label && /* @__PURE__ */ jsx("span", {
37
+ id: labelId,
38
+ className: `block text-sm font-semibold ${disabled ? "text-slate-400" : "text-slate-800"}`,
39
+ children: label
40
+ }), description && /* @__PURE__ */ jsx("span", {
41
+ className: "block text-xs font-medium leading-relaxed text-slate-400",
42
+ children: description
43
+ })]
44
+ })]
45
+ });
46
+ }
47
+ //#endregion
48
+ export { Switch };
49
+
50
+ //# sourceMappingURL=index22.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index22.mjs","names":[],"sources":["../src/ui-library/gallery/switch/Switch.tsx"],"sourcesContent":["/**\n * Switch — Design System Component\n *\n * Communicates an immediate on/off toggle — not a form checkbox.\n * Use Switch when the action takes effect immediately (e.g. toggling a setting).\n * Use Checkbox when the value is submitted as part of a form.\n *\n * Role: switch (ARIA) — announces as \"on\"/\"off\" to screen readers.\n */\n\nimport type { ReactNode } from 'react';\nimport { useId } from 'react';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n label?: ReactNode;\n description?: string;\n disabled?: boolean;\n /** Show a loading spinner in place of the thumb */\n loading?: boolean;\n id?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n description,\n disabled = false,\n loading = false,\n id: externalId,\n}: SwitchProps) {\n const generatedId = useId();\n const id = externalId ?? generatedId;\n const labelId = label ? `${id}-label` : undefined;\n const isInteractive = !disabled && !loading;\n\n return (\n <div className=\"flex items-start gap-3\">\n {/* Track + thumb */}\n <button\n id={id}\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-labelledby={labelId}\n aria-disabled={!isInteractive || undefined}\n disabled={!isInteractive}\n onClick={() => isInteractive && onChange(!checked)}\n className={[\n 'relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 focus-visible:ring-offset-1',\n checked ? 'bg-brand-blue' : 'bg-slate-200',\n !isInteractive ? 'cursor-not-allowed opacity-60' : 'cursor-pointer',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Thumb */}\n <span\n aria-hidden=\"true\"\n className={[\n 'inline-block h-5 w-5 rounded-full bg-white shadow-sm ring-0 transition-transform duration-200',\n checked ? 'translate-x-5' : 'translate-x-0',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Loading spinner inside thumb */}\n {loading && (\n <span className=\"flex h-full w-full items-center justify-center\">\n <span className=\"h-2.5 w-2.5 animate-spin rounded-full border-2 border-slate-300 border-t-brand-blue\" />\n </span>\n )}\n </span>\n </button>\n\n {/* Label + description */}\n {(label || description) && (\n <div className=\"min-w-0 pt-0.5\">\n {label && (\n <span\n id={labelId}\n className={`block text-sm font-semibold ${disabled ? 'text-slate-400' : 'text-slate-800'}`}\n >\n {label}\n </span>\n )}\n {description && (\n <span className=\"block text-xs font-medium leading-relaxed text-slate-400\">\n {description}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;AAwBA,SAAgB,OAAO,EACrB,SACA,UACA,OACA,aACA,WAAW,OACX,UAAU,OACV,IAAI,cACU;CACd,MAAM,cAAc,MAAM;CAC1B,MAAM,KAAK,cAAc;CACzB,MAAM,UAAU,QAAQ,GAAG,GAAG,UAAU,KAAA;CACxC,MAAM,gBAAgB,CAAC,YAAY,CAAC;CAEpC,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CAEE,oBAAC,UAAD;GACM;GACJ,MAAK;GACL,MAAK;GACL,gBAAc;GACd,mBAAiB;GACjB,iBAAe,CAAC,iBAAiB,KAAA;GACjC,UAAU,CAAC;GACX,eAAe,iBAAiB,SAAS,CAAC,OAAO;GACjD,WAAW;IACT;IACA;IACA,UAAU,kBAAkB;IAC5B,CAAC,gBAAgB,kCAAkC;GACrD,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;GAGX,UAAA,oBAAC,QAAD;IACE,eAAY;IACZ,WAAW,CACT,iGACA,UAAU,kBAAkB,eAC9B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;IAGV,UAAA,WACC,oBAAC,QAAD;KAAM,WAAU;KACd,UAAA,oBAAC,QAAD,EAAM,WAAU,sFAAuF,CAAA;IACnG,CAAA;GAEJ,CAAA;EACA,CAAA,IAGN,SAAS,gBACT,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,SACC,oBAAC,QAAD;IACE,IAAI;IACJ,WAAW,+BAA+B,WAAW,mBAAmB;IAEvE,UAAA;GACG,CAAA,GAEP,eACC,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,CAEL;EAEJ,CAAA,CAAA;;AAET"}
@@ -0,0 +1,143 @@
1
+ let react_jsx_runtime = require("react/jsx-runtime");
2
+ let react = require("react");
3
+ let lucide_react = require("lucide-react");
4
+ //#region src/ui-library/gallery/combobox/Combobox.tsx
5
+ /**
6
+ * Combobox — Gallery-native searchable dropdown.
7
+ * Copied from shared/components/PisCombobox.tsx and isolated.
8
+ * No production imports.
9
+ */
10
+ var fieldInputClass = "w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60";
11
+ var fieldInputErrorClass = "border-rose-300 focus:border-rose-400 focus:ring-rose-100";
12
+ function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error }) {
13
+ const [isOpen, setIsOpen] = (0, react.useState)(false);
14
+ const [search, setSearch] = (0, react.useState)(value);
15
+ const [highlightIndex, setHighlightIndex] = (0, react.useState)(-1);
16
+ const inputRef = (0, react.useRef)(null);
17
+ const listRef = (0, react.useRef)(null);
18
+ const wrapperRef = (0, react.useRef)(null);
19
+ const uid = (0, react.useId)();
20
+ const listboxId = `${uid}-listbox`;
21
+ const optionId = (index) => `${uid}-option-${index}`;
22
+ const q = search.toLowerCase().trim();
23
+ const filtered = q.length < 2 ? [] : options.filter((opt) => opt.label.toLowerCase().includes(q)).sort((a, b) => {
24
+ const al = a.label.toLowerCase();
25
+ const bl = b.label.toLowerCase();
26
+ return (al === q ? 0 : al.startsWith(q) ? 1 : al.indexOf(q) + 2) - (bl === q ? 0 : bl.startsWith(q) ? 1 : bl.indexOf(q) + 2);
27
+ });
28
+ const DISPLAY_LIMIT = 100;
29
+ const displayed = filtered.length > DISPLAY_LIMIT ? filtered.slice(0, DISPLAY_LIMIT) : filtered;
30
+ (0, react.useEffect)(() => {
31
+ setSearch(value);
32
+ }, [value]);
33
+ (0, react.useEffect)(() => {
34
+ function handleClickOutside(e) {
35
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setIsOpen(false);
36
+ }
37
+ document.addEventListener("mousedown", handleClickOutside);
38
+ return () => document.removeEventListener("mousedown", handleClickOutside);
39
+ }, []);
40
+ (0, react.useEffect)(() => {
41
+ if (!isOpen) setHighlightIndex(-1);
42
+ }, [isOpen]);
43
+ (0, react.useEffect)(() => {
44
+ if (highlightIndex >= 0 && listRef.current) listRef.current.children[highlightIndex]?.scrollIntoView({ block: "nearest" });
45
+ }, [highlightIndex]);
46
+ const selectOption = (opt) => {
47
+ onChange(opt.value);
48
+ setSearch(opt.label);
49
+ setIsOpen(false);
50
+ inputRef.current?.focus();
51
+ };
52
+ const handleInputChange = (e) => {
53
+ const val = e.target.value;
54
+ setSearch(val);
55
+ onChange(val);
56
+ setIsOpen(true);
57
+ setHighlightIndex(-1);
58
+ };
59
+ const handleKeyDown = (e) => {
60
+ if (e.key === "ArrowDown") {
61
+ e.preventDefault();
62
+ if (!isOpen) {
63
+ setIsOpen(true);
64
+ return;
65
+ }
66
+ setHighlightIndex((prev) => Math.min(prev + 1, displayed.length - 1));
67
+ } else if (e.key === "ArrowUp") {
68
+ e.preventDefault();
69
+ setHighlightIndex((prev) => Math.max(prev - 1, -1));
70
+ } else if (e.key === "Enter") {
71
+ e.preventDefault();
72
+ if (highlightIndex >= 0 && displayed[highlightIndex]) selectOption(displayed[highlightIndex]);
73
+ else if (isOpen) setIsOpen(false);
74
+ } else if (e.key === "Escape") {
75
+ e.preventDefault();
76
+ setIsOpen(false);
77
+ }
78
+ };
79
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
80
+ ref: wrapperRef,
81
+ className: "relative",
82
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
83
+ className: "relative",
84
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
85
+ ref: inputRef,
86
+ type: "text",
87
+ role: "combobox",
88
+ "aria-expanded": isOpen,
89
+ "aria-controls": listboxId,
90
+ "aria-activedescendant": highlightIndex >= 0 ? optionId(highlightIndex) : void 0,
91
+ "aria-autocomplete": "list",
92
+ "aria-invalid": error ? "true" : void 0,
93
+ value: search,
94
+ onChange: handleInputChange,
95
+ onFocus: () => setIsOpen(true),
96
+ onKeyDown: handleKeyDown,
97
+ placeholder,
98
+ disabled,
99
+ className: `${fieldInputClass} pr-8${error ? ` ${fieldInputErrorClass}` : ""}${className ? ` ${className}` : ""}`
100
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, {
101
+ size: 16,
102
+ "aria-hidden": "true",
103
+ className: `absolute right-3 top-1/2 -translate-y-1/2 text-slate-300 pointer-events-none transition-transform ${isOpen ? "rotate-180" : ""}`
104
+ })]
105
+ }), isOpen && !disabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
106
+ ref: listRef,
107
+ id: listboxId,
108
+ role: "listbox",
109
+ className: "absolute z-50 mt-1 w-full bg-white border border-slate-200 rounded-xl shadow-lg max-h-60 overflow-y-auto",
110
+ children: error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
111
+ className: "px-3 py-2 text-sm text-rose-500 font-semibold",
112
+ children: error
113
+ }) : loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
114
+ className: "px-3 py-2 text-sm text-slate-400 font-semibold",
115
+ children: "Loading..."
116
+ }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
117
+ className: "px-3 py-2 text-sm text-slate-400 font-semibold",
118
+ children: q.length < 2 ? "Type at least 2 characters to search..." : "No matches — press Enter to use this value"
119
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [displayed.map((opt, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
120
+ id: optionId(i),
121
+ role: "option",
122
+ "aria-selected": opt.value === value,
123
+ onMouseDown: (e) => {
124
+ e.preventDefault();
125
+ selectOption(opt);
126
+ },
127
+ className: `px-3 py-2 text-sm cursor-pointer transition-colors ${i === highlightIndex ? "bg-blue-50 text-brand-blue font-semibold" : "text-slate-700 hover:bg-slate-50"} ${opt.value === value ? "font-medium" : ""}`,
128
+ children: opt.label
129
+ }, opt.value)), filtered.length > DISPLAY_LIMIT && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
130
+ className: "px-3 py-2 text-xs text-slate-400 font-semibold text-center border-t border-slate-100",
131
+ children: [
132
+ "+",
133
+ filtered.length - DISPLAY_LIMIT,
134
+ " more results — refine your search"
135
+ ]
136
+ })] })
137
+ })]
138
+ });
139
+ }
140
+ //#endregion
141
+ exports.Combobox = Combobox;
142
+
143
+ //# sourceMappingURL=index23.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index23.cjs","names":[],"sources":["../src/ui-library/gallery/combobox/Combobox.tsx"],"sourcesContent":["/**\n * Combobox — Gallery-native searchable dropdown.\n * Copied from shared/components/PisCombobox.tsx and isolated.\n * No production imports.\n */\nimport { useState, useRef, useEffect, useId } from 'react';\nimport { ChevronDown } from 'lucide-react';\n\nexport interface ComboboxProps {\n value: string;\n onChange: (value: string) => void;\n options: { value: string; label: string }[];\n placeholder?: string;\n className?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: string;\n}\n\nconst fieldInputClass =\n 'w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60';\nconst fieldInputErrorClass = 'border-rose-300 focus:border-rose-400 focus:ring-rose-100';\n\nexport function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error }: ComboboxProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [search, setSearch] = useState(value);\n const [highlightIndex, setHighlightIndex] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const uid = useId();\n const listboxId = `${uid}-listbox`;\n const optionId = (index: number) => `${uid}-option-${index}`;\n\n const q = search.toLowerCase().trim();\n const filtered = q.length < 2 ? [] : options.filter(opt =>\n opt.label.toLowerCase().includes(q)\n ).sort((a, b) => {\n const al = a.label.toLowerCase();\n const bl = b.label.toLowerCase();\n const aScore = al === q ? 0 : al.startsWith(q) ? 1 : al.indexOf(q) + 2;\n const bScore = bl === q ? 0 : bl.startsWith(q) ? 1 : bl.indexOf(q) + 2;\n return aScore - bScore;\n });\n const DISPLAY_LIMIT = 100;\n const displayed = filtered.length > DISPLAY_LIMIT ? filtered.slice(0, DISPLAY_LIMIT) : filtered;\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => { setSearch(value); }, [value]);\n\n useEffect(() => {\n function handleClickOutside(e: MouseEvent) {\n if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) setIsOpen(false);\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => { if (!isOpen) setHighlightIndex(-1); }, [isOpen]);\n\n useEffect(() => {\n if (highlightIndex >= 0 && listRef.current) {\n const item = listRef.current.children[highlightIndex] as HTMLElement;\n item?.scrollIntoView({ block: 'nearest' });\n }\n }, [highlightIndex]);\n\n const selectOption = (opt: { value: string; label: string }) => {\n onChange(opt.value);\n setSearch(opt.label);\n setIsOpen(false);\n inputRef.current?.focus();\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearch(val);\n onChange(val);\n setIsOpen(true);\n setHighlightIndex(-1);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!isOpen) { setIsOpen(true); return; }\n setHighlightIndex(prev => Math.min(prev + 1, displayed.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setHighlightIndex(prev => Math.max(prev - 1, -1));\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (highlightIndex >= 0 && displayed[highlightIndex]) selectOption(displayed[highlightIndex]);\n else if (isOpen) setIsOpen(false);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setIsOpen(false);\n }\n };\n\n return (\n <div ref={wrapperRef} className=\"relative\">\n <div className=\"relative\">\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-activedescendant={highlightIndex >= 0 ? optionId(highlightIndex) : undefined}\n aria-autocomplete=\"list\"\n aria-invalid={error ? 'true' : undefined}\n value={search}\n onChange={handleInputChange}\n onFocus={() => setIsOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n className={`${fieldInputClass} pr-8${error ? ` ${fieldInputErrorClass}` : ''}${className ? ` ${className}` : ''}`}\n />\n <ChevronDown\n size={16}\n aria-hidden=\"true\"\n className={`absolute right-3 top-1/2 -translate-y-1/2 text-slate-300 pointer-events-none transition-transform ${isOpen ? 'rotate-180' : ''}`}\n />\n </div>\n\n {isOpen && !disabled && (\n <div ref={listRef} id={listboxId} role=\"listbox\"\n className=\"absolute z-50 mt-1 w-full bg-white border border-slate-200 rounded-xl shadow-lg max-h-60 overflow-y-auto\"\n >\n {error ? (\n <div className=\"px-3 py-2 text-sm text-rose-500 font-semibold\">{error}</div>\n ) : loading ? (\n <div className=\"px-3 py-2 text-sm text-slate-400 font-semibold\">Loading...</div>\n ) : filtered.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-slate-400 font-semibold\">\n {q.length < 2 ? 'Type at least 2 characters to search...' : 'No matches — press Enter to use this value'}\n </div>\n ) : (\n <>\n {displayed.map((opt, i) => (\n <div key={opt.value} id={optionId(i)} role=\"option\" aria-selected={opt.value === value}\n onMouseDown={(e) => { e.preventDefault(); selectOption(opt); }}\n className={`px-3 py-2 text-sm cursor-pointer transition-colors ${i === highlightIndex ? 'bg-blue-50 text-brand-blue font-semibold' : 'text-slate-700 hover:bg-slate-50'} ${opt.value === value ? 'font-medium' : ''}`}\n >\n {opt.label}\n </div>\n ))}\n {filtered.length > DISPLAY_LIMIT && (\n <div className=\"px-3 py-2 text-xs text-slate-400 font-semibold text-center border-t border-slate-100\">\n +{filtered.length - DISPLAY_LIMIT} more results — refine your search\n </div>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ import { ChevronDown } from "lucide-react";
4
+ //#region src/ui-library/gallery/combobox/Combobox.tsx
5
+ /**
6
+ * Combobox — Gallery-native searchable dropdown.
7
+ * Copied from shared/components/PisCombobox.tsx and isolated.
8
+ * No production imports.
9
+ */
10
+ var fieldInputClass = "w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60";
11
+ var fieldInputErrorClass = "border-rose-300 focus:border-rose-400 focus:ring-rose-100";
12
+ function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error }) {
13
+ const [isOpen, setIsOpen] = useState(false);
14
+ const [search, setSearch] = useState(value);
15
+ const [highlightIndex, setHighlightIndex] = useState(-1);
16
+ const inputRef = useRef(null);
17
+ const listRef = useRef(null);
18
+ const wrapperRef = useRef(null);
19
+ const uid = useId();
20
+ const listboxId = `${uid}-listbox`;
21
+ const optionId = (index) => `${uid}-option-${index}`;
22
+ const q = search.toLowerCase().trim();
23
+ const filtered = q.length < 2 ? [] : options.filter((opt) => opt.label.toLowerCase().includes(q)).sort((a, b) => {
24
+ const al = a.label.toLowerCase();
25
+ const bl = b.label.toLowerCase();
26
+ return (al === q ? 0 : al.startsWith(q) ? 1 : al.indexOf(q) + 2) - (bl === q ? 0 : bl.startsWith(q) ? 1 : bl.indexOf(q) + 2);
27
+ });
28
+ const DISPLAY_LIMIT = 100;
29
+ const displayed = filtered.length > DISPLAY_LIMIT ? filtered.slice(0, DISPLAY_LIMIT) : filtered;
30
+ useEffect(() => {
31
+ setSearch(value);
32
+ }, [value]);
33
+ useEffect(() => {
34
+ function handleClickOutside(e) {
35
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setIsOpen(false);
36
+ }
37
+ document.addEventListener("mousedown", handleClickOutside);
38
+ return () => document.removeEventListener("mousedown", handleClickOutside);
39
+ }, []);
40
+ useEffect(() => {
41
+ if (!isOpen) setHighlightIndex(-1);
42
+ }, [isOpen]);
43
+ useEffect(() => {
44
+ if (highlightIndex >= 0 && listRef.current) listRef.current.children[highlightIndex]?.scrollIntoView({ block: "nearest" });
45
+ }, [highlightIndex]);
46
+ const selectOption = (opt) => {
47
+ onChange(opt.value);
48
+ setSearch(opt.label);
49
+ setIsOpen(false);
50
+ inputRef.current?.focus();
51
+ };
52
+ const handleInputChange = (e) => {
53
+ const val = e.target.value;
54
+ setSearch(val);
55
+ onChange(val);
56
+ setIsOpen(true);
57
+ setHighlightIndex(-1);
58
+ };
59
+ const handleKeyDown = (e) => {
60
+ if (e.key === "ArrowDown") {
61
+ e.preventDefault();
62
+ if (!isOpen) {
63
+ setIsOpen(true);
64
+ return;
65
+ }
66
+ setHighlightIndex((prev) => Math.min(prev + 1, displayed.length - 1));
67
+ } else if (e.key === "ArrowUp") {
68
+ e.preventDefault();
69
+ setHighlightIndex((prev) => Math.max(prev - 1, -1));
70
+ } else if (e.key === "Enter") {
71
+ e.preventDefault();
72
+ if (highlightIndex >= 0 && displayed[highlightIndex]) selectOption(displayed[highlightIndex]);
73
+ else if (isOpen) setIsOpen(false);
74
+ } else if (e.key === "Escape") {
75
+ e.preventDefault();
76
+ setIsOpen(false);
77
+ }
78
+ };
79
+ return /* @__PURE__ */ jsxs("div", {
80
+ ref: wrapperRef,
81
+ className: "relative",
82
+ children: [/* @__PURE__ */ jsxs("div", {
83
+ className: "relative",
84
+ children: [/* @__PURE__ */ jsx("input", {
85
+ ref: inputRef,
86
+ type: "text",
87
+ role: "combobox",
88
+ "aria-expanded": isOpen,
89
+ "aria-controls": listboxId,
90
+ "aria-activedescendant": highlightIndex >= 0 ? optionId(highlightIndex) : void 0,
91
+ "aria-autocomplete": "list",
92
+ "aria-invalid": error ? "true" : void 0,
93
+ value: search,
94
+ onChange: handleInputChange,
95
+ onFocus: () => setIsOpen(true),
96
+ onKeyDown: handleKeyDown,
97
+ placeholder,
98
+ disabled,
99
+ className: `${fieldInputClass} pr-8${error ? ` ${fieldInputErrorClass}` : ""}${className ? ` ${className}` : ""}`
100
+ }), /* @__PURE__ */ jsx(ChevronDown, {
101
+ size: 16,
102
+ "aria-hidden": "true",
103
+ className: `absolute right-3 top-1/2 -translate-y-1/2 text-slate-300 pointer-events-none transition-transform ${isOpen ? "rotate-180" : ""}`
104
+ })]
105
+ }), isOpen && !disabled && /* @__PURE__ */ jsx("div", {
106
+ ref: listRef,
107
+ id: listboxId,
108
+ role: "listbox",
109
+ className: "absolute z-50 mt-1 w-full bg-white border border-slate-200 rounded-xl shadow-lg max-h-60 overflow-y-auto",
110
+ children: error ? /* @__PURE__ */ jsx("div", {
111
+ className: "px-3 py-2 text-sm text-rose-500 font-semibold",
112
+ children: error
113
+ }) : loading ? /* @__PURE__ */ jsx("div", {
114
+ className: "px-3 py-2 text-sm text-slate-400 font-semibold",
115
+ children: "Loading..."
116
+ }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", {
117
+ className: "px-3 py-2 text-sm text-slate-400 font-semibold",
118
+ children: q.length < 2 ? "Type at least 2 characters to search..." : "No matches — press Enter to use this value"
119
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [displayed.map((opt, i) => /* @__PURE__ */ jsx("div", {
120
+ id: optionId(i),
121
+ role: "option",
122
+ "aria-selected": opt.value === value,
123
+ onMouseDown: (e) => {
124
+ e.preventDefault();
125
+ selectOption(opt);
126
+ },
127
+ className: `px-3 py-2 text-sm cursor-pointer transition-colors ${i === highlightIndex ? "bg-blue-50 text-brand-blue font-semibold" : "text-slate-700 hover:bg-slate-50"} ${opt.value === value ? "font-medium" : ""}`,
128
+ children: opt.label
129
+ }, opt.value)), filtered.length > DISPLAY_LIMIT && /* @__PURE__ */ jsxs("div", {
130
+ className: "px-3 py-2 text-xs text-slate-400 font-semibold text-center border-t border-slate-100",
131
+ children: [
132
+ "+",
133
+ filtered.length - DISPLAY_LIMIT,
134
+ " more results — refine your search"
135
+ ]
136
+ })] })
137
+ })]
138
+ });
139
+ }
140
+ //#endregion
141
+ export { Combobox };
142
+
143
+ //# sourceMappingURL=index23.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index23.mjs","names":[],"sources":["../src/ui-library/gallery/combobox/Combobox.tsx"],"sourcesContent":["/**\n * Combobox — Gallery-native searchable dropdown.\n * Copied from shared/components/PisCombobox.tsx and isolated.\n * No production imports.\n */\nimport { useState, useRef, useEffect, useId } from 'react';\nimport { ChevronDown } from 'lucide-react';\n\nexport interface ComboboxProps {\n value: string;\n onChange: (value: string) => void;\n options: { value: string; label: string }[];\n placeholder?: string;\n className?: string;\n disabled?: boolean;\n loading?: boolean;\n error?: string;\n}\n\nconst fieldInputClass =\n 'w-full rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15 disabled:cursor-not-allowed disabled:opacity-60';\nconst fieldInputErrorClass = 'border-rose-300 focus:border-rose-400 focus:ring-rose-100';\n\nexport function Combobox({ value, onChange, options, placeholder, className, disabled, loading, error }: ComboboxProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [search, setSearch] = useState(value);\n const [highlightIndex, setHighlightIndex] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const uid = useId();\n const listboxId = `${uid}-listbox`;\n const optionId = (index: number) => `${uid}-option-${index}`;\n\n const q = search.toLowerCase().trim();\n const filtered = q.length < 2 ? [] : options.filter(opt =>\n opt.label.toLowerCase().includes(q)\n ).sort((a, b) => {\n const al = a.label.toLowerCase();\n const bl = b.label.toLowerCase();\n const aScore = al === q ? 0 : al.startsWith(q) ? 1 : al.indexOf(q) + 2;\n const bScore = bl === q ? 0 : bl.startsWith(q) ? 1 : bl.indexOf(q) + 2;\n return aScore - bScore;\n });\n const DISPLAY_LIMIT = 100;\n const displayed = filtered.length > DISPLAY_LIMIT ? filtered.slice(0, DISPLAY_LIMIT) : filtered;\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => { setSearch(value); }, [value]);\n\n useEffect(() => {\n function handleClickOutside(e: MouseEvent) {\n if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) setIsOpen(false);\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => { if (!isOpen) setHighlightIndex(-1); }, [isOpen]);\n\n useEffect(() => {\n if (highlightIndex >= 0 && listRef.current) {\n const item = listRef.current.children[highlightIndex] as HTMLElement;\n item?.scrollIntoView({ block: 'nearest' });\n }\n }, [highlightIndex]);\n\n const selectOption = (opt: { value: string; label: string }) => {\n onChange(opt.value);\n setSearch(opt.label);\n setIsOpen(false);\n inputRef.current?.focus();\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n setSearch(val);\n onChange(val);\n setIsOpen(true);\n setHighlightIndex(-1);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!isOpen) { setIsOpen(true); return; }\n setHighlightIndex(prev => Math.min(prev + 1, displayed.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setHighlightIndex(prev => Math.max(prev - 1, -1));\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (highlightIndex >= 0 && displayed[highlightIndex]) selectOption(displayed[highlightIndex]);\n else if (isOpen) setIsOpen(false);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setIsOpen(false);\n }\n };\n\n return (\n <div ref={wrapperRef} className=\"relative\">\n <div className=\"relative\">\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-activedescendant={highlightIndex >= 0 ? optionId(highlightIndex) : undefined}\n aria-autocomplete=\"list\"\n aria-invalid={error ? 'true' : undefined}\n value={search}\n onChange={handleInputChange}\n onFocus={() => setIsOpen(true)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n className={`${fieldInputClass} pr-8${error ? ` ${fieldInputErrorClass}` : ''}${className ? ` ${className}` : ''}`}\n />\n <ChevronDown\n size={16}\n aria-hidden=\"true\"\n className={`absolute right-3 top-1/2 -translate-y-1/2 text-slate-300 pointer-events-none transition-transform ${isOpen ? 'rotate-180' : ''}`}\n />\n </div>\n\n {isOpen && !disabled && (\n <div ref={listRef} id={listboxId} role=\"listbox\"\n className=\"absolute z-50 mt-1 w-full bg-white border border-slate-200 rounded-xl shadow-lg max-h-60 overflow-y-auto\"\n >\n {error ? (\n <div className=\"px-3 py-2 text-sm text-rose-500 font-semibold\">{error}</div>\n ) : loading ? (\n <div className=\"px-3 py-2 text-sm text-slate-400 font-semibold\">Loading...</div>\n ) : filtered.length === 0 ? (\n <div className=\"px-3 py-2 text-sm text-slate-400 font-semibold\">\n {q.length < 2 ? 'Type at least 2 characters to search...' : 'No matches — press Enter to use this value'}\n </div>\n ) : (\n <>\n {displayed.map((opt, i) => (\n <div key={opt.value} id={optionId(i)} role=\"option\" aria-selected={opt.value === value}\n onMouseDown={(e) => { e.preventDefault(); selectOption(opt); }}\n className={`px-3 py-2 text-sm cursor-pointer transition-colors ${i === highlightIndex ? 'bg-blue-50 text-brand-blue font-semibold' : 'text-slate-700 hover:bg-slate-50'} ${opt.value === value ? 'font-medium' : ''}`}\n >\n {opt.label}\n </div>\n ))}\n {filtered.length > DISPLAY_LIMIT && (\n <div className=\"px-3 py-2 text-xs text-slate-400 font-semibold text-center border-t border-slate-100\">\n +{filtered.length - DISPLAY_LIMIT} more results — refine your search\n </div>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ const require_runtime = require("./index2.cjs");
2
+ const require_FieldContext = require("./index12.cjs");
3
+ ;/* empty css */
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+ let react = require("react");
6
+ let lucide_react = require("lucide-react");
7
+ let react_calendar = require("react-calendar");
8
+ react_calendar = require_runtime.__toESM(react_calendar, 1);
9
+ let date_fns = require("date-fns");
10
+ //#region src/ui-library/gallery/date-picker/DatePicker.tsx
11
+ /**
12
+ * DatePicker — Gallery-native date picker.
13
+ * Copied from shared/components/PisDatePicker.tsx.
14
+ * Updated to import FieldContext from gallery-local field directory.
15
+ * Uses react-calendar and date-fns.
16
+ * Note: CSS for .pis-datepicker-popover and .pis-rc-calendar is in index.css.
17
+ */
18
+ var MAX_DATE = new Date(2026, 11, 31);
19
+ var POPOVER_WIDTH = 352;
20
+ var CALENDAR_HEIGHT = 360;
21
+ function DatePicker({ value, onChange, placeholder, className, disabled, error, minDate, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, required }) {
22
+ const [isOpen, setIsOpen] = (0, react.useState)(false);
23
+ const [popupStyle, setPopupStyle] = (0, react.useState)({});
24
+ const wrapperRef = (0, react.useRef)(null);
25
+ const inputRef = (0, react.useRef)(null);
26
+ const internalId = (0, react.useId)();
27
+ const ctx = require_FieldContext.useFieldContext();
28
+ const inputId = id ?? ctx?.inputId ?? internalId;
29
+ const resolvedRequired = required ?? ctx?.required ?? false;
30
+ const resolvedInvalid = error ? true : ctx?.invalid ?? false;
31
+ const describedBy = ctx?.invalid && ctx?.errorId ? ctx.errorId : void 0;
32
+ const selectedDate = value ? (() => {
33
+ const d = (0, date_fns.parse)(value, "yyyy-MM-dd", /* @__PURE__ */ new Date());
34
+ if ((0, date_fns.isValid)(d)) return d;
35
+ const d2 = new Date(value);
36
+ return isNaN(d2.getTime()) ? void 0 : d2;
37
+ })() : void 0;
38
+ const displayValue = selectedDate ? (0, date_fns.format)(selectedDate, "MMM d, yyyy") : "";
39
+ const skipNextOpen = (0, react.useRef)(false);
40
+ const openPopup = (0, react.useCallback)(() => {
41
+ if (disabled || !wrapperRef.current) return;
42
+ if (skipNextOpen.current) {
43
+ skipNextOpen.current = false;
44
+ return;
45
+ }
46
+ const rect = wrapperRef.current.getBoundingClientRect();
47
+ const spaceBelow = window.innerHeight - rect.bottom;
48
+ const spaceAbove = rect.top;
49
+ const isNarrow = window.innerWidth < 368;
50
+ const style = {
51
+ position: "fixed",
52
+ left: isNarrow ? 8 : Math.max(8, Math.min(rect.left, window.innerWidth - POPOVER_WIDTH - 8)),
53
+ width: isNarrow ? `calc(100vw - 16px)` : void 0
54
+ };
55
+ if (spaceBelow >= CALENDAR_HEIGHT || spaceBelow >= spaceAbove) style.top = rect.bottom + 6;
56
+ else style.top = rect.top - CALENDAR_HEIGHT - 6;
57
+ setPopupStyle(style);
58
+ setIsOpen(true);
59
+ }, [disabled]);
60
+ (0, react.useEffect)(() => {
61
+ function handleClickOutside(e) {
62
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) setIsOpen(false);
63
+ }
64
+ document.addEventListener("mousedown", handleClickOutside);
65
+ return () => document.removeEventListener("mousedown", handleClickOutside);
66
+ }, []);
67
+ (0, react.useEffect)(() => {
68
+ if (!isOpen) return;
69
+ function handleScroll() {
70
+ setIsOpen(false);
71
+ }
72
+ window.addEventListener("scroll", handleScroll, { capture: true });
73
+ window.addEventListener("resize", handleScroll);
74
+ return () => {
75
+ window.removeEventListener("scroll", handleScroll, { capture: true });
76
+ window.removeEventListener("resize", handleScroll);
77
+ };
78
+ }, [isOpen]);
79
+ (0, react.useEffect)(() => {
80
+ if (!isOpen) return;
81
+ function handleFocusOut(e) {
82
+ if (!e.relatedTarget) return;
83
+ if (wrapperRef.current && !wrapperRef.current.contains(e.relatedTarget)) setIsOpen(false);
84
+ }
85
+ const wrapper = wrapperRef.current;
86
+ wrapper?.addEventListener("focusout", handleFocusOut);
87
+ return () => wrapper?.removeEventListener("focusout", handleFocusOut);
88
+ }, [isOpen]);
89
+ function handleKeyDown(e) {
90
+ if (e.key === "Escape") {
91
+ e.preventDefault();
92
+ setIsOpen(false);
93
+ inputRef.current?.focus();
94
+ return;
95
+ }
96
+ if (e.key === " " || e.key === "Enter") {
97
+ e.preventDefault();
98
+ if (isOpen) setIsOpen(false);
99
+ else openPopup();
100
+ }
101
+ }
102
+ const inputClasses = [
103
+ "w-full rounded-xl border bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 pr-8 cursor-pointer select-none",
104
+ error ? "border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100" : "border-slate-200 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15",
105
+ disabled ? "cursor-not-allowed opacity-60" : "",
106
+ className ?? ""
107
+ ].filter(Boolean).join(" ");
108
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
109
+ ref: wrapperRef,
110
+ className: "relative",
111
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
112
+ className: "relative",
113
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
114
+ ref: inputRef,
115
+ id: inputId,
116
+ type: "text",
117
+ readOnly: true,
118
+ value: displayValue,
119
+ onFocus: openPopup,
120
+ onClick: openPopup,
121
+ onKeyDown: handleKeyDown,
122
+ placeholder,
123
+ disabled,
124
+ "aria-label": ariaLabel,
125
+ "aria-labelledby": ariaLabelledBy,
126
+ "aria-required": resolvedRequired ? "true" : void 0,
127
+ "aria-invalid": resolvedInvalid ? "true" : void 0,
128
+ "aria-describedby": describedBy,
129
+ "aria-haspopup": "dialog",
130
+ "aria-expanded": isOpen,
131
+ role: "combobox",
132
+ className: inputClasses
133
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CalendarDays, {
134
+ size: 16,
135
+ className: `absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none ${isOpen ? "text-brand-blue" : "text-slate-300"}`,
136
+ "aria-hidden": "true"
137
+ })]
138
+ }), isOpen && !disabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
139
+ className: "pis-datepicker-popover",
140
+ style: popupStyle,
141
+ role: "dialog",
142
+ "aria-label": ariaLabel ? `${ariaLabel} calendar` : "Date picker",
143
+ "aria-modal": "false",
144
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_calendar.default, {
145
+ value: selectedDate ?? null,
146
+ onChange: (val) => {
147
+ if (val instanceof Date) {
148
+ onChange((0, date_fns.format)(val, "yyyy-MM-dd"));
149
+ setIsOpen(false);
150
+ skipNextOpen.current = true;
151
+ requestAnimationFrame(() => inputRef.current?.focus());
152
+ }
153
+ },
154
+ defaultActiveStartDate: selectedDate ?? minDate,
155
+ minDate,
156
+ maxDate: MAX_DATE,
157
+ defaultView: "month",
158
+ showNeighboringDecade: true,
159
+ showNeighboringCentury: true,
160
+ prevLabel: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, { size: 14 }),
161
+ nextLabel: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { size: 14 }),
162
+ prev2Label: null,
163
+ next2Label: null,
164
+ navigationLabel: ({ date, view }) => {
165
+ if (view === "month") return (0, date_fns.format)(date, "MMMM yyyy");
166
+ if (view === "year") return (0, date_fns.format)(date, "yyyy");
167
+ return `${Math.floor(date.getFullYear() / 10) * 10} – ${Math.floor(date.getFullYear() / 10) * 10 + 9}`;
168
+ },
169
+ className: "pis-rc-calendar"
170
+ }, isOpen ? "open" : "closed")
171
+ })]
172
+ });
173
+ }
174
+ //#endregion
175
+ exports.DatePicker = DatePicker;
176
+
177
+ //# sourceMappingURL=index25.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index25.cjs","names":[],"sources":["../src/ui-library/gallery/date-picker/DatePicker.tsx"],"sourcesContent":["/**\n * DatePicker — Gallery-native date picker.\n * Copied from shared/components/PisDatePicker.tsx.\n * Updated to import FieldContext from gallery-local field directory.\n * Uses react-calendar and date-fns.\n * Note: CSS for .pis-datepicker-popover and .pis-rc-calendar is in index.css.\n */\nimport { useState, useRef, useEffect, useCallback, useId } from 'react';\nimport Calendar from 'react-calendar';\nimport { format, parse, isValid } from 'date-fns';\nimport { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react';\nimport 'react-calendar/dist/Calendar.css';\nimport { useFieldContext } from '../field/FieldContext';\n\ninterface DatePickerProps {\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n className?: string;\n disabled?: boolean;\n error?: string;\n minDate?: Date;\n id?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n required?: boolean;\n}\n\nconst MAX_DATE = new Date(2026, 11, 31);\nconst CALENDAR_WIDTH = 320;\nconst POPOVER_WIDTH = CALENDAR_WIDTH + 32;\nconst CALENDAR_HEIGHT = 360;\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n className,\n disabled,\n error,\n minDate,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n required,\n}: DatePickerProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [popupStyle, setPopupStyle] = useState<React.CSSProperties>({});\n const wrapperRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const internalId = useId();\n\n const ctx = useFieldContext();\n const inputId = id ?? ctx?.inputId ?? internalId;\n const resolvedRequired = required ?? ctx?.required ?? false;\n const resolvedInvalid = error ? true : (ctx?.invalid ?? false);\n const describedBy = ctx?.invalid && ctx?.errorId ? ctx.errorId : undefined;\n\n const selectedDate = value\n ? (() => {\n const d = parse(value, 'yyyy-MM-dd', new Date());\n if (isValid(d)) return d;\n const d2 = new Date(value);\n return isNaN(d2.getTime()) ? undefined : d2;\n })()\n : undefined;\n\n const displayValue = selectedDate ? format(selectedDate, 'MMM d, yyyy') : '';\n\n const skipNextOpen = useRef(false);\n\n const openPopup = useCallback(() => {\n if (disabled || !wrapperRef.current) return;\n if (skipNextOpen.current) {\n skipNextOpen.current = false;\n return;\n }\n const rect = wrapperRef.current.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n\n const isNarrow = window.innerWidth < POPOVER_WIDTH + 16;\n const style: React.CSSProperties = {\n position: 'fixed',\n left: isNarrow ? 8 : Math.max(8, Math.min(rect.left, window.innerWidth - POPOVER_WIDTH - 8)),\n width: isNarrow ? `calc(100vw - 16px)` : undefined,\n };\n\n if (spaceBelow >= CALENDAR_HEIGHT || spaceBelow >= spaceAbove) {\n style.top = rect.bottom + 6;\n } else {\n style.top = rect.top - CALENDAR_HEIGHT - 6;\n }\n\n setPopupStyle(style);\n setIsOpen(true);\n }, [disabled]);\n\n useEffect(() => {\n function handleClickOutside(e: MouseEvent) {\n if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) {\n setIsOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n useEffect(() => {\n if (!isOpen) return;\n function handleScroll() { setIsOpen(false); }\n window.addEventListener('scroll', handleScroll, { capture: true });\n window.addEventListener('resize', handleScroll);\n return () => {\n window.removeEventListener('scroll', handleScroll, { capture: true });\n window.removeEventListener('resize', handleScroll);\n };\n }, [isOpen]);\n\n useEffect(() => {\n if (!isOpen) return;\n function handleFocusOut(e: FocusEvent) {\n if (!e.relatedTarget) return;\n if (wrapperRef.current && !wrapperRef.current.contains(e.relatedTarget as Node)) {\n setIsOpen(false);\n }\n }\n const wrapper = wrapperRef.current;\n wrapper?.addEventListener('focusout', handleFocusOut);\n return () => wrapper?.removeEventListener('focusout', handleFocusOut);\n }, [isOpen]);\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (e.key === 'Escape') {\n e.preventDefault();\n setIsOpen(false);\n inputRef.current?.focus();\n return;\n }\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n if (isOpen) setIsOpen(false);\n else openPopup();\n }\n }\n\n const inputClasses = [\n 'w-full rounded-xl border bg-slate-50 px-4 py-2.5 text-sm font-medium text-slate-900 outline-none transition placeholder:text-slate-400 pr-8 cursor-pointer select-none',\n error ? 'border-rose-300 focus:border-rose-400 focus:ring-2 focus:ring-rose-100' : 'border-slate-200 focus:border-brand-blue/40 focus:ring-2 focus:ring-brand-blue/15',\n disabled ? 'cursor-not-allowed opacity-60' : '',\n className ?? '',\n ].filter(Boolean).join(' ');\n\n return (\n <div ref={wrapperRef} className=\"relative\">\n <div className=\"relative\">\n <input\n ref={inputRef}\n id={inputId}\n type=\"text\"\n readOnly\n value={displayValue}\n onFocus={openPopup}\n onClick={openPopup}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-required={resolvedRequired ? 'true' : undefined}\n aria-invalid={resolvedInvalid ? 'true' : undefined}\n aria-describedby={describedBy}\n aria-haspopup=\"dialog\"\n aria-expanded={isOpen}\n role=\"combobox\"\n className={inputClasses}\n />\n <CalendarDays\n size={16}\n className={`absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none ${isOpen ? 'text-brand-blue' : 'text-slate-300'}`}\n aria-hidden=\"true\"\n />\n </div>\n\n {isOpen && !disabled && (\n <div\n className=\"pis-datepicker-popover\"\n style={popupStyle}\n role=\"dialog\"\n aria-label={ariaLabel ? `${ariaLabel} calendar` : 'Date picker'}\n aria-modal=\"false\"\n >\n <Calendar\n key={isOpen ? 'open' : 'closed'}\n value={selectedDate ?? null}\n onChange={(val) => {\n if (val instanceof Date) {\n onChange(format(val, 'yyyy-MM-dd'));\n setIsOpen(false);\n skipNextOpen.current = true;\n requestAnimationFrame(() => inputRef.current?.focus());\n }\n }}\n defaultActiveStartDate={selectedDate ?? minDate}\n minDate={minDate}\n maxDate={MAX_DATE}\n defaultView=\"month\"\n showNeighboringDecade={true}\n showNeighboringCentury={true}\n prevLabel={<ChevronLeft size={14} />}\n nextLabel={<ChevronRight size={14} />}\n prev2Label={null}\n next2Label={null}\n navigationLabel={({ date, view }) => {\n if (view === 'month') return format(date, 'MMMM yyyy');\n if (view === 'year') return format(date, 'yyyy');\n return `${Math.floor(date.getFullYear() / 10) * 10} – ${Math.floor(date.getFullYear() / 10) * 10 + 9}`;\n }}\n className=\"pis-rc-calendar\"\n />\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}