@devslab/dds-solid 0.23.0 → 0.25.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.
- package/README.ko.md +15 -3
- package/README.md +15 -3
- package/dist/assets/{calendar-view-1RO2mtf1.js → calendar-view-BBQGmkJ7.js} +181 -145
- package/dist/assets/calendar-view-BBQGmkJ7.js.map +1 -0
- package/dist/assets/{choice-DoXiK8nc.js → choice-DPmk9AHn.js} +41 -29
- package/dist/assets/choice-DPmk9AHn.js.map +1 -0
- package/dist/assets/choice-types-h4YVL8xH.js +24 -0
- package/dist/assets/choice-types-h4YVL8xH.js.map +1 -0
- package/dist/assets/date-only-0Ldsjp43.js +174 -0
- package/dist/assets/date-only-0Ldsjp43.js.map +1 -0
- package/dist/assets/direction-BpTqmXs-.js +24 -0
- package/dist/assets/direction-BpTqmXs-.js.map +1 -0
- package/dist/calendar-view-CZLsC57_.js +481 -0
- package/dist/calendar-view-CZLsC57_.js.map +1 -0
- package/dist/calendar-view.d.ts +10 -0
- package/dist/calendar-view.d.ts.map +1 -1
- package/dist/calendar.js +7 -6
- package/dist/calendar.js.map +1 -1
- package/dist/calendar.server.js +2 -1
- package/dist/calendar.server.js.map +1 -1
- package/dist/choice-CTNeFOVo.js +403 -0
- package/dist/choice-CTNeFOVo.js.map +1 -0
- package/dist/choice-types-kSaEnZPr.js +23 -0
- package/dist/choice-types-kSaEnZPr.js.map +1 -0
- package/dist/combobox.js +1 -1
- package/dist/combobox.server.js +1 -1
- package/dist/date-only-Bu4UmsTP.js +151 -0
- package/dist/date-only-Bu4UmsTP.js.map +1 -0
- package/dist/date-only.d.ts +92 -0
- package/dist/date-only.d.ts.map +1 -1
- package/dist/date-picker.js +51 -50
- package/dist/date-picker.js.map +1 -1
- package/dist/date-picker.server.js +2 -1
- package/dist/date-picker.server.js.map +1 -1
- package/dist/date-range-picker.d.ts +41 -0
- package/dist/date-range-picker.d.ts.map +1 -0
- package/dist/date-range-picker.js +368 -0
- package/dist/date-range-picker.js.map +1 -0
- package/dist/date-range-picker.server.js +347 -0
- package/dist/date-range-picker.server.js.map +1 -0
- package/dist/direction-CS85IDNU.js +21 -0
- package/dist/direction-CS85IDNU.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -179
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +1 -1
- package/dist/input.js.map +1 -1
- package/dist/input.server.js +1 -1
- package/dist/input.server.js.map +1 -1
- package/dist/internal/choice.d.ts +25 -3
- package/dist/internal/choice.d.ts.map +1 -1
- package/dist/month-picker.d.ts +33 -0
- package/dist/month-picker.d.ts.map +1 -0
- package/dist/month-picker.js +287 -0
- package/dist/month-picker.js.map +1 -0
- package/dist/month-picker.server.js +282 -0
- package/dist/month-picker.server.js.map +1 -0
- package/dist/number-input.d.ts +53 -0
- package/dist/number-input.d.ts.map +1 -0
- package/dist/number-input.js +267 -0
- package/dist/number-input.js.map +1 -0
- package/dist/number-input.server.js +237 -0
- package/dist/number-input.server.js.map +1 -0
- package/dist/segmented-control.d.ts +40 -0
- package/dist/segmented-control.d.ts.map +1 -0
- package/dist/segmented-control.js +133 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/segmented-control.server.js +138 -0
- package/dist/segmented-control.server.js.map +1 -0
- package/dist/select-picker.js +1 -1
- package/dist/select-picker.server.js +1 -1
- package/dist/server.js +8 -22
- package/dist/server.js.map +1 -1
- package/dist/time-only.d.ts +32 -0
- package/dist/time-only.d.ts.map +1 -0
- package/dist/time-picker-BlMWCQwk.js +113 -0
- package/dist/time-picker-BlMWCQwk.js.map +1 -0
- package/dist/time-picker.d.ts +34 -0
- package/dist/time-picker.d.ts.map +1 -0
- package/dist/time-picker.js +2 -0
- package/dist/time-picker.server.js +152 -0
- package/dist/time-picker.server.js.map +1 -0
- package/package.json +44 -4
- package/styles.css +31 -1
- package/dist/assets/calendar-view-1RO2mtf1.js.map +0 -1
- package/dist/assets/choice-DoXiK8nc.js.map +0 -1
- package/dist/calendar-view-CTBTPB4T.js +0 -444
- package/dist/calendar-view-CTBTPB4T.js.map +0 -1
- package/dist/choice-BPMiJlPJ.js +0 -395
- 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) =>
|
|
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"
|
|
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-
|
|
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"}
|