@devslab/dds-solid 0.23.0 → 0.24.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 (87) hide show
  1. package/README.ko.md +15 -3
  2. package/README.md +15 -3
  3. package/dist/assets/{calendar-view-1RO2mtf1.js → calendar-view-BBQGmkJ7.js} +181 -145
  4. package/dist/assets/calendar-view-BBQGmkJ7.js.map +1 -0
  5. package/dist/assets/{choice-DoXiK8nc.js → choice-DPmk9AHn.js} +41 -29
  6. package/dist/assets/choice-DPmk9AHn.js.map +1 -0
  7. package/dist/assets/choice-types-h4YVL8xH.js +24 -0
  8. package/dist/assets/choice-types-h4YVL8xH.js.map +1 -0
  9. package/dist/assets/date-only-0Ldsjp43.js +174 -0
  10. package/dist/assets/date-only-0Ldsjp43.js.map +1 -0
  11. package/dist/assets/direction-BpTqmXs-.js +24 -0
  12. package/dist/assets/direction-BpTqmXs-.js.map +1 -0
  13. package/dist/calendar-view-CZLsC57_.js +481 -0
  14. package/dist/calendar-view-CZLsC57_.js.map +1 -0
  15. package/dist/calendar-view.d.ts +10 -0
  16. package/dist/calendar-view.d.ts.map +1 -1
  17. package/dist/calendar.js +7 -6
  18. package/dist/calendar.js.map +1 -1
  19. package/dist/calendar.server.js +2 -1
  20. package/dist/calendar.server.js.map +1 -1
  21. package/dist/choice-CTNeFOVo.js +403 -0
  22. package/dist/choice-CTNeFOVo.js.map +1 -0
  23. package/dist/choice-types-kSaEnZPr.js +23 -0
  24. package/dist/choice-types-kSaEnZPr.js.map +1 -0
  25. package/dist/combobox.js +1 -1
  26. package/dist/combobox.server.js +1 -1
  27. package/dist/date-only-Bu4UmsTP.js +151 -0
  28. package/dist/date-only-Bu4UmsTP.js.map +1 -0
  29. package/dist/date-only.d.ts +92 -0
  30. package/dist/date-only.d.ts.map +1 -1
  31. package/dist/date-picker.js +51 -50
  32. package/dist/date-picker.js.map +1 -1
  33. package/dist/date-picker.server.js +2 -1
  34. package/dist/date-picker.server.js.map +1 -1
  35. package/dist/date-range-picker.d.ts +41 -0
  36. package/dist/date-range-picker.d.ts.map +1 -0
  37. package/dist/date-range-picker.js +368 -0
  38. package/dist/date-range-picker.js.map +1 -0
  39. package/dist/date-range-picker.server.js +347 -0
  40. package/dist/date-range-picker.server.js.map +1 -0
  41. package/dist/direction-CS85IDNU.js +21 -0
  42. package/dist/direction-CS85IDNU.js.map +1 -0
  43. package/dist/index.d.ts +5 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +168 -179
  46. package/dist/index.js.map +1 -1
  47. package/dist/internal/choice.d.ts +25 -3
  48. package/dist/internal/choice.d.ts.map +1 -1
  49. package/dist/month-picker.d.ts +33 -0
  50. package/dist/month-picker.d.ts.map +1 -0
  51. package/dist/month-picker.js +287 -0
  52. package/dist/month-picker.js.map +1 -0
  53. package/dist/month-picker.server.js +282 -0
  54. package/dist/month-picker.server.js.map +1 -0
  55. package/dist/number-input.d.ts +53 -0
  56. package/dist/number-input.d.ts.map +1 -0
  57. package/dist/number-input.js +267 -0
  58. package/dist/number-input.js.map +1 -0
  59. package/dist/number-input.server.js +237 -0
  60. package/dist/number-input.server.js.map +1 -0
  61. package/dist/segmented-control.d.ts +40 -0
  62. package/dist/segmented-control.d.ts.map +1 -0
  63. package/dist/segmented-control.js +133 -0
  64. package/dist/segmented-control.js.map +1 -0
  65. package/dist/segmented-control.server.js +138 -0
  66. package/dist/segmented-control.server.js.map +1 -0
  67. package/dist/select-picker.js +1 -1
  68. package/dist/select-picker.server.js +1 -1
  69. package/dist/server.js +8 -22
  70. package/dist/server.js.map +1 -1
  71. package/dist/time-only.d.ts +32 -0
  72. package/dist/time-only.d.ts.map +1 -0
  73. package/dist/time-picker-BlMWCQwk.js +113 -0
  74. package/dist/time-picker-BlMWCQwk.js.map +1 -0
  75. package/dist/time-picker.d.ts +34 -0
  76. package/dist/time-picker.d.ts.map +1 -0
  77. package/dist/time-picker.js +2 -0
  78. package/dist/time-picker.server.js +152 -0
  79. package/dist/time-picker.server.js.map +1 -0
  80. package/package.json +44 -4
  81. package/styles.css +31 -1
  82. package/dist/assets/calendar-view-1RO2mtf1.js.map +0 -1
  83. package/dist/assets/choice-DoXiK8nc.js.map +0 -1
  84. package/dist/calendar-view-CTBTPB4T.js +0 -444
  85. package/dist/calendar-view-CTBTPB4T.js.map +0 -1
  86. package/dist/choice-BPMiJlPJ.js +0 -395
  87. package/dist/choice-BPMiJlPJ.js.map +0 -1
@@ -1,29 +1,9 @@
1
+ import { n as choiceWarningsEnabled, r as validateOptions, t as choiceMessages } from "./choice-types-h4YVL8xH.js";
1
2
  import { For, Show, createEffect, createMemo, createSignal, createUniqueId, onCleanup, onMount, untrack } from "solid-js";
2
3
  import { Portal, createComponent, escape, memo, mergeProps as mergeProps$1, ssr, ssrAttribute, ssrHydrationKey, ssrStyle, ssrStyleProperty } from "solid-js/web";
3
4
  import { Combobox, createListCollection } from "@ark-ui/solid/combobox";
4
5
  import { Select } from "@ark-ui/solid/select";
5
6
  import { createVirtualizer, defaultRangeExtractor } from "@tanstack/solid-virtual";
6
- //#region src/choice-types.ts
7
- function validateOptions(items) {
8
- const ids = /* @__PURE__ */ new Set();
9
- for (const item of items) {
10
- if (!item.value || ids.has(item.value)) throw new Error(`DDS choice: option IDs must be nonempty and unique (${JSON.stringify(item.value)})`);
11
- ids.add(item.value);
12
- }
13
- }
14
- var choiceMessages = {
15
- open: "선택 열기",
16
- clear: "선택 지우기",
17
- loading: "불러오는 중",
18
- empty: "결과 없음",
19
- error: "불러오지 못했습니다",
20
- retry: "다시 시도"
21
- };
22
- /** Read the consumer environment at runtime, rather than the library build mode. */
23
- function choiceWarningsEnabled() {
24
- return globalThis.process?.env?.NODE_ENV !== "production";
25
- }
26
- //#endregion
27
7
  //#region src/internal/choice.tsx
