@devslab/dds-react 0.21.2 → 0.22.1
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 +6 -1
- package/README.md +6 -1
- package/dist/calendar-view-I_sNlioP.js +145 -0
- package/dist/calendar-view-I_sNlioP.js.map +1 -0
- package/dist/calendar-view.d.ts +16 -0
- package/dist/calendar-view.d.ts.map +1 -0
- package/dist/calendar.d.ts +19 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +51 -0
- package/dist/calendar.js.map +1 -0
- package/dist/choice-B3vNMfKK.js +300 -0
- package/dist/choice-B3vNMfKK.js.map +1 -0
- package/dist/choice-types.d.ts +56 -0
- package/dist/choice-types.d.ts.map +1 -0
- package/dist/combobox.d.ts +4 -0
- package/dist/combobox.d.ts.map +1 -0
- package/dist/combobox.js +13 -0
- package/dist/combobox.js.map +1 -0
- package/dist/controls-BajigKUv.js +139 -0
- package/dist/controls-BajigKUv.js.map +1 -0
- package/dist/date-only.d.ts +36 -0
- package/dist/date-only.d.ts.map +1 -0
- package/dist/date-picker.d.ts +8 -9
- package/dist/date-picker.d.ts.map +1 -1
- package/dist/date-picker.js +198 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/dropdown-menu.d.ts +31 -0
- package/dist/dropdown-menu.d.ts.map +1 -0
- package/dist/dropdown-menu.js +73 -0
- package/dist/dropdown-menu.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -578
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +22 -0
- package/dist/input.d.ts.map +1 -0
- package/dist/input.js +92 -0
- package/dist/input.js.map +1 -0
- package/dist/internal/choice.d.ts +5 -0
- package/dist/internal/choice.d.ts.map +1 -0
- package/dist/popover.d.ts +21 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +49 -0
- package/dist/popover.js.map +1 -0
- package/dist/select-picker.d.ts +4 -0
- package/dist/select-picker.d.ts.map +1 -0
- package/dist/select-picker.js +13 -0
- package/dist/select-picker.js.map +1 -0
- package/package.json +46 -10
- package/styles.css +10 -1
package/README.ko.md
CHANGED
|
@@ -59,4 +59,9 @@ Unknown closed-domain status values throw to expose incomplete catalogs. Domains
|
|
|
59
59
|
|
|
60
60
|
validity callback은 최초 mount, 의미 있는 입력·제약·외부 값 변경을 보고합니다. invalid/partial 입력은 `onChange`를 호출하지 않으므로 dirty/이탈 방지와 발행 확인 취소도 validity callback에 연결해야 합니다. callback 함수 identity만 바뀌면 같은 결과를 재보고하지 않아 inline setState 루프를 막습니다. 새 편집기는 문서 ID·명시적 reset revision을 key로 새로 mount하고 useCallback으로 안정적인 함수를 사용하세요. 같은 날짜여도 새 keyed 편집기는 초기 결과를 받습니다. 유효할 때 canonical value, invalid일 때 raw inputValue로 pristine 상태를 비교하면 표시 언어만 바뀔 때의 오탐과 소비자 포맷 코드를 피할 수 있습니다. 영문 예제의 keyed editor·baseline·previous 패턴을 참고하세요.
|
|
61
61
|
|
|
62
|
-
아직 반영되지 않은 로컬 값과 일치하는 부모 값은 해당 발생 건의 응답으로 보고 최신 draft를 유지합니다. B/C/B 반복을 각각 보존하고 blur/Enter 중복 commit을 막습니다. 미반영 목록에 없는 다른 외부 값은 reset으로 처리합니다. 같은 문자열만으로는 미반영 값과 같은 의도적 reset을 응답과 구별할 수 없으므로 명시적 reset은 keyed editor remount를 사용하세요. 로컬 controlled state는 즉시 갱신하고 서버 저장을 분리하세요.
|
|
62
|
+
아직 반영되지 않은 로컬 값과 일치하는 부모 값은 해당 발생 건의 응답으로 보고 최신 draft를 유지합니다. B/C/B 반복을 각각 보존하고 blur/Enter 중복 commit을 막습니다. 미반영 목록에 없는 다른 외부 값은 reset으로 처리합니다. 같은 문자열만으로는 미반영 값과 같은 의도적 reset을 응답과 구별할 수 없으므로 명시적 reset은 keyed editor remount를 사용하세요. 로컬 controlled state는 즉시 갱신하고 서버 저장을 분리하세요.
|
|
63
|
+
## 입력·선택·메뉴·공유 달력
|
|
64
|
+
|
|
65
|
+
Input/InputGroup은 검색 전용이 아닌 일반 입력 기반이며 라벨 배치·내용 지우기를 지원합니다. Combobox/SelectPicker는 가상화를, DropdownMenu/Popover는 접근 가능한 팝업을, Calendar/DatePicker는 공유 달력을 제공합니다.
|
|
66
|
+
|
|
67
|
+
상세 import: `@devslab/dds-react/input`, `/combobox`, `/select-picker`, `/dropdown-menu`, `/popover`, `/calendar`, `/date-picker`. 기존 루트 import와 `styles.css`는 유지합니다. [공통 사용 가이드](https://github.com/devslab-kr/dds/blob/main/docs/components-input-choice-calendar.ko.md)를 참고하세요.
|
package/README.md
CHANGED
|
@@ -93,4 +93,9 @@ const onDateValidity = useCallback((state: DatePickerValidity) => {
|
|
|
93
93
|
// Every button/API/shortcut Save checks valid and persists state.value only.
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
Delayed controlled echoes matching an outstanding local emission acknowledge that occurrence without replacing a newer draft. Repeated B/C/B is retained as three occurrences; duplicate blur/Enter does not emit again. A changed value not among pending emissions is an external reset and clears pending history. The string-only API cannot distinguish an intentional reset to a still-outstanding identical value from its acknowledgement; use a keyed editor remount for an explicit reset. Keep local controlled state synchronous and persist to the server separately. Unacknowledged emissions are retained until acknowledgement, external reset or unmount.
|
|
96
|
+
Delayed controlled echoes matching an outstanding local emission acknowledge that occurrence without replacing a newer draft. Repeated B/C/B is retained as three occurrences; duplicate blur/Enter does not emit again. A changed value not among pending emissions is an external reset and clears pending history. The string-only API cannot distinguish an intentional reset to a still-outstanding identical value from its acknowledgement; use a keyed editor remount for an explicit reset. Keep local controlled state synchronous and persist to the server separately. Unacknowledged emissions are retained until acknowledgement, external reset or unmount.
|
|
97
|
+
## Inputs, choices, overlays and shared calendars
|
|
98
|
+
|
|
99
|
+
Input/InputGroup are general-purpose native inputs, not search-only, with label placement and clear actions. Combobox/SelectPicker support fixed-row virtualization; DropdownMenu/Popover provide accessible overlays; Calendar/DatePicker share a calendar view.
|
|
100
|
+
|
|
101
|
+
Use explicit subpaths `@devslab/dds-react/input`, `/combobox`, `/select-picker`, `/dropdown-menu`, `/popover`, `/calendar`, `/date-picker`, or the existing root exports. Keep importing `styles.css` once. See the [common usage guide](https://github.com/devslab-kr/dds/blob/main/docs/components-input-choice-calendar.md).
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { t as e } from "./controls-BajigKUv.js";
|
|
2
|
+
import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
3
|
+
import { DatePicker as i } from "@ark-ui/react/date-picker";
|
|
4
|
+
//#region src/date-only.ts
|
|
5
|
+
function a(e) {
|
|
6
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(e)) return !1;
|
|
7
|
+
let t = Number(e.slice(0, 4)), n = Number(e.slice(5, 7)), r = Number(e.slice(8, 10));
|
|
8
|
+
return t < 1 || n < 1 || n > 12 || r < 1 ? !1 : r <= [
|
|
9
|
+
31,
|
|
10
|
+
t % 4 == 0 && (t % 100 != 0 || t % 400 == 0) ? 29 : 28,
|
|
11
|
+
31,
|
|
12
|
+
30,
|
|
13
|
+
31,
|
|
14
|
+
30,
|
|
15
|
+
31,
|
|
16
|
+
31,
|
|
17
|
+
30,
|
|
18
|
+
31,
|
|
19
|
+
30,
|
|
20
|
+
31
|
|
21
|
+
][n - 1];
|
|
22
|
+
}
|
|
23
|
+
function o(e) {
|
|
24
|
+
return /^ko(?:-|$)/i.test(e);
|
|
25
|
+
}
|
|
26
|
+
function s(e, t) {
|
|
27
|
+
return o(t) && a(e) ? e.replaceAll("-", "/") : e;
|
|
28
|
+
}
|
|
29
|
+
function c(e, t) {
|
|
30
|
+
return o(t) && /^\d{4}\/\d{2}\/\d{2}$/.test(e) ? e.replaceAll("/", "-") : e;
|
|
31
|
+
}
|
|
32
|
+
function l(e, t, n, r, i = "en-US") {
|
|
33
|
+
let s = c(e, i), l = e.length < 10 && (/^\d{0,4}(?:-\d{0,2}(?:-\d{0,2})?)?$/.test(e) || o(i) && /^\d{0,4}(?:\/\d{0,2}(?:\/\d{0,2})?)?$/.test(e)), u = "valid";
|
|
34
|
+
return e === "" ? u = t ? "required" : "valid" : a(s) ? n && !a(n) || r && !a(r) || n && r && n > r ? u = "invalid" : n && s < n ? u = "rangeUnderflow" : r && s > r && (u = "rangeOverflow") : u = l ? "incomplete" : "invalid", {
|
|
35
|
+
inputValue: e,
|
|
36
|
+
value: u === "valid" ? s : null,
|
|
37
|
+
valid: u === "valid",
|
|
38
|
+
reason: u
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function u(e, t = {}) {
|
|
42
|
+
let n = o(e);
|
|
43
|
+
return {
|
|
44
|
+
previousMonth: n ? "이전 달" : "Previous month",
|
|
45
|
+
nextMonth: n ? "다음 달" : "Next month",
|
|
46
|
+
today: n ? "오늘" : "Today",
|
|
47
|
+
clear: n ? "선택 날짜 지우기" : "Clear selected date",
|
|
48
|
+
openCalendar: n ? "달력 열기" : "Open calendar",
|
|
49
|
+
selectDate: (e) => n ? `${e} 선택` : `Choose ${e}`,
|
|
50
|
+
required: n ? "날짜를 입력해 주세요." : "Enter a date.",
|
|
51
|
+
invalid: n ? "YYYY/MM/DD 형식의 유효한 범위 내 날짜를 입력해 주세요." : "Enter a valid date within the allowed range (YYYY-MM-DD).",
|
|
52
|
+
...t
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function d(e) {
|
|
56
|
+
let t = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
|
|
57
|
+
timeZone: e,
|
|
58
|
+
year: "numeric",
|
|
59
|
+
month: "2-digit",
|
|
60
|
+
day: "2-digit"
|
|
61
|
+
}).formatToParts(/* @__PURE__ */ new Date()), n = (e) => t.find((t) => t.type === e).value;
|
|
62
|
+
return `${n("year").padStart(4, "0")}-${n("month")}-${n("day")}`;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/calendar-view.tsx
|
|
66
|
+
function f({ next: e = !1 }) {
|
|
67
|
+
return /* @__PURE__ */ n("svg", {
|
|
68
|
+
width: "18",
|
|
69
|
+
height: "18",
|
|
70
|
+
viewBox: "0 0 24 24",
|
|
71
|
+
fill: "none",
|
|
72
|
+
stroke: "currentColor",
|
|
73
|
+
strokeWidth: "1.5",
|
|
74
|
+
"aria-hidden": "true",
|
|
75
|
+
children: /* @__PURE__ */ n("path", { d: e ? "m9 5 7 7-7 7" : "m15 5-7 7 7 7" })
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function p({ locale: a = "ko-KR", timeZone: o = "Asia/Seoul", min: s, max: c, messages: p, disabled: m, readOnly: h, showToday: g = !0, showClear: _ = !0, onClear: v }) {
|
|
79
|
+
let y = u(a, p), b = m || h;
|
|
80
|
+
return /* @__PURE__ */ n(i.View, {
|
|
81
|
+
view: "day",
|
|
82
|
+
children: /* @__PURE__ */ n(i.Context, { children: (u) => /* @__PURE__ */ r(t, { children: [
|
|
83
|
+
/* @__PURE__ */ r(i.ViewControl, {
|
|
84
|
+
className: "dds-date-picker-header",
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ n(i.PrevTrigger, {
|
|
87
|
+
asChild: !0,
|
|
88
|
+
children: /* @__PURE__ */ n(e, {
|
|
89
|
+
type: "button",
|
|
90
|
+
tone: "secondary",
|
|
91
|
+
"aria-label": y.previousMonth,
|
|
92
|
+
children: /* @__PURE__ */ n(f, {})
|
|
93
|
+
})
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ n(i.RangeText, {}),
|
|
96
|
+
/* @__PURE__ */ n(i.NextTrigger, {
|
|
97
|
+
asChild: !0,
|
|
98
|
+
children: /* @__PURE__ */ n(e, {
|
|
99
|
+
type: "button",
|
|
100
|
+
tone: "secondary",
|
|
101
|
+
"aria-label": y.nextMonth,
|
|
102
|
+
children: /* @__PURE__ */ n(f, { next: !0 })
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ r(i.Table, {
|
|
108
|
+
className: "dds-date-picker-table",
|
|
109
|
+
children: [/* @__PURE__ */ n(i.TableHead, { children: /* @__PURE__ */ n(i.TableRow, { children: u.weekDays.map((e, t) => /* @__PURE__ */ n(i.TableHeader, { children: e.short }, t)) }) }), /* @__PURE__ */ n(i.TableBody, { children: u.weeks.map((e, t) => /* @__PURE__ */ n(i.TableRow, { children: e.map((e) => /* @__PURE__ */ n(i.TableCell, {
|
|
110
|
+
value: e,
|
|
111
|
+
children: /* @__PURE__ */ n(i.TableCellTrigger, { children: e.day })
|
|
112
|
+
}, e.toString())) }, t)) })]
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ r("div", {
|
|
115
|
+
className: "dds-date-picker-footer",
|
|
116
|
+
children: [g && /* @__PURE__ */ n(e, {
|
|
117
|
+
type: "button",
|
|
118
|
+
tone: "secondary",
|
|
119
|
+
disabled: b || !l(d(o), !1, s, c, a).valid,
|
|
120
|
+
onClick: () => {
|
|
121
|
+
!b && l(d(o), !1, s, c, a).valid && u.selectToday();
|
|
122
|
+
},
|
|
123
|
+
children: y.today
|
|
124
|
+
}), _ && /* @__PURE__ */ n(i.ClearTrigger, {
|
|
125
|
+
hidden: !1,
|
|
126
|
+
asChild: !0,
|
|
127
|
+
children: /* @__PURE__ */ n(e, {
|
|
128
|
+
type: "button",
|
|
129
|
+
tone: "secondary",
|
|
130
|
+
disabled: b,
|
|
131
|
+
onPointerDown: (e) => e.preventDefault(),
|
|
132
|
+
onClick: () => {
|
|
133
|
+
b || v?.();
|
|
134
|
+
},
|
|
135
|
+
children: y.clear
|
|
136
|
+
})
|
|
137
|
+
})]
|
|
138
|
+
})
|
|
139
|
+
] }) })
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { a, s as i, c as n, o, u as r, l as s, p as t };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=calendar-view-I_sNlioP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-view-I_sNlioP.js","names":[],"sources":["../src/date-only.ts","../src/calendar-view.tsx"],"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 today?: 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 today: ko ? \"오늘\" : \"Today\",\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","import { DatePicker as ArkDatePicker } from \"@ark-ui/react/date-picker\";\nimport { Button } from \"./controls\";\nimport {\n dateMessages,\n todayDate,\n validateInput,\n type CalendarMessages,\n} from \"./date-only\";\nfunction Chevron({ next = false }: { next?: boolean }) {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n aria-hidden=\"true\"\n >\n <path d={next ? \"m9 5 7 7-7 7\" : \"m15 5-7 7 7 7\"} />\n </svg>\n );\n}\nexport interface CalendarViewProps {\n timeZone?: string | undefined;\n min?: string | undefined;\n max?: string | undefined;\n locale?: string | undefined;\n messages?: CalendarMessages | undefined;\n disabled?: boolean | undefined;\n readOnly?: boolean | undefined;\n showToday?: boolean | undefined;\n showClear?: boolean | undefined;\n onClear?: (() => void) | undefined;\n}\n/** Internal view: the caller owns the single Ark root and its selection. */\nexport function CalendarView({\n locale = \"ko-KR\",\n timeZone = \"Asia/Seoul\",\n min,\n max,\n messages,\n disabled,\n readOnly,\n showToday = true,\n showClear = true,\n onClear,\n}: CalendarViewProps) {\n const text = dateMessages(locale, messages),\n locked = disabled || readOnly;\n return (\n <ArkDatePicker.View view=\"day\">\n <ArkDatePicker.Context>\n {(picker) => (\n <>\n <ArkDatePicker.ViewControl className=\"dds-date-picker-header\">\n <ArkDatePicker.PrevTrigger asChild>\n <Button\n type=\"button\"\n tone=\"secondary\"\n aria-label={text.previousMonth}\n >\n <Chevron />\n </Button>\n </ArkDatePicker.PrevTrigger>\n <ArkDatePicker.RangeText />\n <ArkDatePicker.NextTrigger asChild>\n <Button\n type=\"button\"\n tone=\"secondary\"\n aria-label={text.nextMonth}\n >\n <Chevron next />\n </Button>\n </ArkDatePicker.NextTrigger>\n </ArkDatePicker.ViewControl>\n <ArkDatePicker.Table className=\"dds-date-picker-table\">\n <ArkDatePicker.TableHead>\n <ArkDatePicker.TableRow>\n {picker.weekDays.map((day, index) => (\n <ArkDatePicker.TableHeader key={index}>\n {day.short}\n </ArkDatePicker.TableHeader>\n ))}\n </ArkDatePicker.TableRow>\n </ArkDatePicker.TableHead>\n <ArkDatePicker.TableBody>\n {picker.weeks.map((week, index) => (\n <ArkDatePicker.TableRow key={index}>\n {week.map((day) => (\n <ArkDatePicker.TableCell key={day.toString()} value={day}>\n <ArkDatePicker.TableCellTrigger>\n {day.day}\n </ArkDatePicker.TableCellTrigger>\n </ArkDatePicker.TableCell>\n ))}\n </ArkDatePicker.TableRow>\n ))}\n </ArkDatePicker.TableBody>\n </ArkDatePicker.Table>\n <div className=\"dds-date-picker-footer\">\n {showToday && (\n <Button\n type=\"button\"\n tone=\"secondary\"\n disabled={\n locked ||\n !validateInput(todayDate(timeZone), false, min, max, locale)\n .valid\n }\n onClick={() => {\n if (\n !locked &&\n validateInput(\n todayDate(timeZone),\n false,\n min,\n max,\n locale,\n ).valid\n )\n picker.selectToday();\n }}\n >\n {text.today}\n </Button>\n )}\n {showClear && (\n <ArkDatePicker.ClearTrigger hidden={false} asChild>\n <Button\n type=\"button\"\n tone=\"secondary\"\n disabled={locked}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n if (!locked) onClear?.();\n }}\n >\n {text.clear}\n </Button>\n </ArkDatePicker.ClearTrigger>\n )}\n </div>\n </>\n )}\n </ArkDatePicker.Context>\n </ArkDatePicker.View>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CalendarMessages } from "./date-only";
|
|
2
|
+
export interface CalendarViewProps {
|
|
3
|
+
timeZone?: string | undefined;
|
|
4
|
+
min?: string | undefined;
|
|
5
|
+
max?: string | undefined;
|
|
6
|
+
locale?: string | undefined;
|
|
7
|
+
messages?: CalendarMessages | undefined;
|
|
8
|
+
disabled?: boolean | undefined;
|
|
9
|
+
readOnly?: boolean | undefined;
|
|
10
|
+
showToday?: boolean | undefined;
|
|
11
|
+
showClear?: boolean | undefined;
|
|
12
|
+
onClear?: (() => void) | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Internal view: the caller owns the single Ark root and its selection. */
|
|
15
|
+
export declare function CalendarView({ locale, timeZone, min, max, messages, disabled, readOnly, showToday, showClear, onClear, }: CalendarViewProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=calendar-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-view.d.ts","sourceRoot":"","sources":["../src/calendar-view.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAC;AAgBrB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACpC;AACD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAC3B,MAAgB,EAChB,QAAuB,EACvB,GAAG,EACH,GAAG,EACH,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAgB,EAChB,SAAgB,EAChB,OAAO,GACR,EAAE,iBAAiB,+BAqGnB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type CalendarMessages } from "./date-only";
|
|
2
|
+
export interface CalendarProps {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (value: string) => void;
|
|
6
|
+
locale?: string;
|
|
7
|
+
timeZone?: string;
|
|
8
|
+
min?: string;
|
|
9
|
+
max?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
readOnly?: boolean;
|
|
12
|
+
startOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
13
|
+
messages?: CalendarMessages;
|
|
14
|
+
showToday?: boolean;
|
|
15
|
+
clearable?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export type { CalendarMessages } from "./date-only";
|
|
18
|
+
export declare function Calendar({ label, value, onChange, locale, timeZone, min, max, disabled, readOnly, startOfWeek, messages, showToday, clearable, }: CalendarProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=calendar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../src/calendar.tsx"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAC;AACrB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AACD,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,MAAgB,EAChB,QAAuB,EACvB,GAAG,EACH,GAAG,EACH,QAAgB,EAChB,QAAgB,EAChB,WAAe,EACf,QAAQ,EACR,SAAgB,EAChB,SAAgB,GACjB,EAAE,aAAa,+BAmDf"}
|
package/dist/calendar.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { a as e, r as t, s as n, t as r } from "./calendar-view-I_sNlioP.js";
|
|
2
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
3
|
+
import { DatePicker as a, parseDate as o } from "@ark-ui/react/date-picker";
|
|
4
|
+
//#region src/calendar.tsx
|
|
5
|
+
function s({ label: s, value: c, onChange: l, locale: u = "ko-KR", timeZone: d = "Asia/Seoul", min: f, max: p, disabled: m = !1, readOnly: h = !1, startOfWeek: g = 0, messages: _, showToday: v = !0, clearable: y = !0 }) {
|
|
6
|
+
let b = t(u, _);
|
|
7
|
+
return /* @__PURE__ */ i(a.Root, {
|
|
8
|
+
className: "dds-calendar",
|
|
9
|
+
"aria-label": s,
|
|
10
|
+
role: "group",
|
|
11
|
+
inline: !0,
|
|
12
|
+
locale: u,
|
|
13
|
+
timeZone: d,
|
|
14
|
+
disabled: m,
|
|
15
|
+
readOnly: h,
|
|
16
|
+
min: f && e(f) ? o(f) : void 0,
|
|
17
|
+
max: p && e(p) ? o(p) : void 0,
|
|
18
|
+
startOfWeek: g,
|
|
19
|
+
minView: "day",
|
|
20
|
+
maxView: "day",
|
|
21
|
+
fixedWeeks: !0,
|
|
22
|
+
value: e(c) ? [o(c)] : [],
|
|
23
|
+
translations: {
|
|
24
|
+
dayCell: (e) => b.selectDate(e.valueText),
|
|
25
|
+
clearTrigger: b.clear
|
|
26
|
+
},
|
|
27
|
+
onValueChange: (e) => {
|
|
28
|
+
let t = e.value[0]?.toString() ?? "";
|
|
29
|
+
!m && !h && n(t, !1, f, p, u).valid && l(t);
|
|
30
|
+
},
|
|
31
|
+
children: /* @__PURE__ */ i(a.Content, {
|
|
32
|
+
className: "dds-date-picker-content",
|
|
33
|
+
"aria-label": s,
|
|
34
|
+
children: /* @__PURE__ */ i(r, {
|
|
35
|
+
timeZone: d,
|
|
36
|
+
min: f,
|
|
37
|
+
max: p,
|
|
38
|
+
locale: u,
|
|
39
|
+
messages: _,
|
|
40
|
+
disabled: m,
|
|
41
|
+
readOnly: h,
|
|
42
|
+
showToday: v,
|
|
43
|
+
showClear: y
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { s as Calendar };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","names":[],"sources":["../src/calendar.tsx"],"sourcesContent":["import {\n DatePicker as ArkDatePicker,\n parseDate,\n} from \"@ark-ui/react/date-picker\";\nimport { CalendarView } from \"./calendar-view\";\nimport {\n isCalendarDate,\n validateInput,\n dateMessages,\n type CalendarMessages,\n} from \"./date-only\";\nexport interface CalendarProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n locale?: string;\n timeZone?: string;\n min?: string;\n max?: string;\n disabled?: boolean;\n readOnly?: boolean;\n startOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;\n messages?: CalendarMessages;\n showToday?: boolean;\n clearable?: boolean;\n}\nexport type { CalendarMessages } from \"./date-only\";\nexport function Calendar({\n label,\n value,\n onChange,\n locale = \"ko-KR\",\n timeZone = \"Asia/Seoul\",\n min,\n max,\n disabled = false,\n readOnly = false,\n startOfWeek = 0,\n messages,\n showToday = true,\n clearable = true,\n}: CalendarProps) {\n const text = dateMessages(locale, messages);\n return (\n <ArkDatePicker.Root\n className=\"dds-calendar\"\n aria-label={label}\n role=\"group\"\n inline\n locale={locale}\n timeZone={timeZone}\n disabled={disabled}\n readOnly={readOnly}\n min={min && isCalendarDate(min) ? parseDate(min) : undefined}\n max={max && isCalendarDate(max) ? parseDate(max) : undefined}\n startOfWeek={startOfWeek}\n minView=\"day\"\n maxView=\"day\"\n fixedWeeks\n value={isCalendarDate(value) ? [parseDate(value)] : []}\n translations={{\n dayCell: (state) => text.selectDate(state.valueText),\n clearTrigger: text.clear,\n }}\n onValueChange={(details) => {\n const next = details.value[0]?.toString() ?? \"\";\n if (\n !disabled &&\n !readOnly &&\n validateInput(next, false, min, max, locale).valid\n )\n onChange(next);\n }}\n >\n <ArkDatePicker.Content\n className=\"dds-date-picker-content\"\n aria-label={label}\n >\n <CalendarView\n timeZone={timeZone}\n min={min}\n max={max}\n locale={locale}\n messages={messages}\n disabled={disabled}\n readOnly={readOnly}\n showToday={showToday}\n showClear={clearable}\n />\n </ArkDatePicker.Content>\n </ArkDatePicker.Root>\n );\n}\n"],"mappings":";;;;AA2BA,SAAgB,EAAS,EACvB,UACA,UACA,aACA,YAAS,SACT,cAAW,cACX,QACA,QACA,cAAW,IACX,cAAW,IACX,iBAAc,GACd,aACA,eAAY,IACZ,eAAY,MACI;CAChB,IAAM,IAAO,EAAa,GAAQ,CAAQ;CAC1C,OACE,kBAAC,EAAc,MAAf;EACE,WAAU;EACV,cAAY;EACZ,MAAK;EACL,QAAA;EACQ;EACE;EACA;EACA;EACV,KAAK,KAAO,EAAe,CAAG,IAAI,EAAU,CAAG,IAAI,KAAA;EACnD,KAAK,KAAO,EAAe,CAAG,IAAI,EAAU,CAAG,IAAI,KAAA;EACtC;EACb,SAAQ;EACR,SAAQ;EACR,YAAA;EACA,OAAO,EAAe,CAAK,IAAI,CAAC,EAAU,CAAK,CAAC,IAAI,CAAC;EACrD,cAAc;GACZ,UAAU,MAAU,EAAK,WAAW,EAAM,SAAS;GACnD,cAAc,EAAK;EACrB;EACA,gBAAgB,MAAY;GAC1B,IAAM,IAAO,EAAQ,MAAM,EAAE,EAAE,SAAS,KAAK;GAC7C,AACE,CAAC,KACD,CAAC,KACD,EAAc,GAAM,IAAO,GAAK,GAAK,CAAM,CAAC,CAAC,SAE7C,EAAS,CAAI;EACjB;EAEA,UAAA,kBAAC,EAAc,SAAf;GACE,WAAU;GACV,cAAY;GAEZ,UAAA,kBAAC,GAAD;IACY;IACL;IACA;IACG;IACE;IACA;IACA;IACC;IACX,WAAW;GACZ,CAAA;EACoB,CAAA;CACL,CAAA;AAExB"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { useEffect as e, useMemo as t, useRef as n, useState as r } from "react";
|
|
2
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
3
|
+
import { Portal as o } from "@ark-ui/react/portal";
|
|
4
|
+
import { Combobox as s, createListCollection as c } from "@ark-ui/react/combobox";
|
|
5
|
+
import { Select as l } from "@ark-ui/react/select";
|
|
6
|
+
import { defaultRangeExtractor as u, useVirtualizer as d } from "@tanstack/react-virtual";
|
|
7
|
+
//#region src/choice-types.ts
|
|
8
|
+
function f(e) {
|
|
9
|
+
let t = /* @__PURE__ */ new Set();
|
|
10
|
+
for (let n of e) {
|
|
11
|
+
if (!n.value || t.has(n.value)) throw Error(`DDS choice: option IDs must be nonempty and unique (${JSON.stringify(n.value)})`);
|
|
12
|
+
t.add(n.value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
var p = {
|
|
16
|
+
open: "선택 열기",
|
|
17
|
+
clear: "선택 지우기",
|
|
18
|
+
loading: "불러오는 중",
|
|
19
|
+
empty: "결과 없음",
|
|
20
|
+
error: "불러오지 못했습니다",
|
|
21
|
+
retry: "다시 시도"
|
|
22
|
+
};
|
|
23
|
+
function m() {
|
|
24
|
+
return globalThis.process?.env?.NODE_ENV !== "production";
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/internal/choice.tsx
|
|
28
|
+
var h = {
|
|
29
|
+
position: "absolute",
|
|
30
|
+
width: 1,
|
|
31
|
+
height: 1,
|
|
32
|
+
padding: 0,
|
|
33
|
+
border: 0,
|
|
34
|
+
clipPath: "inset(50%)",
|
|
35
|
+
overflow: "hidden",
|
|
36
|
+
whiteSpace: "nowrap"
|
|
37
|
+
};
|
|
38
|
+
function g(g) {
|
|
39
|
+
f(g.items);
|
|
40
|
+
let [_, v] = r(g.defaultValue ?? ""), y = g.value ?? _, b = g.items.find((e) => e.value === y) ?? (g.selectedOption?.value === y ? g.selectedOption : void 0), x = b?.label ?? y, [S, C] = r(g.defaultInputValue ?? x), w = g.inputValue ?? S, [T, E] = r(!1), [D, O] = r(null), k = n(null), A = n(null), j = n(null), [M, N] = r(null);
|
|
41
|
+
e(() => {
|
|
42
|
+
let e = k.current;
|
|
43
|
+
e && N(e.closest("[role=\"dialog\"], [role=\"alertdialog\"]") ?? e.ownerDocument.body);
|
|
44
|
+
}, []);
|
|
45
|
+
let P = n(!1), F = n({
|
|
46
|
+
value: y,
|
|
47
|
+
label: x
|
|
48
|
+
}), I = n(null), L = (e) => g.items.find((t) => t.value === e)?.label ?? (g.selectedOption?.value === e ? g.selectedOption.label : e), R = {
|
|
49
|
+
...p,
|
|
50
|
+
...g.messages
|
|
51
|
+
}, z = g.disabled || g.readOnly, B = (e) => {
|
|
52
|
+
(I.current?.from !== w || I.current.to !== e) && (I.current = null, g.inputValue === void 0 && C(e), g.onInputValueChange?.(e));
|
|
53
|
+
}, V = (e) => {
|
|
54
|
+
e !== w && (I.current?.from !== w || I.current.to !== e) && (I.current = {
|
|
55
|
+
from: w,
|
|
56
|
+
to: e
|
|
57
|
+
}, g.inputValue === void 0 ? C(e) : g.onInputValueChange?.(e));
|
|
58
|
+
}, H = (e) => {
|
|
59
|
+
g.value === void 0 && v(e), g.onValueChange?.(e);
|
|
60
|
+
};
|
|
61
|
+
e(() => {
|
|
62
|
+
(F.current.value !== y || F.current.label !== x) && (F.current = {
|
|
63
|
+
value: y,
|
|
64
|
+
label: x
|
|
65
|
+
}, V(x));
|
|
66
|
+
}, [y, x]), e(() => {
|
|
67
|
+
m() && y && !b && console.warn(`DDS choice: no label supplied for selected ID ${JSON.stringify(y)}; pass selectedOption when the selection is outside items.`);
|
|
68
|
+
}, [y, b]), e(() => {
|
|
69
|
+
let e = A.current?.form;
|
|
70
|
+
if (!e) return;
|
|
71
|
+
let t = (e) => queueMicrotask(() => {
|
|
72
|
+
if (e.defaultPrevented) return;
|
|
73
|
+
let t = g.value ?? g.defaultValue ?? "", n = L(t);
|
|
74
|
+
F.current = {
|
|
75
|
+
value: t,
|
|
76
|
+
label: n
|
|
77
|
+
}, g.value === void 0 && v(t);
|
|
78
|
+
let r = g.defaultInputValue ?? n;
|
|
79
|
+
I.current = null, g.inputValue === void 0 ? C(r) : V(r), E(!1), k.current instanceof HTMLInputElement && (k.current.value = g.inputValue ?? r), A.current && (A.current.value = t);
|
|
80
|
+
});
|
|
81
|
+
return e.addEventListener("reset", t), () => e.removeEventListener("reset", t);
|
|
82
|
+
}, [
|
|
83
|
+
g.defaultValue,
|
|
84
|
+
g.defaultInputValue,
|
|
85
|
+
g.value,
|
|
86
|
+
g.inputValue,
|
|
87
|
+
g.items,
|
|
88
|
+
g.selectedOption,
|
|
89
|
+
g.form
|
|
90
|
+
]);
|
|
91
|
+
let U = t(() => g.searchable && g.filterMode !== "external" && w !== x ? g.items.filter((e) => e.label.toLocaleLowerCase().includes(w.toLocaleLowerCase())) : g.items, [
|
|
92
|
+
g.items,
|
|
93
|
+
g.searchable,
|
|
94
|
+
g.filterMode,
|
|
95
|
+
w,
|
|
96
|
+
x
|
|
97
|
+
]), W = t(() => c({
|
|
98
|
+
items: U,
|
|
99
|
+
itemToString: (e) => e.label,
|
|
100
|
+
itemToValue: (e) => e.value,
|
|
101
|
+
isItemDisabled: (e) => !!e.disabled
|
|
102
|
+
}), [U]), G = !!g.virtualization, K = g.virtualization ? g.virtualization.itemHeight : void 0, q = Number.isFinite(K) ? Math.max(40, K) : 40, J = U.findIndex((e) => e.value === D), Y = d({
|
|
103
|
+
count: U.length,
|
|
104
|
+
getScrollElement: () => j.current,
|
|
105
|
+
estimateSize: () => q,
|
|
106
|
+
overscan: g.virtualization ? g.virtualization.overscan ?? 5 : 5,
|
|
107
|
+
enabled: G && T,
|
|
108
|
+
initialRect: {
|
|
109
|
+
width: 0,
|
|
110
|
+
height: 320
|
|
111
|
+
},
|
|
112
|
+
rangeExtractor: (e) => {
|
|
113
|
+
let t = u(e);
|
|
114
|
+
return J >= 0 && !t.includes(J) && t.push(J), t.sort((e, t) => e - t);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
e(() => {
|
|
118
|
+
O(null), G && T && Y.scrollToIndex(Math.max(0, U.findIndex((e) => e.value === y)), { align: "auto" });
|
|
119
|
+
}, [U, T]);
|
|
120
|
+
let X = g.searchable ? s : l, Z = G ? Y.getVirtualItems().map((e) => ({
|
|
121
|
+
index: e.index,
|
|
122
|
+
start: e.start
|
|
123
|
+
})) : U.map((e, t) => ({
|
|
124
|
+
index: t,
|
|
125
|
+
start: 0
|
|
126
|
+
}));
|
|
127
|
+
G && J >= 0 && !Z.some((e) => e.index === J) && Z.push({
|
|
128
|
+
index: J,
|
|
129
|
+
start: J * q
|
|
130
|
+
});
|
|
131
|
+
let Q = g.loading ? R.loading : g.error ? typeof g.error == "string" ? g.error : R.error : U.length === 0 ? R.empty : "", $ = {
|
|
132
|
+
collection: W,
|
|
133
|
+
value: y ? [y] : [],
|
|
134
|
+
open: T && !z,
|
|
135
|
+
disabled: g.disabled,
|
|
136
|
+
readOnly: g.readOnly,
|
|
137
|
+
onOpenChange: (e) => {
|
|
138
|
+
z || E(e.open);
|
|
139
|
+
},
|
|
140
|
+
onValueChange: (e) => {
|
|
141
|
+
if (z || P.current) return;
|
|
142
|
+
let t = e.value[0] ?? "";
|
|
143
|
+
t !== y && H(t);
|
|
144
|
+
},
|
|
145
|
+
onHighlightChange: (e) => O(e.highlightedValue),
|
|
146
|
+
scrollToIndexFn: G ? ({ index: e }) => Y.scrollToIndex(e, { align: "auto" }) : void 0,
|
|
147
|
+
positioning: {
|
|
148
|
+
placement: "bottom-start",
|
|
149
|
+
sameWidth: !0,
|
|
150
|
+
gutter: 4,
|
|
151
|
+
strategy: M?.matches("[role=\"dialog\"], [role=\"alertdialog\"]") ? "fixed" : "absolute",
|
|
152
|
+
hideWhenDetached: !!M?.matches("[role=\"dialog\"], [role=\"alertdialog\"]")
|
|
153
|
+
}
|
|
154
|
+
}, ee = g.searchable ? {
|
|
155
|
+
inputValue: w,
|
|
156
|
+
onInputValueChange: (e) => {
|
|
157
|
+
!z && e.inputValue !== w && B(e.inputValue);
|
|
158
|
+
},
|
|
159
|
+
selectionBehavior: "preserve"
|
|
160
|
+
} : {};
|
|
161
|
+
return /* @__PURE__ */ a(X.Root, {
|
|
162
|
+
...$,
|
|
163
|
+
...ee,
|
|
164
|
+
id: g.id,
|
|
165
|
+
className: "dds-choice",
|
|
166
|
+
"data-label-placement": g.labelPlacement ?? "outside",
|
|
167
|
+
"data-has-value": y || w ? "" : void 0,
|
|
168
|
+
children: [
|
|
169
|
+
g.label && /* @__PURE__ */ i(X.Label, {
|
|
170
|
+
className: "dds-choice-label",
|
|
171
|
+
onClick: () => k.current?.focus(),
|
|
172
|
+
children: g.label
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ a(X.Control, {
|
|
175
|
+
className: "dds-choice-control",
|
|
176
|
+
children: [
|
|
177
|
+
g.searchable ? /* @__PURE__ */ i(s.Input, {
|
|
178
|
+
ref: (e) => {
|
|
179
|
+
k.current = e;
|
|
180
|
+
},
|
|
181
|
+
className: "dds-choice-input",
|
|
182
|
+
"aria-label": g["aria-label"],
|
|
183
|
+
"aria-labelledby": g["aria-labelledby"],
|
|
184
|
+
"aria-describedby": g["aria-describedby"],
|
|
185
|
+
"aria-required": g.required,
|
|
186
|
+
placeholder: g.placeholder,
|
|
187
|
+
onCompositionStart: () => {
|
|
188
|
+
P.current = !0;
|
|
189
|
+
},
|
|
190
|
+
onCompositionEnd: () => {
|
|
191
|
+
P.current = !1;
|
|
192
|
+
},
|
|
193
|
+
onKeyDown: (e) => {
|
|
194
|
+
P.current && e.key === "Enter" && (e.preventDefault(), e.stopPropagation());
|
|
195
|
+
},
|
|
196
|
+
onBlur: () => {
|
|
197
|
+
y && V(x);
|
|
198
|
+
}
|
|
199
|
+
}) : null,
|
|
200
|
+
/* @__PURE__ */ i(X.Trigger, {
|
|
201
|
+
ref: (e) => {
|
|
202
|
+
g.searchable || (k.current = e);
|
|
203
|
+
},
|
|
204
|
+
className: "dds-choice-trigger",
|
|
205
|
+
"aria-label": g.searchable ? R.open : g["aria-label"],
|
|
206
|
+
"aria-labelledby": g["aria-labelledby"],
|
|
207
|
+
"aria-describedby": g["aria-describedby"],
|
|
208
|
+
"aria-required": g.required,
|
|
209
|
+
children: g.searchable ? "⌄" : /* @__PURE__ */ i("span", {
|
|
210
|
+
className: "dds-choice-value",
|
|
211
|
+
children: x || g.placeholder || R.open
|
|
212
|
+
})
|
|
213
|
+
}),
|
|
214
|
+
g.clearable && !z && (y || w) ? /* @__PURE__ */ i("button", {
|
|
215
|
+
className: "dds-choice-clear",
|
|
216
|
+
type: "button",
|
|
217
|
+
"aria-label": R.clear,
|
|
218
|
+
onPointerDown: (e) => e.preventDefault(),
|
|
219
|
+
onClick: () => {
|
|
220
|
+
H(""), B(""), E(!1), k.current?.focus();
|
|
221
|
+
},
|
|
222
|
+
children: "×"
|
|
223
|
+
}) : null
|
|
224
|
+
]
|
|
225
|
+
}),
|
|
226
|
+
/* @__PURE__ */ i("input", {
|
|
227
|
+
ref: A,
|
|
228
|
+
className: "dds-choice-validation",
|
|
229
|
+
style: h,
|
|
230
|
+
tabIndex: -1,
|
|
231
|
+
"aria-hidden": "true",
|
|
232
|
+
name: g.name,
|
|
233
|
+
form: g.form,
|
|
234
|
+
value: y,
|
|
235
|
+
required: g.required,
|
|
236
|
+
disabled: g.disabled,
|
|
237
|
+
onChange: () => {},
|
|
238
|
+
onInvalid: (e) => {
|
|
239
|
+
e.preventDefault(), k.current?.focus();
|
|
240
|
+
}
|
|
241
|
+
}),
|
|
242
|
+
/* @__PURE__ */ a("div", {
|
|
243
|
+
className: "dds-choice-status",
|
|
244
|
+
role: "status",
|
|
245
|
+
"aria-live": "polite",
|
|
246
|
+
children: [Q, g.error && g.onRetry ? /* @__PURE__ */ i("button", {
|
|
247
|
+
className: "dds-choice-retry",
|
|
248
|
+
type: "button",
|
|
249
|
+
onClick: g.onRetry,
|
|
250
|
+
children: R.retry
|
|
251
|
+
}) : null]
|
|
252
|
+
}),
|
|
253
|
+
M && /* @__PURE__ */ i(o, {
|
|
254
|
+
container: { current: M },
|
|
255
|
+
children: /* @__PURE__ */ i(X.Positioner, {
|
|
256
|
+
className: "dds-choice-positioner",
|
|
257
|
+
children: /* @__PURE__ */ i(X.Content, {
|
|
258
|
+
ref: j,
|
|
259
|
+
className: "dds-choice-content",
|
|
260
|
+
style: {
|
|
261
|
+
maxHeight: "min(320px, var(--available-height, 320px))",
|
|
262
|
+
overflow: "auto"
|
|
263
|
+
},
|
|
264
|
+
children: /* @__PURE__ */ i("div", {
|
|
265
|
+
style: G ? {
|
|
266
|
+
height: Y.getTotalSize(),
|
|
267
|
+
position: "relative"
|
|
268
|
+
} : void 0,
|
|
269
|
+
children: Z.map((e) => {
|
|
270
|
+
let t = U[e.index];
|
|
271
|
+
return /* @__PURE__ */ a(X.Item, {
|
|
272
|
+
item: t,
|
|
273
|
+
className: "dds-choice-item",
|
|
274
|
+
"aria-posinset": e.index + 1,
|
|
275
|
+
"aria-setsize": U.length,
|
|
276
|
+
style: G ? {
|
|
277
|
+
position: "absolute",
|
|
278
|
+
top: 0,
|
|
279
|
+
left: 0,
|
|
280
|
+
width: "100%",
|
|
281
|
+
height: q,
|
|
282
|
+
transform: `translateY(${e.start}px)`
|
|
283
|
+
} : void 0,
|
|
284
|
+
children: [/* @__PURE__ */ i(X.ItemText, { children: t.label }), t.description ? /* @__PURE__ */ i("span", {
|
|
285
|
+
className: "dds-choice-description",
|
|
286
|
+
children: t.description
|
|
287
|
+
}) : null]
|
|
288
|
+
}, t.value);
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
export { g as t };
|
|
299
|
+
|
|
300
|
+
//# sourceMappingURL=choice-B3vNMfKK.js.map
|