28
8
  var _tmpl$ = [
29
9
  "<button",
@@ -78,6 +58,7 @@ function Choice(props) {
78
58
  const [portalMount, setPortalMount] = createSignal();
79
59
  onMount(() => {});
80
60
  let composing = false;
61
+ let consumedOnBlur = null;
81
62
  let pendingRestore = null;
82
63
  const resolveLabel = (id) => props.items.find((item) => item.value === id)?.label ?? (props.selectedOption?.value === id ? props.selectedOption.label : id);
83
64
  const blocked = () => props.disabled || props.readOnly;
@@ -129,8 +110,9 @@ function Choice(props) {
129
110
  createEffect(() => {
130
111
  const form = props.form ? void 0 : void 0;
131
112
  if (!form) return;
132
- const reset = (event) => queueMicrotask(() => {
113
+ const reset = (event) => setTimeout(() => {
133
114
  if (event.defaultPrevented) return;
115
+ props.onFormReset?.();
134
116
  const resetValue = props.value ?? props.defaultValue ?? "";
135
117
  const resetLabel = resolveLabel(resetValue);
136
118
  previousSelection = {
@@ -145,7 +127,7 @@ function Choice(props) {
145
127
  form.addEventListener("reset", reset);
146
128
  onCleanup(() => form.removeEventListener("reset", reset));
147
129
  });
148
- const items = createMemo(() => props.searchable && props.filterMode !== "external" && inputValue() !== label() ? props.items.filter((item) => item.label.toLocaleLowerCase().includes(inputValue().toLocaleLowerCase())) : props.items);
130
+ const items = createMemo(() => props.searchable && props.filterMode !== "external" && inputValue() !== label() ? props.items.filter((item) => props.matchItem ? props.matchItem(item, inputValue()) : item.label.toLocaleLowerCase().includes(inputValue().toLocaleLowerCase())) : props.items);
149
131
  const collection = createMemo(() => createListCollection({
150
132
  items: items(),
151
133
  itemToString: (item) => item.label,
@@ -187,7 +169,18 @@ function Choice(props) {
187
169
  items();
188
170
  const opened = open();
189
171
  setHighlight(null);
190
- if (virtual() && opened) virtualizer.scrollToIndex(Math.max(0, items().findIndex((item) => item.value === value())), { align: "auto" });
172
+ if (virtual() && opened) virtualizer.scrollToIndex(Math.max(0, items().findIndex((item) => item.value === value())), { align: props.centerSelected ? "center" : "auto" });
173
+ });
174
+ createEffect(() => {
175
+ const content = scroll();
176
+ if (!props.centerSelected || !open() || virtual() || !content) return;
177
+ const frame = requestAnimationFrame(() => {
178
+ const selected = content.querySelector("[data-part=\"item\"][data-state=\"checked\"]");
179
+ if (!selected) return;
180
+ const list = content.getBoundingClientRect(), row = selected.getBoundingClientRect();
181
+ content.scrollTop += row.top - list.top - (content.clientHeight - row.height) / 2;
182
+ });
183
+ onCleanup(() => cancelAnimationFrame(frame));
191
184
  });
192
185
  const Parts = props.searchable ? Combobox : Select;
193
186
  const rows = createMemo(() => {
@@ -222,6 +215,9 @@ function Choice(props) {
222
215
  get readOnly() {
223
216
  return props.readOnly;
224
217
  },
218
+ get invalid() {
219
+ return props.invalid;
220
+ },
225
221
  onOpenChange: (details) => {
226
222
  if (!blocked()) setOpen(details.open);
227
223
  },
@@ -249,15 +245,21 @@ function Choice(props) {
249
245
  return inputValue();
250
246
  },
251
247
  onInputValueChange: (details) => {
248
+ const stale = consumedOnBlur === details.inputValue && details.reason === "input-change" && false;
249
+ consumedOnBlur = null;
250
+ if (stale) return;
252
251
  if (!blocked() && details.inputValue !== inputValue()) setInput(details.inputValue);
253
252
  },
254
- selectionBehavior: "preserve"
253
+ selectionBehavior: "preserve",
254
+ ...props.autoHighlight ? { inputBehavior: "autohighlight" } : {}
255
255
  } : {};
256
256
  return createComponent(Parts.Root, mergeProps$1(rootProps, inputProps, {
257
257
  get id() {
258
258
  return props.id ?? id;
259
259
  },
260
- "class": "dds-choice",
260
+ get ["class"]() {
261
+ return memo(() => !!props.rootClass)() ? `dds-choice ${props.rootClass}` : "dds-choice";
262
+ },
261
263
  get ["data-label-placement"]() {
262
264
  return props.labelPlacement ?? "outside";
263
265
  },
@@ -306,6 +308,9 @@ function Choice(props) {
306
308
  get placeholder() {
307
309
  return props.placeholder;
308
310
  },
311
+ get inputMode() {
312
+ return props.inputMode;
313
+ },
309
314
  onCompositionStart: () => {
310
315
  composing = true;
311
316
  },
@@ -318,7 +323,14 @@ function Choice(props) {
318
323
  event.stopPropagation();
319
324
  }
320
325
  },
321
- onBlur: () => {
326
+ onBlur: (event) => {
327
+ if (props.commitDraft) {
328
+ consumedOnBlur = event.currentTarget.value;
329
+ const next = blocked() ? null : props.commitDraft(consumedOnBlur);
330
+ if (next !== null && next !== value()) setValue(next);
331
+ restoreInput(label());
332
+ return;
333
+ }
322
334
  if (value()) restoreInput(label());
323
335
  }
324
336
  });
@@ -339,7 +351,7 @@ function Choice(props) {
339
351
  return props.required;
340
352
  },
341
353
  get children() {
342
- return props.searchable ? "⌄" : ssr(_tmpl$5, ssrHydrationKey(), escape(label() || props.placeholder || messages().open));
354
+ return props.searchable ? props.triggerContent ? props.triggerContent() : "⌄" : ssr(_tmpl$5, ssrHydrationKey(), escape(label() || props.placeholder || messages().open));
343
355
  }
344
356
  }),
345
357
  createComponent(Show, {
@@ -440,4 +452,4 @@ function Choice(props) {
440
452
  //#endregion
441
453
  export { Choice as t };
442
454
 
443
- //# sourceMappingURL=choice-DoXiK8nc.js.map
455
+ //# sourceMappingURL=choice-DPmk9AHn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice-DPmk9AHn.js","names":["Combobox","C","createListCollection","Select","S","Portal","createEffect","createMemo","createSignal","createUniqueId","For","onCleanup","onMount","Show","untrack","JSX","createVirtualizer","defaultRangeExtractor","Range","choiceMessages","choiceWarningsEnabled","validateOptions","ChoiceOption","ComboboxProps","ChoiceInternals","searchable","matchItem","item","query","commitDraft","text","triggerContent","Element","rootClass","invalid","autoHighlight","centerSelected","inputMode","HTMLAttributes","HTMLInputElement","onFormReset","Choice","props","id","internal","setInternal","defaultValue","value","label","items","find","selectedOption","draft","setDraft","defaultInputValue","inputValue","open","setOpen","highlight","setHighlight","visible","HTMLButtonElement","validation","scroll","setScroll","HTMLDivElement","portalMount","setPortalMount","HTMLElement","closest","ownerDocument","body","composing","consumedOnBlur","pendingRestore","from","to","resolveLabel","blocked","disabled","readOnly","messages","setInput","next","undefined","onInputValueChange","restoreInput","current","setValue","onValueChange","some","console","warn","JSON","stringify","previousSelection","associatedForm","form","getElementById","HTMLFormElement","reset","event","Event","setTimeout","defaultPrevented","resetValue","resetLabel","addEventListener","removeEventListener","filterMode","filter","toLocaleLowerCase","includes","collection","itemToString","itemToValue","isItemDisabled","virtual","virtualization","height","configured","itemHeight","Number","isFinite","Math","max","activeIndex","findIndex","virtualizer","count","length","getScrollElement","estimateSize","overscan","enabled","initialRect","width","rangeExtractor","active","range","indexes","push","sort","a","b","opened","scrollToIndex","align","content","frame","requestAnimationFrame","selected","querySelector","list","getBoundingClientRect","row","scrollTop","top","clientHeight","cancelAnimationFrame","Parts","rows","result","getVirtualItems","map","index","start","_","status","loading","error","empty","rootProps","onOpenChange","details","onHighlightChange","highlightedValue","scrollToIndexFn","positioning","placement","const","sameWidth","gutter","strategy","matches","hideWhenDetached","inputProps","reason","stale","activeElement","selectionBehavior","inputBehavior","_$createComponent","Root","_$mergeProps","class","_$memo","data-label-placement","labelPlacement","data-has-value","children","when","Label","onClick","focus","Control","Input","aria-label","aria-labelledby","aria-describedby","aria-required","required","placeholder","onCompositionStart","onCompositionEnd","onKeyDown","key","preventDefault","stopPropagation","onBlur","currentTarget","Trigger","_$ssr","_tmpl$5","_$ssrHydrationKey","_$escape","clearable","_tmpl$","_$ssrAttribute","clear","_tmpl$2","_$ssrStyleProperty","name","_tmpl$4","onRetry","_tmpl$3","retry","mount","Positioner","Content","style","overflow","_tmpl$6","_$ssrStyle","getTotalSize","position","each","Item","aria-posinset","aria-setsize","left","transform","ItemText","description","_tmpl$7"],"sources":["../../src/internal/choice.tsx"],"sourcesContent":["import { Combobox as C, createListCollection } from \"@ark-ui/solid/combobox\";\nimport { Select as S } from \"@ark-ui/solid/select\";\nimport { Portal } from \"solid-js/web\";\nimport {\n createEffect,\n createMemo,\n createSignal,\n createUniqueId,\n For,\n onCleanup,\n onMount,\n Show,\n untrack,\n type JSX,\n} from \"solid-js\";\nimport {\n createVirtualizer,\n defaultRangeExtractor,\n type Range,\n} from \"@tanstack/solid-virtual\";\nimport {\n choiceMessages,\n choiceWarningsEnabled,\n validateOptions,\n type ChoiceOption,\n type ComboboxProps,\n} from \"../choice-types\";\n\n/**\n * Options for DDS components built on Choice (TimePicker). They are not part\n * of the public Combobox/SelectPicker props; every default keeps the existing\n * Combobox and SelectPicker behavior.\n */\nexport interface ChoiceInternals {\n searchable: boolean;\n /** Replaces the default case-insensitive label substring filter. */\n matchItem?: (item: ChoiceOption, query: string) => boolean;\n /** On blur, the value the typed text stands for, \"\" to clear, or null to restore the label. */\n commitDraft?: (text: string) => string | null;\n /** Content of the searchable trigger button (default \"⌄\"). */\n triggerContent?: () => JSX.Element;\n rootClass?: string;\n invalid?: boolean;\n /** Highlight the first match while typing so Enter picks it. */\n autoHighlight?: boolean;\n /** Scroll the selected option to the middle of the list when it opens. */\n centerSelected?: boolean;\n inputMode?: JSX.HTMLAttributes<HTMLInputElement>[\"inputMode\"];\n /** Called before a native form reset restores the value. */\n onFormReset?: () => void;\n}\n\nexport function Choice(props: ComboboxProps & ChoiceInternals) {\n const id = createUniqueId();\n const [internal, setInternal] = createSignal(props.defaultValue ?? \"\");\n const value = () => props.value ?? internal();\n const label = createMemo(\n () =>\n props.items.find((item) => item.value === value())?.label ??\n (props.selectedOption?.value === value()\n ? props.selectedOption.label\n : value()),\n );\n const [draft, setDraft] = createSignal(props.defaultInputValue ?? label());\n const inputValue = () => props.inputValue ?? draft();\n const [open, setOpen] = createSignal(false),\n [highlight, setHighlight] = createSignal<string | null>(null);\n let visible: HTMLInputElement | HTMLButtonElement | undefined,\n validation: HTMLInputElement | undefined;\n const [scroll, setScroll] = createSignal<HTMLDivElement | null>(null);\n const [portalMount, setPortalMount] = createSignal<HTMLElement>();\n onMount(() => {\n // Preserve the enclosing modal's isolation boundary for nested options.\n if (visible)\n setPortalMount(\n visible.closest<HTMLElement>('[role=\"dialog\"], [role=\"alertdialog\"]') ??\n visible.ownerDocument.body,\n );\n });\n let composing = false;\n let consumedOnBlur: string | null = null;\n let pendingRestore: { from: string; to: string } | null = null;\n const resolveLabel = (id: string) =>\n props.items.find((item) => item.value === id)?.label ??\n (props.selectedOption?.value === id ? props.selectedOption.label : id);\n const blocked = () => props.disabled || props.readOnly;\n const messages = () => ({ ...choiceMessages, ...props.messages });\n const setInput = (next: string) => {\n if (pendingRestore?.from === inputValue() && pendingRestore.to === next)\n return;\n pendingRestore = null;\n if (props.inputValue === undefined) setDraft(next);\n props.onInputValueChange?.(next);\n };\n const restoreInput = (next: string) => {\n const current = inputValue();\n if (next === current) return;\n if (pendingRestore?.from === current && pendingRestore.to === next) return;\n pendingRestore = { from: current, to: next };\n if (props.inputValue === undefined) setDraft(next);\n else props.onInputValueChange?.(next);\n };\n const setValue = (next: string) => {\n if (props.value === undefined) setInternal(next);\n props.onValueChange?.(next);\n };\n createEffect(() => {\n validateOptions(props.items);\n });\n createEffect(() => {\n if (\n choiceWarningsEnabled() &&\n value() &&\n !props.items.some((item) => item.value === value()) &&\n props.selectedOption?.value !== value()\n )\n console.warn(\n `DDS choice: no label supplied for selected ID ${JSON.stringify(value())}; pass selectedOption when the selection is outside items.`,\n );\n });\n let previousSelection = { value: value(), label: label() };\n createEffect(() => {\n const current = { value: value(), label: label() };\n if (\n previousSelection.value !== current.value ||\n previousSelection.label !== current.label\n ) {\n previousSelection = current;\n untrack(() => restoreInput(current.label));\n }\n });\n createEffect(() => {\n const associatedForm = props.form;\n const form = associatedForm\n ? (validation?.ownerDocument.getElementById(\n associatedForm,\n ) as HTMLFormElement | null)\n : validation?.form;\n if (!form) return;\n // A task, not a microtask: after a reset-button click, microtasks run\n // before the browser resets the controls and would be overwritten.\n const reset = (event: Event) =>\n setTimeout(() => {\n if (event.defaultPrevented) return;\n props.onFormReset?.();\n const resetValue = props.value ?? props.defaultValue ?? \"\";\n const resetLabel = resolveLabel(resetValue);\n previousSelection = { value: resetValue, label: resetLabel };\n if (props.value === undefined) setInternal(resetValue);\n restoreInput(props.defaultInputValue ?? resetLabel);\n setOpen(false);\n if (visible instanceof HTMLInputElement) visible.value = inputValue();\n if (validation) validation.value = value();\n });\n form.addEventListener(\"reset\", reset);\n onCleanup(() => form.removeEventListener(\"reset\", reset));\n });\n const items = createMemo(() =>\n props.searchable &&\n props.filterMode !== \"external\" &&\n inputValue() !== label()\n ? props.items.filter((item) =>\n props.matchItem\n ? props.matchItem(item, inputValue())\n : item.label\n .toLocaleLowerCase()\n .includes(inputValue().toLocaleLowerCase()),\n )\n : props.items,\n );\n const collection = createMemo(() =>\n createListCollection({\n items: items(),\n itemToString: (item) => item.label,\n itemToValue: (item) => item.value,\n isItemDisabled: (item) => !!item.disabled,\n }),\n );\n const virtual = () => !!props.virtualization;\n const height = () => {\n const configured = props.virtualization\n ? props.virtualization.itemHeight\n : undefined;\n return Number.isFinite(configured) ? Math.max(40, configured!) : 40;\n };\n const activeIndex = () =>\n items().findIndex((item) => item.value === highlight());\n const virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({\n get count() {\n return items().length;\n },\n getScrollElement: scroll,\n estimateSize: height,\n get overscan() {\n return props.virtualization ? (props.virtualization.overscan ?? 5) : 5;\n },\n get enabled() {\n return virtual() && open();\n },\n initialRect: { width: 0, height: 320 },\n get rangeExtractor() {\n const active = activeIndex();\n return (range: Range) => {\n const indexes = defaultRangeExtractor(range);\n if (active >= 0 && !indexes.includes(active)) indexes.push(active);\n return indexes.sort((a, b) => a - b);\n };\n },\n });\n createEffect(() => {\n items();\n const opened = open();\n setHighlight(null);\n if (virtual() && opened)\n virtualizer.scrollToIndex(\n Math.max(\n 0,\n items().findIndex((item) => item.value === value()),\n ),\n { align: props.centerSelected ? \"center\" : \"auto\" },\n );\n });\n createEffect(() => {\n const content = scroll();\n if (!props.centerSelected || !open() || virtual() || !content) return;\n // Ark only scrolls the highlighted option to the nearest edge.\n const frame = requestAnimationFrame(() => {\n const selected = content.querySelector<HTMLElement>(\n '[data-part=\"item\"][data-state=\"checked\"]',\n );\n if (!selected) return;\n const list = content.getBoundingClientRect(),\n row = selected.getBoundingClientRect();\n content.scrollTop +=\n row.top - list.top - (content.clientHeight - row.height) / 2;\n });\n onCleanup(() => cancelAnimationFrame(frame));\n });\n const Parts = props.searchable ? C : S;\n const rows = createMemo(() => {\n const result = virtual()\n ? virtualizer\n .getVirtualItems()\n .map((row) => ({ index: row.index, start: row.start }))\n : items().map((_, index) => ({ index, start: 0 }));\n const active = activeIndex();\n if (virtual() && active >= 0 && !result.some((row) => row.index === active))\n result.push({ index: active, start: active * height() });\n return result;\n });\n const status = () =>\n props.loading\n ? messages().loading\n : props.error\n ? typeof props.error === \"string\"\n ? props.error\n : messages().error\n : items().length === 0\n ? messages().empty\n : \"\";\n const rootProps = {\n get collection() {\n return collection();\n },\n get value() {\n return value() ? [value()] : [];\n },\n get open() {\n return open() && !blocked();\n },\n get disabled() {\n return props.disabled;\n },\n get readOnly() {\n return props.readOnly;\n },\n get invalid() {\n return props.invalid;\n },\n onOpenChange: (details: { open: boolean }) => {\n if (!blocked()) setOpen(details.open);\n },\n onValueChange: (details: { value: string[] }) => {\n if (blocked() || composing) return;\n const next = details.value[0] ?? \"\";\n if (next !== value()) setValue(next);\n },\n onHighlightChange: (details: { highlightedValue: string | null }) =>\n setHighlight(details.highlightedValue),\n get scrollToIndexFn() {\n return virtual()\n ? ({ index }: { index: number }) =>\n virtualizer.scrollToIndex(index, { align: \"auto\" })\n : undefined;\n },\n get positioning() {\n return {\n placement: \"bottom-start\" as const,\n sameWidth: true,\n gutter: 4,\n strategy: portalMount()?.matches(\n '[role=\"dialog\"], [role=\"alertdialog\"]',\n )\n ? (\"fixed\" as const)\n : (\"absolute\" as const),\n hideWhenDetached: !!portalMount()?.matches(\n '[role=\"dialog\"], [role=\"alertdialog\"]',\n ),\n };\n },\n };\n const inputProps = props.searchable\n ? {\n get inputValue() {\n return inputValue();\n },\n onInputValueChange: (details: {\n inputValue: string;\n reason?: string | undefined;\n }) => {\n // Ark reports a keystroke after the blur that already committed it.\n const stale =\n consumedOnBlur === details.inputValue &&\n details.reason === \"input-change\" &&\n visible?.ownerDocument.activeElement !== visible;\n consumedOnBlur = null;\n if (stale) return;\n if (!blocked() && details.inputValue !== inputValue())\n setInput(details.inputValue);\n },\n selectionBehavior: \"preserve\" as const,\n ...(props.autoHighlight\n ? { inputBehavior: \"autohighlight\" as const }\n : {}),\n }\n : {};\n return (\n <Parts.Root\n {...rootProps}\n {...inputProps}\n id={props.id ?? id}\n class={props.rootClass ? `dds-choice ${props.rootClass}` : \"dds-choice\"}\n data-label-placement={props.labelPlacement ?? \"outside\"}\n data-has-value={value() || inputValue() ? \"\" : undefined}\n >\n <Show when={props.label}>\n <Parts.Label class=\"dds-choice-label\" onClick={() => visible?.focus()}>\n {props.label}\n </Parts.Label>\n </Show>\n <Parts.Control class=\"dds-choice-control\">\n <Show when={props.searchable}>\n <C.Input\n ref={(node) => {\n visible = node;\n }}\n class=\"dds-choice-input\"\n aria-label={props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n placeholder={props.placeholder}\n inputMode={props.inputMode}\n onCompositionStart={() => {\n composing = true;\n }}\n onCompositionEnd={() => {\n composing = false;\n }}\n onKeyDown={(event) => {\n if (composing && event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n }\n }}\n onBlur={(event) => {\n if (props.commitDraft) {\n // The DOM holds the latest keystroke; Ark's input state may still be queued.\n consumedOnBlur = event.currentTarget.value;\n const next = blocked()\n ? null\n : props.commitDraft(consumedOnBlur);\n if (next !== null && next !== value()) setValue(next);\n restoreInput(label());\n return;\n }\n if (value()) restoreInput(label());\n }}\n />\n </Show>\n <Parts.Trigger\n ref={(node) => {\n if (!props.searchable) visible = node;\n }}\n class=\"dds-choice-trigger\"\n aria-label={props.searchable ? messages().open : props[\"aria-label\"]}\n aria-labelledby={props[\"aria-labelledby\"]}\n aria-describedby={props[\"aria-describedby\"]}\n aria-required={props.required}\n >\n {props.searchable ? (\n props.triggerContent ? (\n props.triggerContent()\n ) : (\n \"⌄\"\n )\n ) : (\n <span class=\"dds-choice-value\">\n {label() || props.placeholder || messages().open}\n </span>\n )}\n </Parts.Trigger>\n <Show when={props.clearable && !blocked() && (value() || inputValue())}>\n <button\n class=\"dds-choice-clear\"\n type=\"button\"\n aria-label={messages().clear}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n setValue(\"\");\n setInput(\"\");\n setOpen(false);\n visible?.focus();\n }}\n >\n ×\n </button>\n </Show>\n </Parts.Control>\n <input\n ref={validation}\n class=\"dds-choice-validation\"\n style={{\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n padding: \"0\",\n border: \"0\",\n \"clip-path\": \"inset(50%)\",\n overflow: \"hidden\",\n \"white-space\": \"nowrap\",\n }}\n tabIndex={-1}\n aria-hidden=\"true\"\n name={props.name}\n form={props.form}\n value={value()}\n required={props.required}\n disabled={props.disabled}\n onInput={(event) => {\n event.currentTarget.value = value();\n }}\n onInvalid={(event) => {\n event.preventDefault();\n visible?.focus();\n }}\n />\n <div class=\"dds-choice-status\" role=\"status\" aria-live=\"polite\">\n {status()}\n <Show when={props.error && props.onRetry}>\n <button\n class=\"dds-choice-retry\"\n type=\"button\"\n onClick={() => props.onRetry?.()}\n >\n {messages().retry}\n </button>\n </Show>\n </div>\n <Show when={portalMount()}>\n {(mount) => (\n <Portal mount={mount()}>\n <Parts.Positioner class=\"dds-choice-positioner\">\n <Parts.Content\n ref={setScroll}\n class=\"dds-choice-content\"\n style={{\n \"max-height\": \"min(320px, var(--available-height, 320px))\",\n overflow: \"auto\",\n }}\n >\n <div\n style={\n virtual()\n ? {\n height: `${virtualizer.getTotalSize()}px`,\n position: \"relative\",\n }\n : undefined\n }\n >\n <For each={rows()}>\n {(row) => {\n const item = () => items()[row.index]!;\n return (\n <Parts.Item\n item={item()}\n class=\"dds-choice-item\"\n aria-posinset={row.index + 1}\n aria-setsize={items().length}\n style={\n virtual()\n ? {\n position: \"absolute\",\n top: \"0\",\n left: \"0\",\n width: \"100%\",\n height: `${height()}px`,\n transform: `translateY(${row.start}px)`,\n }\n : undefined\n }\n >\n <Parts.ItemText>{item().label}</Parts.ItemText>\n <Show when={item().description}>\n <span class=\"dds-choice-description\">\n {item().description}\n </span>\n </Show>\n </Parts.Item>\n );\n }}\n </For>\n </div>\n </Parts.Content>\n </Parts.Positioner>\n </Portal>\n )}\n </Show>\n </Parts.Root>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ //#region src/choice-types.ts
2
+ function validateOptions(items) {
3
+ const ids = /* @__PURE__ */ new Set();
4
+ for (const item of items) {
5
+ if (!item.value || ids.has(item.value)) throw new Error(`DDS choice: option IDs must be nonempty and unique (${JSON.stringify(item.value)})`);
6
+ ids.add(item.value);
7
+ }
8
+ }
9
+ var choiceMessages = {
10
+ open: "선택 열기",
11
+ clear: "선택 지우기",
12
+ loading: "불러오는 중",
13
+ empty: "결과 없음",
14
+ error: "불러오지 못했습니다",
15
+ retry: "다시 시도"
16
+ };
17
+ /** Read the consumer environment at runtime, rather than the library build mode. */
18
+ function choiceWarningsEnabled() {
19
+ return globalThis.process?.env?.NODE_ENV !== "production";
20
+ }
21
+ //#endregion
22
+ export { choiceWarningsEnabled as n, validateOptions as r, choiceMessages as t };
23
+
24
+ //# sourceMappingURL=choice-types-h4YVL8xH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice-types-h4YVL8xH.js","names":[],"sources":["../../src/choice-types.ts"],"sourcesContent":["export interface ChoiceOption {\n value: string;\n label: string;\n description?: string;\n disabled?: boolean;\n}\nexport interface ChoiceMessages {\n open?: string;\n clear?: string;\n loading?: string;\n empty?: string;\n error?: string;\n retry?: string;\n}\nexport type ChoiceVirtualization =\n | false\n | { itemHeight?: number; overscan?: number };\nexport interface ChoiceProps {\n items: ChoiceOption[];\n value?: string;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n selectedOption?: ChoiceOption;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n name?: string;\n form?: string;\n id?: string;\n label?: string;\n labelPlacement?: \"outside\" | \"inside\" | \"hidden\";\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n placeholder?: string;\n clearable?: boolean;\n messages?: ChoiceMessages;\n virtualization?: ChoiceVirtualization;\n}\nexport interface ComboboxProps extends ChoiceProps {\n inputValue?: string;\n defaultInputValue?: string;\n onInputValueChange?: (value: string) => void;\n filterMode?: \"local\" | \"external\";\n loading?: boolean;\n error?: string | boolean;\n onRetry?: () => void;\n}\nexport interface SelectPickerProps extends ChoiceProps {}\n\nexport function validateOptions(items: ChoiceOption[]) {\n const ids = new Set<string>();\n for (const item of items) {\n if (!item.value || ids.has(item.value))\n throw new Error(\n `DDS choice: option IDs must be nonempty and unique (${JSON.stringify(item.value)})`,\n );\n ids.add(item.value);\n }\n}\nexport const choiceMessages: Required<ChoiceMessages> = {\n open: \"선택 열기\",\n clear: \"선택 지우기\",\n loading: \"불러오는 중\",\n empty: \"결과 없음\",\n error: \"불러오지 못했습니다\",\n retry: \"다시 시도\",\n};\n\n/** Read the consumer environment at runtime, rather than the library build mode. */\nexport function choiceWarningsEnabled() {\n return (\n (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env\n ?.NODE_ENV !== \"production\"\n );\n}\n"],"mappings":";AAkDA,SAAgB,gBAAgB,OAAuB;CACrD,MAAM,sBAAM,IAAI,IAAY;CAC5B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,CAAC,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,GACnC,MAAM,IAAI,MACR,uDAAuD,KAAK,UAAU,KAAK,KAAK,EAAE,EACpF;EACF,IAAI,IAAI,KAAK,KAAK;CACpB;AACF;AACA,IAAa,iBAA2C;CACtD,MAAM;CACN,OAAO;CACP,SAAS;CACT,OAAO;CACP,OAAO;CACP,OAAO;AACT;;AAGA,SAAgB,wBAAwB;CACtC,OACG,WAA6D,SAAS,KACnE,aAAa;AAErB"}
@@ -0,0 +1,174 @@
1
+ //#region src/date-only.ts
2
+ function isCalendarDate(value) {
3
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
4
+ const year = Number(value.slice(0, 4)), month = Number(value.slice(5, 7)), day = Number(value.slice(8, 10));
5
+ if (year < 1 || month < 1 || month > 12 || day < 1) return false;
6
+ return day <= [
7
+ 31,
8
+ year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28,
9
+ 31,
10
+ 30,
11
+ 31,
12
+ 30,
13
+ 31,
14
+ 31,
15
+ 30,
16
+ 31,
17
+ 30,
18
+ 31
19
+ ][month - 1];
20
+ }
21
+ function isKorean(locale) {
22
+ return /^ko(?:-|$)/i.test(locale);
23
+ }
24
+ function displayDate(value, locale) {
25
+ return isKorean(locale) && isCalendarDate(value) ? value.replaceAll("-", "/") : value;
26
+ }
27
+ function canonicalInput(inputValue, locale) {
28
+ return isKorean(locale) && /^\d{4}\/\d{2}\/\d{2}$/.test(inputValue) ? inputValue.replaceAll("/", "-") : inputValue;
29
+ }
30
+ function validateInput(inputValue, required, min, max, locale = "en-US") {
31
+ const canonical = canonicalInput(inputValue, locale);
32
+ const incomplete = inputValue.length < 10 && (/^\d{0,4}(?:-\d{0,2}(?:-\d{0,2})?)?$/.test(inputValue) || isKorean(locale) && /^\d{0,4}(?:\/\d{0,2}(?:\/\d{0,2})?)?$/.test(inputValue));
33
+ let reason = "valid";
34
+ if (inputValue === "") reason = required ? "required" : "valid";
35
+ else if (!isCalendarDate(canonical)) reason = incomplete ? "incomplete" : "invalid";
36
+ else if (min && !isCalendarDate(min) || max && !isCalendarDate(max) || min && max && min > max) reason = "invalid";
37
+ else if (min && canonical < min) reason = "rangeUnderflow";
38
+ else if (max && canonical > max) reason = "rangeOverflow";
39
+ return {
40
+ inputValue,
41
+ value: reason === "valid" ? canonical : null,
42
+ valid: reason === "valid",
43
+ reason
44
+ };
45
+ }
46
+ function dateMessages(locale, messages = {}) {
47
+ const ko = isKorean(locale);
48
+ return {
49
+ previousMonth: ko ? "이전 달" : "Previous month",
50
+ nextMonth: ko ? "다음 달" : "Next month",
51
+ previousYear: ko ? "이전 해" : "Previous year",
52
+ nextYear: ko ? "다음 해" : "Next year",
53
+ today: ko ? "오늘" : "Today",
54
+ thisMonth: ko ? "이번 달" : "This month",
55
+ clear: ko ? "선택 날짜 지우기" : "Clear selected date",
56
+ openCalendar: ko ? "달력 열기" : "Open calendar",
57
+ selectDate: (text) => ko ? `${text} 선택` : `Choose ${text}`,
58
+ required: ko ? "날짜를 입력해 주세요." : "Enter a date.",
59
+ invalid: ko ? "YYYY/MM/DD 형식의 유효한 범위 내 날짜를 입력해 주세요." : "Enter a valid date within the allowed range (YYYY-MM-DD).",
60
+ ...messages
61
+ };
62
+ }
63
+ /** Today is the sole timestamp boundary; stored dates remain Gregorian date-only strings. */
64
+ function todayDate(timeZone) {
65
+ const parts = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
66
+ timeZone,
67
+ year: "numeric",
68
+ month: "2-digit",
69
+ day: "2-digit"
70
+ }).formatToParts(/* @__PURE__ */ new Date());
71
+ const part = (type) => parts.find((item) => item.type === type).value;
72
+ return `${part("year").padStart(4, "0")}-${part("month")}-${part("day")}`;
73
+ }
74
+ function rangeMessages(locale, messages = {}) {
75
+ const ko = isKorean(locale);
76
+ return {
77
+ ...dateMessages(locale),
78
+ clear: ko ? "선택 기간 지우기" : "Clear selected period",
79
+ startLabel: ko ? "시작일" : "Start date",
80
+ endLabel: ko ? "종료일" : "End date",
81
+ chooseRange: ko ? "기간 선택" : "Choose a period",
82
+ presets: ko ? "빠른 기간 선택" : "Quick periods",
83
+ required: ko ? "시작일과 종료일을 입력해 주세요." : "Enter a start date and an end date.",
84
+ order: ko ? "종료일은 시작일과 같거나 그 이후여야 합니다." : "The end date must be on or after the start date.",
85
+ ...messages
86
+ };
87
+ }
88
+ /** Each side follows DatePicker's rules; a typed end before the start is invalid, never swapped. */
89
+ function validateRange(startText, endText, required, min, max, locale = "en-US") {
90
+ const start = validateInput(startText, required, min, max, locale), end = validateInput(endText, required, min, max, locale);
91
+ let reason = !start.valid ? start.reason : !end.valid ? end.reason : "valid";
92
+ if (reason === "valid" && start.value && end.value && start.value > end.value) reason = "order";
93
+ return {
94
+ start,
95
+ end,
96
+ value: reason === "valid" ? {
97
+ start: start.value,
98
+ end: end.value
99
+ } : null,
100
+ valid: reason === "valid",
101
+ reason
102
+ };
103
+ }
104
+ function isCalendarMonth(value) {
105
+ if (!/^\d{4}-\d{2}$/.test(value)) return false;
106
+ const year = Number(value.slice(0, 4)), month = Number(value.slice(5, 7));
107
+ return year >= 1 && month >= 1 && month <= 12;
108
+ }
109
+ function displayMonth(value, locale) {
110
+ return isKorean(locale) && isCalendarMonth(value) ? value.replace("-", "/") : value;
111
+ }
112
+ /** Accepts YYYY-MM, YYYY/MM, YYYY.MM and YYYYMM; other text is returned unchanged. */
113
+ function canonicalMonth(inputValue) {
114
+ const match = /^(\d{4})[-/.](\d{2})$/.exec(inputValue) ?? /^(\d{4})(\d{2})$/.exec(inputValue);
115
+ return match ? `${match[1]}-${match[2]}` : inputValue;
116
+ }
117
+ function validateMonth(inputValue, required, min, max) {
118
+ const canonical = canonicalMonth(inputValue);
119
+ const incomplete = /^\d{0,5}$/.test(inputValue) || /^\d{4}[-/.]\d?$/.test(inputValue);
120
+ let reason = "valid";
121
+ if (inputValue === "") reason = required ? "required" : "valid";
122
+ else if (!isCalendarMonth(canonical)) reason = incomplete ? "incomplete" : "invalid";
123
+ else if (min && !isCalendarMonth(min) || max && !isCalendarMonth(max) || min && max && min > max) reason = "invalid";
124
+ else if (min && canonical < min) reason = "rangeUnderflow";
125
+ else if (max && canonical > max) reason = "rangeOverflow";
126
+ return {
127
+ inputValue,
128
+ value: reason === "valid" ? canonical : null,
129
+ valid: reason === "valid",
130
+ reason
131
+ };
132
+ }
133
+ /** Month bounds widened to whole days, so any day inside an allowed month stays selectable. */
134
+ function monthBounds(min, max) {
135
+ const last = (month) => {
136
+ const year = Number(month.slice(0, 4)), index = Number(month.slice(5, 7));
137
+ return [
138
+ 31,
139
+ year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28,
140
+ 31,
141
+ 30,
142
+ 31,
143
+ 30,
144
+ 31,
145
+ 31,
146
+ 30,
147
+ 31,
148
+ 30,
149
+ 31
150
+ ][index - 1];
151
+ };
152
+ return {
153
+ min: min && isCalendarMonth(min) ? `${min}-01` : void 0,
154
+ max: max && isCalendarMonth(max) ? `${max}-${last(max)}` : void 0
155
+ };
156
+ }
157
+ function monthMessages(locale, messages = {}) {
158
+ const ko = isKorean(locale);
159
+ return {
160
+ previousYear: ko ? "이전 해" : "Previous year",
161
+ nextYear: ko ? "다음 해" : "Next year",
162
+ thisMonth: ko ? "이번 달" : "This month",
163
+ clear: ko ? "선택 월 지우기" : "Clear selected month",
164
+ openCalendar: ko ? "달력 열기" : "Open calendar",
165
+ chooseMonth: ko ? "월 선택" : "Choose a month",
166
+ required: ko ? "월을 입력해 주세요." : "Enter a month.",
167
+ invalid: ko ? "YYYY/MM 형식의 유효한 범위 내 월을 입력해 주세요." : "Enter a valid month within the allowed range (YYYY-MM).",
168
+ ...messages
169
+ };
170
+ }
171
+ //#endregion
172
+ export { displayMonth as a, isKorean as c, rangeMessages as d, todayDate as f, validateRange as h, displayDate as i, monthBounds as l, validateMonth as m, canonicalMonth as n, isCalendarDate as o, validateInput as p, dateMessages as r, isCalendarMonth as s, canonicalInput as t, monthMessages as u };
173
+
174
+ //# sourceMappingURL=date-only-0Ldsjp43.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-only-0Ldsjp43.js","names":[],"sources":["../../src/date-only.ts"],"sourcesContent":["export interface DatePickerValidity {\n /** Exact displayed draft; never persist this display text as an API date. */\n inputValue: string;\n /** Valid ISO date, optional empty string, or null when invalid/incomplete. */\n value: string | null;\n valid: boolean;\n reason:\n | \"valid\"\n | \"required\"\n | \"incomplete\"\n | \"invalid\"\n | \"rangeUnderflow\"\n | \"rangeOverflow\";\n}\n// Date-only Gregorian validation: never let a permissive parser repair user text.\nexport function isCalendarDate(value: string) {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return false;\n const year = Number(value.slice(0, 4)),\n month = Number(value.slice(5, 7)),\n day = Number(value.slice(8, 10));\n if (year < 1 || month < 1 || month > 12 || day < 1) return false;\n const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return (\n day <=\n [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1]!\n );\n}\nexport function isKorean(locale: string) {\n return /^ko(?:-|$)/i.test(locale);\n}\nexport function displayDate(value: string, locale: string) {\n return isKorean(locale) && isCalendarDate(value)\n ? value.replaceAll(\"-\", \"/\")\n : value;\n}\nexport function canonicalInput(inputValue: string, locale: string) {\n return isKorean(locale) && /^\\d{4}\\/\\d{2}\\/\\d{2}$/.test(inputValue)\n ? inputValue.replaceAll(\"/\", \"-\")\n : inputValue;\n}\nexport function validateInput(\n inputValue: string,\n required: boolean,\n min?: string,\n max?: string,\n locale = \"en-US\",\n): DatePickerValidity {\n const canonical = canonicalInput(inputValue, locale);\n const incomplete =\n inputValue.length < 10 &&\n (/^\\d{0,4}(?:-\\d{0,2}(?:-\\d{0,2})?)?$/.test(inputValue) ||\n (isKorean(locale) &&\n /^\\d{0,4}(?:\\/\\d{0,2}(?:\\/\\d{0,2})?)?$/.test(inputValue)));\n let reason: DatePickerValidity[\"reason\"] = \"valid\";\n if (inputValue === \"\") reason = required ? \"required\" : \"valid\";\n else if (!isCalendarDate(canonical))\n reason = incomplete ? \"incomplete\" : \"invalid\";\n else if (\n (min && !isCalendarDate(min)) ||\n (max && !isCalendarDate(max)) ||\n (min && max && min > max)\n )\n reason = \"invalid\";\n else if (min && canonical < min) reason = \"rangeUnderflow\";\n else if (max && canonical > max) reason = \"rangeOverflow\";\n return {\n inputValue,\n value: reason === \"valid\" ? canonical : null,\n valid: reason === \"valid\",\n reason,\n };\n}\n\nexport interface CalendarMessages {\n previousMonth?: string;\n nextMonth?: string;\n /** Month-grid header controls (MonthPicker). */\n previousYear?: string;\n nextYear?: string;\n today?: string;\n /** Footer action of the month grid (MonthPicker). */\n thisMonth?: string;\n clear?: string;\n openCalendar?: string;\n selectDate?: (dateText: string) => string;\n required?: string;\n invalid?: string;\n}\nexport function dateMessages(locale: string, messages: CalendarMessages = {}) {\n const ko = isKorean(locale);\n return {\n previousMonth: ko ? \"이전 달\" : \"Previous month\",\n nextMonth: ko ? \"다음 달\" : \"Next month\",\n previousYear: ko ? \"이전 해\" : \"Previous year\",\n nextYear: ko ? \"다음 해\" : \"Next year\",\n today: ko ? \"오늘\" : \"Today\",\n thisMonth: ko ? \"이번 달\" : \"This month\",\n clear: ko ? \"선택 날짜 지우기\" : \"Clear selected date\",\n openCalendar: ko ? \"달력 열기\" : \"Open calendar\",\n selectDate: (text: string) => (ko ? `${text} 선택` : `Choose ${text}`),\n required: ko ? \"날짜를 입력해 주세요.\" : \"Enter a date.\",\n invalid: ko\n ? \"YYYY/MM/DD 형식의 유효한 범위 내 날짜를 입력해 주세요.\"\n : \"Enter a valid date within the allowed range (YYYY-MM-DD).\",\n ...messages,\n };\n}\n\n/** Today is the sole timestamp boundary; stored dates remain Gregorian date-only strings. */\nexport function todayDate(timeZone: string) {\n const parts = new Intl.DateTimeFormat(\"en-US-u-ca-gregory-nu-latn\", {\n timeZone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n }).formatToParts(new Date());\n const part = (type: string) =>\n parts.find((item) => item.type === type)!.value;\n return `${part(\"year\").padStart(4, \"0\")}-${part(\"month\")}-${part(\"day\")}`;\n}\n\n/* ── Date ranges ─────────────────────────────────────────────────────────── */\n\n/** A period of two date-only values; either side may be \"\" (not chosen). */\nexport interface DateRange {\n start: string;\n end: string;\n}\n\nexport interface DateRangeMessages extends CalendarMessages {\n /** Accessible name of the first input. */\n startLabel?: string;\n /** Accessible name of the second input. */\n endLabel?: string;\n /** Accessible name of the calendar popup. */\n chooseRange?: string;\n /** Shown when both dates are typed but the end is before the start. */\n order?: string;\n /** Accessible name of the preset button group. */\n presets?: string;\n}\n\nexport function rangeMessages(locale: string, messages: DateRangeMessages = {}) {\n const ko = isKorean(locale);\n return {\n ...dateMessages(locale),\n clear: ko ? \"선택 기간 지우기\" : \"Clear selected period\",\n startLabel: ko ? \"시작일\" : \"Start date\",\n endLabel: ko ? \"종료일\" : \"End date\",\n chooseRange: ko ? \"기간 선택\" : \"Choose a period\",\n presets: ko ? \"빠른 기간 선택\" : \"Quick periods\",\n required: ko\n ? \"시작일과 종료일을 입력해 주세요.\"\n : \"Enter a start date and an end date.\",\n order: ko\n ? \"종료일은 시작일과 같거나 그 이후여야 합니다.\"\n : \"The end date must be on or after the start date.\",\n ...messages,\n };\n}\n\nexport interface DateRangeValidity {\n start: DatePickerValidity;\n end: DatePickerValidity;\n /** Canonical range, or null while either side is invalid/incomplete or out of order. */\n value: DateRange | null;\n valid: boolean;\n reason: DatePickerValidity[\"reason\"] | \"order\";\n}\n\n/** Each side follows DatePicker's rules; a typed end before the start is invalid, never swapped. */\nexport function validateRange(\n startText: string,\n endText: string,\n required: boolean,\n min?: string,\n max?: string,\n locale = \"en-US\",\n): DateRangeValidity {\n const start = validateInput(startText, required, min, max, locale),\n end = validateInput(endText, required, min, max, locale);\n let reason: DateRangeValidity[\"reason\"] = !start.valid\n ? start.reason\n : !end.valid\n ? end.reason\n : \"valid\";\n if (reason === \"valid\" && start.value && end.value && start.value > end.value)\n reason = \"order\";\n return {\n start,\n end,\n value:\n reason === \"valid\" ? { start: start.value!, end: end.value! } : null,\n valid: reason === \"valid\",\n reason,\n };\n}\n\n/* ── Months ──────────────────────────────────────────────────────────────── */\n\nexport function isCalendarMonth(value: string) {\n if (!/^\\d{4}-\\d{2}$/.test(value)) return false;\n const year = Number(value.slice(0, 4)),\n month = Number(value.slice(5, 7));\n return year >= 1 && month >= 1 && month <= 12;\n}\n\nexport function displayMonth(value: string, locale: string) {\n return isKorean(locale) && isCalendarMonth(value)\n ? value.replace(\"-\", \"/\")\n : value;\n}\n\n/** Accepts YYYY-MM, YYYY/MM, YYYY.MM and YYYYMM; other text is returned unchanged. */\nexport function canonicalMonth(inputValue: string) {\n const match =\n /^(\\d{4})[-/.](\\d{2})$/.exec(inputValue) ?? /^(\\d{4})(\\d{2})$/.exec(inputValue);\n return match ? `${match[1]}-${match[2]}` : inputValue;\n}\n\nexport interface MonthPickerValidity {\n /** Exact displayed draft; never persist this display text as an API month. */\n inputValue: string;\n /** Valid YYYY-MM, optional empty string, or null when invalid/incomplete. */\n value: string | null;\n valid: boolean;\n reason: DatePickerValidity[\"reason\"];\n}\n\nexport function validateMonth(\n inputValue: string,\n required: boolean,\n min?: string,\n max?: string,\n): MonthPickerValidity {\n const canonical = canonicalMonth(inputValue);\n const incomplete = /^\\d{0,5}$/.test(inputValue) || /^\\d{4}[-/.]\\d?$/.test(inputValue);\n let reason: MonthPickerValidity[\"reason\"] = \"valid\";\n if (inputValue === \"\") reason = required ? \"required\" : \"valid\";\n else if (!isCalendarMonth(canonical))\n reason = incomplete ? \"incomplete\" : \"invalid\";\n else if (\n (min && !isCalendarMonth(min)) ||\n (max && !isCalendarMonth(max)) ||\n (min && max && min > max)\n )\n reason = \"invalid\";\n else if (min && canonical < min) reason = \"rangeUnderflow\";\n else if (max && canonical > max) reason = \"rangeOverflow\";\n return {\n inputValue,\n value: reason === \"valid\" ? canonical : null,\n valid: reason === \"valid\",\n reason,\n };\n}\n\n/** Month bounds widened to whole days, so any day inside an allowed month stays selectable. */\nexport function monthBounds(min?: string, max?: string) {\n const last = (month: string) => {\n const year = Number(month.slice(0, 4)),\n index = Number(month.slice(5, 7)),\n leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n return [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][index - 1]!;\n };\n return {\n min: min && isCalendarMonth(min) ? `${min}-01` : undefined,\n max: max && isCalendarMonth(max) ? `${max}-${last(max)}` : undefined,\n };\n}\n\nexport interface MonthPickerMessages {\n previousYear?: string;\n nextYear?: string;\n thisMonth?: string;\n clear?: string;\n openCalendar?: string;\n /** Accessible name of the month popup. */\n chooseMonth?: string;\n required?: string;\n invalid?: string;\n}\n\nexport function monthMessages(locale: string, messages: MonthPickerMessages = {}) {\n const ko = isKorean(locale);\n return {\n previousYear: ko ? \"이전 해\" : \"Previous year\",\n nextYear: ko ? \"다음 해\" : \"Next year\",\n thisMonth: ko ? \"이번 달\" : \"This month\",\n clear: ko ? \"선택 월 지우기\" : \"Clear selected month\",\n openCalendar: ko ? \"달력 열기\" : \"Open calendar\",\n chooseMonth: ko ? \"월 선택\" : \"Choose a month\",\n required: ko ? \"월을 입력해 주세요.\" : \"Enter a month.\",\n invalid: ko\n ? \"YYYY/MM 형식의 유효한 범위 내 월을 입력해 주세요.\"\n : \"Enter a valid month within the allowed range (YYYY-MM).\",\n ...messages,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { createSignal, onCleanup, onMount } from "solid-js";
2
+ //#region src/direction.ts
3
+ /** SSR callers may supply direction; clients also inherit their containing DOM. */
4
+ function useDirection(element, explicit) {
5
+ const [ambient, setAmbient] = createSignal("ltr");
6
+ onMount(() => {
7
+ const parent = element()?.parentElement;
8
+ if (!parent) return;
9
+ const update = () => setAmbient(getComputedStyle(parent).direction === "rtl" ? "rtl" : "ltr");
10
+ update();
11
+ const observer = new MutationObserver(update);
12
+ observer.observe(parent.ownerDocument.documentElement, {
13
+ attributes: true,
14
+ subtree: true,
15
+ attributeFilter: ["dir"]
16
+ });
17
+ onCleanup(() => observer.disconnect());
18
+ });
19
+ return () => explicit() ?? ambient();
20
+ }
21
+ //#endregion
22
+ export { useDirection as t };
23
+
24
+ //# sourceMappingURL=direction-BpTqmXs-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direction-BpTqmXs-.js","names":[],"sources":["../../src/direction.ts"],"sourcesContent":["import { createSignal, onCleanup, onMount, type Accessor } from \"solid-js\";\n\nexport type Direction = \"ltr\" | \"rtl\";\n\n/** SSR callers may supply direction; clients also inherit their containing DOM. */\nexport function useDirection(element: () => HTMLElement | undefined, explicit: Accessor<Direction | undefined>) {\n const [ambient, setAmbient] = createSignal<Direction>(\"ltr\");\n onMount(() => {\n const parent = element()?.parentElement;\n if (!parent) return;\n const update = () => setAmbient(getComputedStyle(parent).direction === \"rtl\" ? \"rtl\" : \"ltr\");\n update();\n const observer = new MutationObserver(update);\n observer.observe(parent.ownerDocument.documentElement, { attributes: true, subtree: true, attributeFilter: [\"dir\"] });\n onCleanup(() => observer.disconnect());\n });\n return () => explicit() ?? ambient();\n}\n"],"mappings":";;;AAKA,SAAgB,aAAa,SAAwC,UAA2C;CAC9G,MAAM,CAAC,SAAS,cAAc,aAAwB,KAAK;CAC3D,cAAc;EACZ,MAAM,SAAS,QAAQ,CAAC,EAAE;EAC1B,IAAI,CAAC,QAAQ;EACb,MAAM,eAAe,WAAW,iBAAiB,MAAM,CAAC,CAAC,cAAc,QAAQ,QAAQ,KAAK;EAC5F,OAAO;EACP,MAAM,WAAW,IAAI,iBAAiB,MAAM;EAC5C,SAAS,QAAQ,OAAO,cAAc,iBAAiB;GAAE,YAAY;GAAM,SAAS;GAAM,iBAAiB,CAAC,KAAK;EAAE,CAAC;EACpH,gBAAgB,SAAS,WAAW,CAAC;CACvC,CAAC;CACD,aAAa,SAAS,KAAK,QAAQ;AACrC"}