@mitcsutt/kiln-ui 0.5.0 → 0.7.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/dist/components/actions/CopyButton/CopyButton.d.ts +58 -0
- package/dist/components/actions/CopyButton/CopyButton.js +63 -0
- package/dist/components/actions/CopyButton/CopyButton.js.map +1 -0
- package/dist/components/actions/CopyButton/CopyButton.module.js +9 -0
- package/dist/components/actions/CopyButton/CopyButton.module.js.map +1 -0
- package/dist/components/actions/CopyButton/index.d.ts +4 -0
- package/dist/components/actions/CopyButton/useClipboard.d.ts +35 -0
- package/dist/components/actions/CopyButton/useClipboard.js +62 -0
- package/dist/components/actions/CopyButton/useClipboard.js.map +1 -0
- package/dist/components/actions/ToggleChip/ToggleChip.d.ts +6 -0
- package/dist/components/actions/ToggleChip/ToggleChip.js +26 -24
- package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
- package/dist/components/display/Badge/Badge.d.ts +6 -0
- package/dist/components/display/Badge/Badge.js +16 -15
- package/dist/components/display/Badge/Badge.js.map +1 -1
- package/dist/components/display/CodeBlock/CodeBlock.d.ts +44 -3
- package/dist/components/display/CodeBlock/CodeBlock.js +39 -47
- package/dist/components/display/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/display/CodeBlock/CodeBlock.module.js +4 -3
- package/dist/components/display/CodeBlock/CodeBlock.module.js.map +1 -1
- package/dist/components/display/CodeBlock/index.d.ts +1 -1
- package/dist/components/display/Swatch/Swatch.d.ts +52 -0
- package/dist/components/display/Swatch/Swatch.js +27 -0
- package/dist/components/display/Swatch/Swatch.js.map +1 -0
- package/dist/components/display/Swatch/Swatch.module.js +6 -0
- package/dist/components/display/Swatch/Swatch.module.js.map +1 -0
- package/dist/components/display/Swatch/index.d.ts +2 -0
- package/dist/components/display/Tag/Tag.d.ts +7 -0
- package/dist/components/display/Tag/Tag.js +31 -26
- package/dist/components/display/Tag/Tag.js.map +1 -1
- package/dist/components/feedback/Indicator/Indicator.d.ts +74 -0
- package/dist/components/feedback/Indicator/Indicator.js +50 -0
- package/dist/components/feedback/Indicator/Indicator.js.map +1 -0
- package/dist/components/feedback/Indicator/Indicator.module.js +12 -0
- package/dist/components/feedback/Indicator/Indicator.module.js.map +1 -0
- package/dist/components/feedback/Indicator/index.d.ts +2 -0
- package/dist/components/feedback/Toaster/Toaster.d.ts +71 -0
- package/dist/components/feedback/Toaster/Toaster.js +121 -0
- package/dist/components/feedback/Toaster/Toaster.js.map +1 -0
- package/dist/components/feedback/Toaster/Toaster.module.js +20 -0
- package/dist/components/feedback/Toaster/Toaster.module.js.map +1 -0
- package/dist/components/feedback/Toaster/index.d.ts +4 -0
- package/dist/components/feedback/Toaster/toast.d.ts +96 -0
- package/dist/components/feedback/Toaster/toast.js +131 -0
- package/dist/components/feedback/Toaster/toast.js.map +1 -0
- package/dist/components/inputs/Calendar/Calendar.d.ts +87 -0
- package/dist/components/inputs/Calendar/Calendar.js +217 -0
- package/dist/components/inputs/Calendar/Calendar.js.map +1 -0
- package/dist/components/inputs/Calendar/Calendar.module.js +18 -0
- package/dist/components/inputs/Calendar/Calendar.module.js.map +1 -0
- package/dist/components/inputs/Calendar/index.d.ts +2 -0
- package/dist/components/inputs/Combobox/Combobox.js +36 -44
- package/dist/components/inputs/Combobox/Combobox.js.map +1 -1
- package/dist/components/inputs/DateField/DateField.d.ts +17 -0
- package/dist/components/inputs/DateField/DateField.js +26 -0
- package/dist/components/inputs/DateField/DateField.js.map +1 -0
- package/dist/components/inputs/DateField/index.d.ts +2 -0
- package/dist/components/inputs/DateInput/DateInput.d.ts +75 -0
- package/dist/components/inputs/DateInput/DateInput.js +139 -0
- package/dist/components/inputs/DateInput/DateInput.js.map +1 -0
- package/dist/components/inputs/DateInput/index.d.ts +3 -0
- package/dist/components/inputs/DateRangeField/DateRangeField.d.ts +18 -3
- package/dist/components/inputs/DateRangeField/DateRangeField.js.map +1 -1
- package/dist/components/inputs/DateRangeField/DateRangeField.module.js +8 -3
- package/dist/components/inputs/DateRangeField/DateRangeField.module.js.map +1 -1
- package/dist/components/inputs/DateRangeField/DateRangePickerField.d.ts +48 -0
- package/dist/components/inputs/DateRangeField/DateRangePickerField.js +246 -0
- package/dist/components/inputs/DateRangeField/DateRangePickerField.js.map +1 -0
- package/dist/components/inputs/DateRangeField/index.d.ts +2 -0
- package/dist/components/inputs/DateTimeField/DateTimeField.d.ts +17 -0
- package/dist/components/inputs/DateTimeField/DateTimeField.js +26 -0
- package/dist/components/inputs/DateTimeField/DateTimeField.js.map +1 -0
- package/dist/components/inputs/DateTimeField/index.d.ts +2 -0
- package/dist/components/inputs/DateTimeInput/DateTimeInput.d.ts +83 -0
- package/dist/components/inputs/DateTimeInput/DateTimeInput.js +216 -0
- package/dist/components/inputs/DateTimeInput/DateTimeInput.js.map +1 -0
- package/dist/components/inputs/DateTimeInput/index.d.ts +2 -0
- package/dist/components/inputs/JsonField/JsonField.d.ts +23 -0
- package/dist/components/inputs/JsonField/JsonField.js +33 -0
- package/dist/components/inputs/JsonField/JsonField.js.map +1 -0
- package/dist/components/inputs/JsonField/index.d.ts +2 -0
- package/dist/components/inputs/JsonInput/JsonInput.d.ts +119 -0
- package/dist/components/inputs/JsonInput/JsonInput.js +282 -0
- package/dist/components/inputs/JsonInput/JsonInput.js.map +1 -0
- package/dist/components/inputs/JsonInput/JsonInput.module.js +16 -0
- package/dist/components/inputs/JsonInput/JsonInput.module.js.map +1 -0
- package/dist/components/inputs/JsonInput/index.d.ts +4 -0
- package/dist/components/inputs/JsonInput/json.d.ts +59 -0
- package/dist/components/inputs/JsonInput/json.js +231 -0
- package/dist/components/inputs/JsonInput/json.js.map +1 -0
- package/dist/components/inputs/TagsInput/TagsInput.js +5 -5
- package/dist/components/inputs/TimeField/TimeField.d.ts +17 -0
- package/dist/components/inputs/TimeField/TimeField.js +26 -0
- package/dist/components/inputs/TimeField/TimeField.js.map +1 -0
- package/dist/components/inputs/TimeField/index.d.ts +2 -0
- package/dist/components/inputs/TimeInput/TimeInput.d.ts +54 -0
- package/dist/components/inputs/TimeInput/TimeInput.js +107 -0
- package/dist/components/inputs/TimeInput/TimeInput.js.map +1 -0
- package/dist/components/inputs/TimeInput/index.d.ts +2 -0
- package/dist/components/inputs/internal/DateSegments.d.ts +80 -0
- package/dist/components/inputs/internal/DateSegments.js +345 -0
- package/dist/components/inputs/internal/DateSegments.js.map +1 -0
- package/dist/components/inputs/internal/dates.d.ts +101 -0
- package/dist/components/inputs/internal/dates.js +262 -0
- package/dist/components/inputs/internal/dates.js.map +1 -0
- package/dist/components/inputs/internal/filterOptions.d.ts +22 -1
- package/dist/components/inputs/internal/filterOptions.js +32 -1
- package/dist/components/inputs/internal/filterOptions.js.map +1 -1
- package/dist/components/inputs/internal/picker.d.ts +31 -0
- package/dist/components/inputs/internal/picker.js +29 -0
- package/dist/components/inputs/internal/picker.js.map +1 -0
- package/dist/components/inputs/internal/picker.module.js +15 -0
- package/dist/components/inputs/internal/picker.module.js.map +1 -0
- package/dist/components/inputs/internal/segments.module.js +10 -0
- package/dist/components/inputs/internal/segments.module.js.map +1 -0
- package/dist/components/layout/Collapse/Collapse.d.ts +39 -0
- package/dist/components/layout/Collapse/Collapse.js +24 -0
- package/dist/components/layout/Collapse/Collapse.js.map +1 -0
- package/dist/components/layout/Collapse/Collapse.module.js +6 -0
- package/dist/components/layout/Collapse/Collapse.module.js.map +1 -0
- package/dist/components/layout/Collapse/index.d.ts +2 -0
- package/dist/components/layout/Collapse/useHeightMotion.d.ts +16 -0
- package/dist/components/layout/Collapse/useHeightMotion.js +60 -0
- package/dist/components/layout/Collapse/useHeightMotion.js.map +1 -0
- package/dist/components/layout/ShowMore/ShowMore.d.ts +59 -0
- package/dist/components/layout/ShowMore/ShowMore.js +114 -0
- package/dist/components/layout/ShowMore/ShowMore.js.map +1 -0
- package/dist/components/layout/ShowMore/ShowMore.module.js +12 -0
- package/dist/components/layout/ShowMore/ShowMore.module.js.map +1 -0
- package/dist/components/layout/ShowMore/index.d.ts +2 -0
- package/dist/components/layout/Transition/Transition.d.ts +63 -0
- package/dist/components/layout/Transition/Transition.js +63 -0
- package/dist/components/layout/Transition/Transition.js.map +1 -0
- package/dist/components/layout/Transition/Transition.module.js +17 -0
- package/dist/components/layout/Transition/Transition.module.js.map +1 -0
- package/dist/components/layout/Transition/index.d.ts +2 -0
- package/dist/components/navigation/Collapsible/Collapsible.d.ts +49 -0
- package/dist/components/navigation/Collapsible/Collapsible.js +83 -0
- package/dist/components/navigation/Collapsible/Collapsible.js.map +1 -0
- package/dist/components/navigation/Collapsible/Collapsible.module.js +11 -0
- package/dist/components/navigation/Collapsible/Collapsible.module.js.map +1 -0
- package/dist/components/navigation/Collapsible/index.d.ts +2 -0
- package/dist/components/navigation/NavLinks/NavLinks.d.ts +32 -4
- package/dist/components/navigation/NavLinks/NavLinks.js +69 -39
- package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
- package/dist/components/navigation/NavLinks/NavLinks.module.js +13 -3
- package/dist/components/navigation/NavLinks/NavLinks.module.js.map +1 -1
- package/dist/components/navigation/NavLinks/NavLinksGroup.d.ts +49 -0
- package/dist/components/navigation/NavLinks/NavLinksGroup.js +185 -0
- package/dist/components/navigation/NavLinks/NavLinksGroup.js.map +1 -0
- package/dist/components/navigation/NavLinks/context.d.ts +28 -0
- package/dist/components/navigation/NavLinks/context.js +13 -0
- package/dist/components/navigation/NavLinks/context.js.map +1 -0
- package/dist/components/navigation/NavLinks/index.d.ts +2 -0
- package/dist/components/navigation/NavLinks/treeKeys.d.ts +8 -0
- package/dist/components/navigation/NavLinks/treeKeys.js +57 -0
- package/dist/components/navigation/NavLinks/treeKeys.js.map +1 -0
- package/dist/components/overlays/CommandPalette/CommandPalette.d.ts +120 -0
- package/dist/components/overlays/CommandPalette/CommandPalette.js +386 -0
- package/dist/components/overlays/CommandPalette/CommandPalette.js.map +1 -0
- package/dist/components/overlays/CommandPalette/CommandPalette.module.js +31 -0
- package/dist/components/overlays/CommandPalette/CommandPalette.module.js.map +1 -0
- package/dist/components/overlays/CommandPalette/index.d.ts +2 -0
- package/dist/components/overlays/CommandPalette/shortcut.d.ts +28 -0
- package/dist/components/overlays/CommandPalette/shortcut.js +104 -0
- package/dist/components/overlays/CommandPalette/shortcut.js.map +1 -0
- package/dist/highlight/index.d.ts +18 -0
- package/dist/highlight/index.js +103 -0
- package/dist/highlight/index.js.map +1 -0
- package/dist/index.d.ts +41 -5
- package/dist/index.js +123 -100
- package/dist/styles.css +1 -1
- package/dist/themes/fiesta.css +1 -1
- package/dist/themes/flightdeck.css +1 -1
- package/dist/themes/ledger.css +1 -1
- package/dist/themes/monograph.css +1 -1
- package/dist/themes/riso.css +1 -1
- package/dist/utils/newlines.d.ts +2 -0
- package/dist/utils/newlines.js +10 -0
- package/dist/utils/newlines.js.map +1 -0
- package/package.json +13 -2
- package/skills/custom-theme/SKILL.md +32 -0
- package/skills/custom-theme/references/colour.md +20 -0
- package/skills/custom-theme/references/motion.md +9 -0
- package/skills/custom-theme/references/tokens.md +35 -0
- package/skills/design-rules/SKILL.md +5 -2
- package/skills/setup-and-theming/SKILL.md +2 -1
- package/skills/setup-and-theming/references/paper.md +1 -1
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
//#region src/components/inputs/internal/dates.ts
|
|
2
|
+
var e = 864e5, t = /^(\d{4})-(\d{2})-(\d{2})$/, n = /^(\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?$/, r = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?)$/, i = /(?:Z|[+-]\d{2}:?\d{2})$/i, a = (e, t = 2) => String(e).padStart(t, "0");
|
|
3
|
+
function o(e) {
|
|
4
|
+
return e % 4 == 0 && e % 100 != 0 || e % 400 == 0;
|
|
5
|
+
}
|
|
6
|
+
function s(e, t) {
|
|
7
|
+
return t === 2 ? o(e) ? 29 : 28 : [
|
|
8
|
+
4,
|
|
9
|
+
6,
|
|
10
|
+
9,
|
|
11
|
+
11
|
|
12
|
+
].includes(t) ? 30 : 31;
|
|
13
|
+
}
|
|
14
|
+
function c(e) {
|
|
15
|
+
let n = t.exec(e);
|
|
16
|
+
if (!n) return null;
|
|
17
|
+
let [r, i, a] = [
|
|
18
|
+
Number(n[1]),
|
|
19
|
+
Number(n[2]),
|
|
20
|
+
Number(n[3])
|
|
21
|
+
];
|
|
22
|
+
return r < 1 || i < 1 || i > 12 || a < 1 || a > s(r, i) ? null : {
|
|
23
|
+
year: r,
|
|
24
|
+
month: i,
|
|
25
|
+
day: a
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function l(e) {
|
|
29
|
+
return `${a(e.year, 4)}-${a(e.month)}-${a(e.day)}`;
|
|
30
|
+
}
|
|
31
|
+
function u(e) {
|
|
32
|
+
let t = n.exec(e);
|
|
33
|
+
if (!t) return null;
|
|
34
|
+
let [r, i, a] = [
|
|
35
|
+
Number(t[1]),
|
|
36
|
+
Number(t[2]),
|
|
37
|
+
Number(t[3] ?? 0)
|
|
38
|
+
];
|
|
39
|
+
return r > 23 || i > 59 || a > 59 ? null : {
|
|
40
|
+
hour: r,
|
|
41
|
+
minute: i,
|
|
42
|
+
second: a
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function d(e, t = "minute") {
|
|
46
|
+
let n = `${a(e.hour)}:${a(e.minute)}`;
|
|
47
|
+
return t === "second" ? `${n}:${a(e.second)}` : n;
|
|
48
|
+
}
|
|
49
|
+
function f(t) {
|
|
50
|
+
let n = (/* @__PURE__ */ new Date(0)).setUTCFullYear(t.year, t.month - 1, t.day);
|
|
51
|
+
return Math.round(n / e);
|
|
52
|
+
}
|
|
53
|
+
function p(t) {
|
|
54
|
+
let n = /* @__PURE__ */ new Date(t * e);
|
|
55
|
+
return {
|
|
56
|
+
year: n.getUTCFullYear(),
|
|
57
|
+
month: n.getUTCMonth() + 1,
|
|
58
|
+
day: n.getUTCDate()
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function m(e, t) {
|
|
62
|
+
return f(e) - f(t);
|
|
63
|
+
}
|
|
64
|
+
function h(e, t) {
|
|
65
|
+
return e != null && t != null && m(e, t) === 0;
|
|
66
|
+
}
|
|
67
|
+
function g(e, t) {
|
|
68
|
+
return p(f(e) + t);
|
|
69
|
+
}
|
|
70
|
+
function _(e, t) {
|
|
71
|
+
let n = e.year * 12 + (e.month - 1) + t, r = Math.floor(n / 12), i = n % 12 + 1;
|
|
72
|
+
return {
|
|
73
|
+
year: r,
|
|
74
|
+
month: i,
|
|
75
|
+
day: Math.min(e.day, s(r, i))
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function v(e) {
|
|
79
|
+
return ((f(e) + 4) % 7 + 7) % 7;
|
|
80
|
+
}
|
|
81
|
+
function y(e, t, n) {
|
|
82
|
+
return t && m(e, t) < 0 ? t : n && m(e, n) > 0 ? n : e;
|
|
83
|
+
}
|
|
84
|
+
var b = /* @__PURE__ */ new Map();
|
|
85
|
+
function x(e) {
|
|
86
|
+
let t = b.get(e);
|
|
87
|
+
return t || (t = new Intl.DateTimeFormat("en-US", {
|
|
88
|
+
timeZone: e,
|
|
89
|
+
calendar: "gregory",
|
|
90
|
+
numberingSystem: "latn",
|
|
91
|
+
hourCycle: "h23",
|
|
92
|
+
year: "numeric",
|
|
93
|
+
month: "numeric",
|
|
94
|
+
day: "numeric",
|
|
95
|
+
hour: "numeric",
|
|
96
|
+
minute: "numeric",
|
|
97
|
+
second: "numeric"
|
|
98
|
+
}), b.set(e, t)), t;
|
|
99
|
+
}
|
|
100
|
+
function S(e, t) {
|
|
101
|
+
let n = {};
|
|
102
|
+
for (let r of x(t).formatToParts(e)) r.type !== "literal" && (n[r.type] = Number(r.value));
|
|
103
|
+
return {
|
|
104
|
+
date: {
|
|
105
|
+
year: n.year ?? 1970,
|
|
106
|
+
month: n.month ?? 1,
|
|
107
|
+
day: n.day ?? 1
|
|
108
|
+
},
|
|
109
|
+
time: {
|
|
110
|
+
hour: (n.hour ?? 0) % 24,
|
|
111
|
+
minute: n.minute ?? 0,
|
|
112
|
+
second: n.second ?? 0
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function C(t, n) {
|
|
117
|
+
return f(t) * e + ((n.hour * 60 + n.minute) * 60 + n.second) * 1e3;
|
|
118
|
+
}
|
|
119
|
+
function w(t, n, r) {
|
|
120
|
+
let i = C(t, n), a = (e) => {
|
|
121
|
+
let t = S(e, r);
|
|
122
|
+
return C(t.date, t.time);
|
|
123
|
+
}, o = [
|
|
124
|
+
i - e,
|
|
125
|
+
i,
|
|
126
|
+
i + e
|
|
127
|
+
].map((e) => i - (a(e) - e)).sort((e, t) => e - t);
|
|
128
|
+
return o.find((e) => a(e) === i) ?? o[2];
|
|
129
|
+
}
|
|
130
|
+
function T(e, t = Date.now()) {
|
|
131
|
+
if (e) return S(t, e).date;
|
|
132
|
+
let n = new Date(t);
|
|
133
|
+
return {
|
|
134
|
+
year: n.getFullYear(),
|
|
135
|
+
month: n.getMonth() + 1,
|
|
136
|
+
day: n.getDate()
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function E(e, t) {
|
|
140
|
+
if (i.test(e) && /^\d{4}-\d{2}-\d{2}T/i.test(e)) {
|
|
141
|
+
let n = Date.parse(e);
|
|
142
|
+
if (Number.isNaN(n)) return null;
|
|
143
|
+
if (t) return S(n, t);
|
|
144
|
+
let r = new Date(n);
|
|
145
|
+
return {
|
|
146
|
+
date: {
|
|
147
|
+
year: r.getFullYear(),
|
|
148
|
+
month: r.getMonth() + 1,
|
|
149
|
+
day: r.getDate()
|
|
150
|
+
},
|
|
151
|
+
time: {
|
|
152
|
+
hour: r.getHours(),
|
|
153
|
+
minute: r.getMinutes(),
|
|
154
|
+
second: r.getSeconds()
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
let n = r.exec(e);
|
|
159
|
+
if (!n) return null;
|
|
160
|
+
let a = c(n[1] ?? ""), o = u(n[2] ?? "");
|
|
161
|
+
return a && o ? {
|
|
162
|
+
date: a,
|
|
163
|
+
time: o
|
|
164
|
+
} : null;
|
|
165
|
+
}
|
|
166
|
+
function D(e, t = "minute", n) {
|
|
167
|
+
if (!n) return `${l(e.date)}T${d(e.time, t)}`;
|
|
168
|
+
let r = w(e.date, e.time, n);
|
|
169
|
+
return `${new Date(r).toISOString().slice(0, 19)}Z`;
|
|
170
|
+
}
|
|
171
|
+
function O(e, t) {
|
|
172
|
+
return c(e) ?? E(e, t)?.date ?? null;
|
|
173
|
+
}
|
|
174
|
+
var k = "en-AU", A = /* @__PURE__ */ new Set(/* @__PURE__ */ "US.CA.MX.BR.JP.KR.TW.HK.MO.PH.IL.IN.ZA.SA.PE.CO.VE.GT.HN.NI.PA.PR.DO.SV.KE.ET.ZW.TH".split("."));
|
|
175
|
+
function j(e) {
|
|
176
|
+
try {
|
|
177
|
+
let t = new Intl.Locale(e), n = t.getWeekInfo?.() ?? t.weekInfo;
|
|
178
|
+
if (n) return n.firstDay % 7;
|
|
179
|
+
let r = t.maximize?.().region ?? t.region;
|
|
180
|
+
return r && A.has(r) ? 0 : 1;
|
|
181
|
+
} catch {
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function M(e) {
|
|
186
|
+
try {
|
|
187
|
+
let t = new Intl.DateTimeFormat(e, { hour: "numeric" }).resolvedOptions().hourCycle;
|
|
188
|
+
return t === "h11" || t === "h12" ? 12 : 24;
|
|
189
|
+
} catch {
|
|
190
|
+
return 24;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function N(e, t) {
|
|
194
|
+
try {
|
|
195
|
+
return new Intl.DateTimeFormat(e, {
|
|
196
|
+
timeZone: "UTC",
|
|
197
|
+
calendar: "gregory",
|
|
198
|
+
...t
|
|
199
|
+
});
|
|
200
|
+
} catch {
|
|
201
|
+
return new Intl.DateTimeFormat(k, {
|
|
202
|
+
timeZone: "UTC",
|
|
203
|
+
...t
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function P(t) {
|
|
208
|
+
return f(t) * e;
|
|
209
|
+
}
|
|
210
|
+
function F(e, t, n) {
|
|
211
|
+
return N(e, {
|
|
212
|
+
year: "numeric",
|
|
213
|
+
month: "long"
|
|
214
|
+
}).format(P({
|
|
215
|
+
year: t,
|
|
216
|
+
month: n,
|
|
217
|
+
day: 1
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
function I(e, t) {
|
|
221
|
+
return N(e, {
|
|
222
|
+
weekday: "long",
|
|
223
|
+
year: "numeric",
|
|
224
|
+
month: "long",
|
|
225
|
+
day: "numeric"
|
|
226
|
+
}).format(P(t));
|
|
227
|
+
}
|
|
228
|
+
function L(e, t) {
|
|
229
|
+
let n = N(e, { weekday: "short" }), r = N(e, { weekday: "long" });
|
|
230
|
+
return Array.from({ length: 7 }, (e, i) => {
|
|
231
|
+
let a = P({
|
|
232
|
+
year: 2026,
|
|
233
|
+
month: 11,
|
|
234
|
+
day: 1 + (t + i) % 7
|
|
235
|
+
});
|
|
236
|
+
return {
|
|
237
|
+
short: n.format(a),
|
|
238
|
+
long: r.format(a)
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function R(e) {
|
|
243
|
+
let t = N(e, {
|
|
244
|
+
hour: "numeric",
|
|
245
|
+
hourCycle: "h12"
|
|
246
|
+
}), n = (e) => t.formatToParts(Date.UTC(2026, 0, 1, e)).find((e) => e.type === "dayPeriod")?.value ?? (e < 12 ? "AM" : "PM");
|
|
247
|
+
return [n(9), n(21)];
|
|
248
|
+
}
|
|
249
|
+
function z(e, t, n = Date.now()) {
|
|
250
|
+
try {
|
|
251
|
+
return new Intl.DateTimeFormat(e, {
|
|
252
|
+
timeZone: t,
|
|
253
|
+
timeZoneName: "short"
|
|
254
|
+
}).formatToParts(n).find((e) => e.type === "timeZoneName")?.value ?? t;
|
|
255
|
+
} catch {
|
|
256
|
+
return t;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
export { k as DEFAULT_LOCALE, g as addDays, _ as addMonths, y as clampDate, m as compareDates, O as dateOf, v as dayOfWeek, R as dayPeriodNames, s as daysInMonth, j as defaultFirstDayOfWeek, M as defaultHourCycle, l as formatDate, D as formatDateTime, I as formatFullDate, F as formatMonthYear, d as formatTime, p as fromDayNumber, o as isLeapYear, h as isSameDay, a as pad, c as parseDate, E as parseDateTime, u as parseTime, z as timeZoneName, f as toDayNumber, T as todayIn, L as weekdayNames, S as zonedParts, w as zonedToInstant };
|
|
261
|
+
|
|
262
|
+
//# sourceMappingURL=dates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dates.js","names":["DAY_MS","DATE_RE","TIME_RE","DATE_TIME_RE","ZONED_RE","pad","value","length","isLeapYear","year","daysInMonth","month","parseDate","match","text","day","formatDate","date","parseTime","hour","minute","second","formatTime","base","time","granularity","toDayNumber","ms","fromDayNumber","d","days","compareDates","a","b","isSameDay","addDays","addMonths","index","months","dayOfWeek","clampDate","min","max","zoneFormats","zoneFormat","format","timeZone","zonedParts","parts","part","wallMs","zonedToInstant","wall","wallAt","local","candidates","todayIn","now","parseDateTime","formatDateTime","dateOf","DEFAULT_LOCALE","SUNDAY_FIRST","defaultFirstDayOfWeek","intlLocale","locale","info","region","defaultHourCycle","cycle","utcFormat","options","utcMs","formatMonthYear","formatFullDate","weekdayNames","short","long","firstDay","dayPeriodNames","read","timeZoneName"],"sources":["../../../../src/components/inputs/internal/dates.ts"],"sourcesContent":["/**\n * Date and time helpers shared by Calendar and the date, time and date-time inputs.\n *\n * Values travel as ISO strings (`2026-10-15`, `14:30`, `2026-10-15T14:30`), never `Date`\n * objects. A `CalendarDate` is a civil date with no time zone: arithmetic runs on day numbers\n * through `Date.UTC`, so a daylight-saving change can never move a day. Time zones only matter\n * for an instant (`…Z`), and those go through `Intl.DateTimeFormat` (ADR 0042).\n */\n\n/** A civil date. `month` is 1 to 12. */\nexport interface CalendarDate {\n year: number\n month: number\n day: number\n}\n\n/** A time of day on the 24-hour clock. */\nexport interface TimeOfDay {\n hour: number\n minute: number\n second: number\n}\n\n/** The smallest unit a time value keeps. */\nexport type TimeGranularity = 'minute' | 'second'\n\nconst DAY_MS = 86_400_000\nconst DATE_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/\nconst TIME_RE = /^(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d+)?)?$/\nconst DATE_TIME_RE = /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)$/\nconst ZONED_RE = /(?:Z|[+-]\\d{2}:?\\d{2})$/i\n\nexport const pad = (value: number, length = 2): string => String(value).padStart(length, '0')\n\nexport function isLeapYear(year: number): boolean {\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n}\n\nexport function daysInMonth(year: number, month: number): number {\n if (month === 2) return isLeapYear(year) ? 29 : 28\n return [4, 6, 9, 11].includes(month) ? 30 : 31\n}\n\n/** `YYYY-MM-DD` → a date, or `null` when it isn't one (`2026-02-30` isn't). */\nexport function parseDate(text: string): CalendarDate | null {\n const match = DATE_RE.exec(text)\n if (!match) return null\n const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])]\n if (year < 1 || month < 1 || month > 12 || day < 1 || day > daysInMonth(year, month)) return null\n return { year, month, day }\n}\n\nexport function formatDate(date: CalendarDate): string {\n return `${pad(date.year, 4)}-${pad(date.month)}-${pad(date.day)}`\n}\n\n/** `HH:mm` or `HH:mm:ss` (fractions ignored) → a time, or `null`. */\nexport function parseTime(text: string): TimeOfDay | null {\n const match = TIME_RE.exec(text)\n if (!match) return null\n const [hour, minute, second] = [Number(match[1]), Number(match[2]), Number(match[3] ?? 0)]\n if (hour > 23 || minute > 59 || second > 59) return null\n return { hour, minute, second }\n}\n\nexport function formatTime(time: TimeOfDay, granularity: TimeGranularity = 'minute'): string {\n const base = `${pad(time.hour)}:${pad(time.minute)}`\n return granularity === 'second' ? `${base}:${pad(time.second)}` : base\n}\n\n/** Days since 1970-01-01. */\nexport function toDayNumber(date: CalendarDate): number {\n const ms = new Date(0).setUTCFullYear(date.year, date.month - 1, date.day)\n return Math.round(ms / DAY_MS)\n}\n\nexport function fromDayNumber(days: number): CalendarDate {\n const d = new Date(days * DAY_MS)\n return { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate() }\n}\n\nexport function compareDates(a: CalendarDate, b: CalendarDate): number {\n return toDayNumber(a) - toDayNumber(b)\n}\n\nexport function isSameDay(a: CalendarDate | null | undefined, b: CalendarDate | null | undefined) {\n return a != null && b != null && compareDates(a, b) === 0\n}\n\nexport function addDays(date: CalendarDate, days: number): CalendarDate {\n return fromDayNumber(toDayNumber(date) + days)\n}\n\n/** Moves by whole months, keeping the day where the month has it (31 Jan + 1 month = 28 Feb). */\nexport function addMonths(date: CalendarDate, months: number): CalendarDate {\n const index = date.year * 12 + (date.month - 1) + months\n const year = Math.floor(index / 12)\n const month = (index % 12) + 1\n return { year, month, day: Math.min(date.day, daysInMonth(year, month)) }\n}\n\n/** 0 (Sunday) to 6 (Saturday). */\nexport function dayOfWeek(date: CalendarDate): number {\n return (((toDayNumber(date) + 4) % 7) + 7) % 7\n}\n\nexport function clampDate(\n date: CalendarDate,\n min: CalendarDate | null,\n max: CalendarDate | null,\n): CalendarDate {\n if (min && compareDates(date, min) < 0) return min\n if (max && compareDates(date, max) > 0) return max\n return date\n}\n\n/* ─── Time zones ─────────────────────────────────────────────────────────── */\n\nconst zoneFormats = new Map<string, Intl.DateTimeFormat>()\n\nfunction zoneFormat(timeZone: string): Intl.DateTimeFormat {\n let format = zoneFormats.get(timeZone)\n if (!format) {\n format = new Intl.DateTimeFormat('en-US', {\n timeZone,\n calendar: 'gregory',\n numberingSystem: 'latn',\n hourCycle: 'h23',\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n })\n zoneFormats.set(timeZone, format)\n }\n return format\n}\n\n/** The wall-clock date and time at instant `ms` in `timeZone` (an IANA name or `UTC`). */\nexport function zonedParts(ms: number, timeZone: string): { date: CalendarDate; time: TimeOfDay } {\n const parts: Partial<Record<Intl.DateTimeFormatPartTypes, number>> = {}\n for (const part of zoneFormat(timeZone).formatToParts(ms)) {\n if (part.type !== 'literal') parts[part.type] = Number(part.value)\n }\n return {\n date: { year: parts.year ?? 1970, month: parts.month ?? 1, day: parts.day ?? 1 },\n time: { hour: (parts.hour ?? 0) % 24, minute: parts.minute ?? 0, second: parts.second ?? 0 },\n }\n}\n\nfunction wallMs(date: CalendarDate, time: TimeOfDay): number {\n return toDayNumber(date) * DAY_MS + ((time.hour * 60 + time.minute) * 60 + time.second) * 1000\n}\n\n/**\n * The instant a wall-clock time in `timeZone` names. A time skipped by a daylight-saving change\n * moves forward with the clocks; a repeated one resolves to its first occurrence.\n */\nexport function zonedToInstant(date: CalendarDate, time: TimeOfDay, timeZone: string): number {\n const wall = wallMs(date, time)\n const wallAt = (ms: number) => {\n const local = zonedParts(ms, timeZone)\n return wallMs(local.date, local.time)\n }\n // A zone's offset either side of a change: sample a day before, at, and a day after.\n const candidates = [wall - DAY_MS, wall, wall + DAY_MS]\n .map((ms) => wall - (wallAt(ms) - ms))\n .sort((a, b) => a - b)\n // A repeated hour reads true at both instants (take the first); a skipped one at neither\n // (take the later, where the clocks have already moved on).\n return candidates.find((ms) => wallAt(ms) === wall) ?? (candidates[2] as number)\n}\n\n/** Today's date, in `timeZone` or the runtime's own zone. */\nexport function todayIn(timeZone?: string, now: number = Date.now()): CalendarDate {\n if (timeZone) return zonedParts(now, timeZone).date\n const d = new Date(now)\n return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() }\n}\n\n/** Whether `timeZone` is one this runtime knows. */\nexport function isValidTimeZone(timeZone: string): boolean {\n try {\n zoneFormat(timeZone)\n return true\n } catch {\n return false\n }\n}\n\n/* ─── Date-time values ───────────────────────────────────────────────────── */\n\nexport interface DateTimeParts {\n date: CalendarDate\n time: TimeOfDay\n}\n\n/**\n * Reads a date-time value. With `timeZone`, the value is an instant: a string with `Z` or an\n * offset is converted to the wall clock there, and one without is taken as that wall clock.\n * Without it, the value is a wall clock (`2026-10-15T14:30`, like `datetime-local`), and an\n * instant is shown in the runtime's own zone.\n */\nexport function parseDateTime(text: string, timeZone?: string): DateTimeParts | null {\n if (ZONED_RE.test(text) && /^\\d{4}-\\d{2}-\\d{2}T/i.test(text)) {\n const ms = Date.parse(text)\n if (Number.isNaN(ms)) return null\n if (timeZone) return zonedParts(ms, timeZone)\n const d = new Date(ms)\n return {\n date: { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() },\n time: { hour: d.getHours(), minute: d.getMinutes(), second: d.getSeconds() },\n }\n }\n const match = DATE_TIME_RE.exec(text)\n if (!match) return null\n const date = parseDate(match[1] ?? '')\n const time = parseTime(match[2] ?? '')\n return date && time ? { date, time } : null\n}\n\n/**\n * Writes a date-time value: a wall clock (`2026-10-15T14:30`) without `timeZone`, or the UTC\n * instant (`2026-10-15T03:30:00Z`) that wall clock names in `timeZone`.\n */\nexport function formatDateTime(\n parts: DateTimeParts,\n granularity: TimeGranularity = 'minute',\n timeZone?: string,\n): string {\n if (!timeZone) return `${formatDate(parts.date)}T${formatTime(parts.time, granularity)}`\n const ms = zonedToInstant(parts.date, parts.time, timeZone)\n return `${new Date(ms).toISOString().slice(0, 19)}Z`\n}\n\n/** The date part of a date or date-time value, for calendar comparisons. */\nexport function dateOf(text: string, timeZone?: string): CalendarDate | null {\n return parseDate(text) ?? parseDateTime(text, timeZone)?.date ?? null\n}\n\n/* ─── Locale ─────────────────────────────────────────────────────────────── */\n\nexport const DEFAULT_LOCALE = 'en-AU'\n\n// Regions whose week starts on Sunday, for runtimes without `Intl.Locale` week info.\nconst SUNDAY_FIRST = new Set([\n 'US', 'CA', 'MX', 'BR', 'JP', 'KR', 'TW', 'HK', 'MO', 'PH', 'IL', 'IN', 'ZA', 'SA',\n 'PE', 'CO', 'VE', 'GT', 'HN', 'NI', 'PA', 'PR', 'DO', 'SV', 'KE', 'ET', 'ZW', 'TH',\n]) // prettier-ignore\n\ninterface WeekInfoLocale {\n getWeekInfo?: () => { firstDay: number }\n weekInfo?: { firstDay: number }\n maximize?: () => { region?: string }\n region?: string\n}\n\n/** The first day of the week for `locale`: 0 (Sunday) to 6 (Saturday). */\nexport function defaultFirstDayOfWeek(locale: string): number {\n try {\n const intlLocale = new Intl.Locale(locale) as unknown as WeekInfoLocale\n const info = intlLocale.getWeekInfo?.() ?? intlLocale.weekInfo\n if (info) return info.firstDay % 7\n const region = intlLocale.maximize?.().region ?? intlLocale.region\n return region && SUNDAY_FIRST.has(region) ? 0 : 1\n } catch {\n return 1\n }\n}\n\n/** 12 or 24, from the locale's own clock. */\nexport function defaultHourCycle(locale: string): 12 | 24 {\n try {\n const cycle = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).resolvedOptions().hourCycle\n return cycle === 'h11' || cycle === 'h12' ? 12 : 24\n } catch {\n return 24\n }\n}\n\nexport type DateSegmentType = 'year' | 'month' | 'day'\n\nexport type DatePattern = ({ type: DateSegmentType } | { type: 'literal'; value: string })[]\n\n/** The order of day, month and year for `locale`, with the separators between them. */\nexport function datePattern(locale: string): DatePattern {\n let parts: Intl.DateTimeFormatPart[]\n try {\n parts = new Intl.DateTimeFormat(locale, {\n timeZone: 'UTC',\n calendar: 'gregory',\n numberingSystem: 'latn',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).formatToParts(Date.UTC(2026, 10, 22))\n } catch {\n return datePattern(DEFAULT_LOCALE)\n }\n const pattern: DatePattern = []\n for (const part of parts) {\n if (part.type === 'year' || part.type === 'month' || part.type === 'day')\n pattern.push({ type: part.type })\n else if (part.type === 'literal' && pattern.length > 0)\n pattern.push({ type: 'literal', value: part.value.replace(/[]/g, '') })\n }\n const last = pattern[pattern.length - 1]\n if (last?.type === 'literal' && last.value.trim() === '') pattern.pop()\n return pattern\n}\n\nfunction utcFormat(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n try {\n return new Intl.DateTimeFormat(locale, { timeZone: 'UTC', calendar: 'gregory', ...options })\n } catch {\n return new Intl.DateTimeFormat(DEFAULT_LOCALE, { timeZone: 'UTC', ...options })\n }\n}\n\nfunction utcMs(date: CalendarDate): number {\n return toDayNumber(date) * DAY_MS\n}\n\n/** \"October 2026\". */\nexport function formatMonthYear(locale: string, year: number, month: number): string {\n return utcFormat(locale, { year: 'numeric', month: 'long' }).format(\n utcMs({ year, month, day: 1 }),\n )\n}\n\n/** \"Thursday 15 October 2026\": a day's accessible name. */\nexport function formatFullDate(locale: string, date: CalendarDate): string {\n return utcFormat(locale, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n }).format(utcMs(date))\n}\n\n/** Seven weekday names starting at `firstDay`, short (\"Mon\") and long (\"Monday\"). */\nexport function weekdayNames(locale: string, firstDay: number): { short: string; long: string }[] {\n const short = utcFormat(locale, { weekday: 'short' })\n const long = utcFormat(locale, { weekday: 'long' })\n // 2026-11-01 is a Sunday.\n return Array.from({ length: 7 }, (_, index) => {\n const ms = utcMs({ year: 2026, month: 11, day: 1 + ((firstDay + index) % 7) })\n return { short: short.format(ms), long: long.format(ms) }\n })\n}\n\n/** The locale's AM and PM markers (\"am\", \"pm\" in en-AU). */\nexport function dayPeriodNames(locale: string): [string, string] {\n const format = utcFormat(locale, { hour: 'numeric', hourCycle: 'h12' })\n const read = (hour: number) =>\n format.formatToParts(Date.UTC(2026, 0, 1, hour)).find((part) => part.type === 'dayPeriod')\n ?.value ?? (hour < 12 ? 'AM' : 'PM')\n return [read(9), read(21)]\n}\n\n/** A short name for `timeZone` at instant `ms` (\"AEDT\", \"UTC\", \"GMT+10\"). */\nexport function timeZoneName(locale: string, timeZone: string, ms: number = Date.now()): string {\n try {\n return (\n new Intl.DateTimeFormat(locale, { timeZone, timeZoneName: 'short' })\n .formatToParts(ms)\n .find((part) => part.type === 'timeZoneName')?.value ?? timeZone\n )\n } catch {\n return timeZone\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Option filtering for type-to-search controls (Combobox). Not exported from the
|
|
2
|
+
* Option filtering for type-to-search controls (Combobox, CommandPalette). Not exported from the
|
|
3
|
+
* package.
|
|
3
4
|
*
|
|
4
5
|
* Matching is case-insensitive and diacritic-folded ("cote" finds "Côte d'Ivoire",
|
|
5
6
|
* "curacao" finds "Curaçao"). Results are ranked, and stable within a rank:
|
|
@@ -21,3 +22,23 @@ export declare function rankOption(option: FilterableOption, foldedQuery: string
|
|
|
21
22
|
* option in its original order.
|
|
22
23
|
*/
|
|
23
24
|
export declare function filterOptions<O extends FilterableOption>(options: readonly O[], query: string): O[];
|
|
25
|
+
export interface GroupableOption {
|
|
26
|
+
group?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface OptionSection<O> {
|
|
29
|
+
key: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
options: O[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Splits options into sections by `group`, in order of each group's first option (so a ranked
|
|
35
|
+
* list keeps its best group first). Options without a group form an unlabelled section.
|
|
36
|
+
*/
|
|
37
|
+
export declare function groupOptions<O extends GroupableOption>(options: readonly O[]): OptionSection<O>[];
|
|
38
|
+
/**
|
|
39
|
+
* Where `query` matches inside `label`, as `[start, end)` indices into the original label, for
|
|
40
|
+
* highlighting. Folds both sides like `filterOptions`, and prefers the match it ranked: the
|
|
41
|
+
* label's start, then the start of a word, then anywhere. `null` when the label doesn't contain
|
|
42
|
+
* the query (the option matched on a keyword or its description).
|
|
43
|
+
*/
|
|
44
|
+
export declare function matchRange(label: string, query: string): [number, number] | null;
|
|
@@ -22,7 +22,38 @@ function r(t, r) {
|
|
|
22
22
|
});
|
|
23
23
|
}), a.sort((e, t) => e.rank - t.rank || e.index - t.index), a.map((e) => e.option);
|
|
24
24
|
}
|
|
25
|
+
function i(e) {
|
|
26
|
+
let t = [], n = /* @__PURE__ */ new Map();
|
|
27
|
+
for (let r of e) {
|
|
28
|
+
let e = r.group === void 0 ? "" : `g:${r.group}`, i = n.get(e);
|
|
29
|
+
i || (i = {
|
|
30
|
+
key: e,
|
|
31
|
+
label: r.group,
|
|
32
|
+
options: []
|
|
33
|
+
}, n.set(e, i), t.push(i)), i.options.push(r);
|
|
34
|
+
}
|
|
35
|
+
return t;
|
|
36
|
+
}
|
|
37
|
+
function a(t, n) {
|
|
38
|
+
let r = e(n);
|
|
39
|
+
if (r === "") return null;
|
|
40
|
+
let i = "", a = [], o = [], s = 0;
|
|
41
|
+
for (let e of t) {
|
|
42
|
+
let t = s + e.length, n = /\s/.test(e) ? i === "" || i.endsWith(" ") ? "" : " " : e.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
|
|
43
|
+
n === "" && !/\s/.test(e) && o.length > 0 && (o[o.length - 1] = t), a.push(...Array(n.length).fill(s)), o.push(...Array(n.length).fill(t)), i += n, s = t;
|
|
44
|
+
}
|
|
45
|
+
let c = -1;
|
|
46
|
+
if (i.startsWith(r)) c = 0;
|
|
47
|
+
else {
|
|
48
|
+
let e = /[\s\-–—'’/().,]/;
|
|
49
|
+
for (let t = i.indexOf(r); t !== -1; t = i.indexOf(r, t + 1)) if (c === -1 && (c = t), e.test(i.charAt(t - 1))) {
|
|
50
|
+
c = t;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return c === -1 ? null : [a[c] ?? 0, o[c + r.length - 1] ?? t.length];
|
|
55
|
+
}
|
|
25
56
|
//#endregion
|
|
26
|
-
export { r as filterOptions, e as foldText, n as rankOption };
|
|
57
|
+
export { r as filterOptions, e as foldText, i as groupOptions, a as matchRange, n as rankOption };
|
|
27
58
|
|
|
28
59
|
//# sourceMappingURL=filterOptions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterOptions.js","names":["foldText","text","words","folded","rankOption","label","option","keywords","foldedQuery","word","keyword","filterOptions","query","options","ranked","rank","a","b","entry"],"sources":["../../../../src/components/inputs/internal/filterOptions.ts"],"sourcesContent":["/**\n * Option filtering for type-to-search controls (Combobox). Not exported from the package.\n *\n * Matching is case-insensitive and diacritic-folded (\"cote\" finds \"Côte d'Ivoire\",\n * \"curacao\" finds \"Curaçao\"). Results are ranked, and stable within a rank:\n * 0 — exact: the label or a keyword equals the query (\"USA\" → United States)\n * 1 — prefix: the label, a word in it, or a keyword starts with the query\n * 2 — substring: the label, a keyword or the description contains the query\n */\n\nexport interface FilterableOption {\n label: string\n keywords?: readonly string[]\n description?: string\n}\n\n/** Lower-case, strip accents, collapse whitespace. */\nexport function foldText(text: string): string {\n return text\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nconst EXACT = 0\nconst PREFIX = 1\nconst SUBSTRING = 2\nconst NO_MATCH = 3\n\nfunction words(folded: string): string[] {\n return folded.split(/[\\s\\-–—'’/().,]+/).filter(Boolean)\n}\n\n/** Rank of one option for an already-folded, non-empty query (lower is better; 3 = no match). */\nexport function rankOption(option: FilterableOption, foldedQuery: string): number {\n const label = foldText(option.label)\n const keywords = (option.keywords ?? []).map(foldText)\n if (label === foldedQuery || keywords.includes(foldedQuery)) return EXACT\n if (\n label.startsWith(foldedQuery) ||\n words(label).some((word) => word.startsWith(foldedQuery)) ||\n keywords.some((keyword) => keyword.startsWith(foldedQuery))\n ) {\n return PREFIX\n }\n if (\n label.includes(foldedQuery) ||\n keywords.some((keyword) => keyword.includes(foldedQuery)) ||\n (option.description !== undefined && foldText(option.description).includes(foldedQuery))\n ) {\n return SUBSTRING\n }\n return NO_MATCH\n}\n\n/**\n * The options matching `query`, best first. An empty (or whitespace) query returns every\n * option in its original order.\n */\nexport function filterOptions<O extends FilterableOption>(\n options: readonly O[],\n query: string,\n): O[] {\n const folded = foldText(query)\n if (folded === '') return [...options]\n const ranked: { option: O; rank: number; index: number }[] = []\n options.forEach((option, index) => {\n const rank = rankOption(option, folded)\n if (rank < NO_MATCH) ranked.push({ option, rank, index })\n })\n ranked.sort((a, b) => a.rank - b.rank || a.index - b.index)\n return ranked.map((entry) => entry.option)\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"filterOptions.js","names":["foldText","text","words","folded","rankOption","label","option","keywords","foldedQuery","word","keyword","filterOptions","query","options","ranked","rank","a","b","entry","groupOptions","sections","byKey","key","section","matchRange","starts","ends","index","char","next","piece","start","boundary","at"],"sources":["../../../../src/components/inputs/internal/filterOptions.ts"],"sourcesContent":["/**\n * Option filtering for type-to-search controls (Combobox, CommandPalette). Not exported from the\n * package.\n *\n * Matching is case-insensitive and diacritic-folded (\"cote\" finds \"Côte d'Ivoire\",\n * \"curacao\" finds \"Curaçao\"). Results are ranked, and stable within a rank:\n * 0 — exact: the label or a keyword equals the query (\"USA\" → United States)\n * 1 — prefix: the label, a word in it, or a keyword starts with the query\n * 2 — substring: the label, a keyword or the description contains the query\n */\n\nexport interface FilterableOption {\n label: string\n keywords?: readonly string[]\n description?: string\n}\n\n/** Lower-case, strip accents, collapse whitespace. */\nexport function foldText(text: string): string {\n return text\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLowerCase()\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nconst EXACT = 0\nconst PREFIX = 1\nconst SUBSTRING = 2\nconst NO_MATCH = 3\n\nfunction words(folded: string): string[] {\n return folded.split(/[\\s\\-–—'’/().,]+/).filter(Boolean)\n}\n\n/** Rank of one option for an already-folded, non-empty query (lower is better; 3 = no match). */\nexport function rankOption(option: FilterableOption, foldedQuery: string): number {\n const label = foldText(option.label)\n const keywords = (option.keywords ?? []).map(foldText)\n if (label === foldedQuery || keywords.includes(foldedQuery)) return EXACT\n if (\n label.startsWith(foldedQuery) ||\n words(label).some((word) => word.startsWith(foldedQuery)) ||\n keywords.some((keyword) => keyword.startsWith(foldedQuery))\n ) {\n return PREFIX\n }\n if (\n label.includes(foldedQuery) ||\n keywords.some((keyword) => keyword.includes(foldedQuery)) ||\n (option.description !== undefined && foldText(option.description).includes(foldedQuery))\n ) {\n return SUBSTRING\n }\n return NO_MATCH\n}\n\n/**\n * The options matching `query`, best first. An empty (or whitespace) query returns every\n * option in its original order.\n */\nexport function filterOptions<O extends FilterableOption>(\n options: readonly O[],\n query: string,\n): O[] {\n const folded = foldText(query)\n if (folded === '') return [...options]\n const ranked: { option: O; rank: number; index: number }[] = []\n options.forEach((option, index) => {\n const rank = rankOption(option, folded)\n if (rank < NO_MATCH) ranked.push({ option, rank, index })\n })\n ranked.sort((a, b) => a.rank - b.rank || a.index - b.index)\n return ranked.map((entry) => entry.option)\n}\n\nexport interface GroupableOption {\n group?: string\n}\n\nexport interface OptionSection<O> {\n key: string\n label?: string\n options: O[]\n}\n\n/**\n * Splits options into sections by `group`, in order of each group's first option (so a ranked\n * list keeps its best group first). Options without a group form an unlabelled section.\n */\nexport function groupOptions<O extends GroupableOption>(options: readonly O[]): OptionSection<O>[] {\n const sections: OptionSection<O>[] = []\n const byKey = new Map<string, OptionSection<O>>()\n for (const option of options) {\n const key = option.group === undefined ? '' : `g:${option.group}`\n let section = byKey.get(key)\n if (!section) {\n section = { key, label: option.group, options: [] }\n byKey.set(key, section)\n sections.push(section)\n }\n section.options.push(option)\n }\n return sections\n}\n\n/**\n * Where `query` matches inside `label`, as `[start, end)` indices into the original label, for\n * highlighting. Folds both sides like `filterOptions`, and prefers the match it ranked: the\n * label's start, then the start of a word, then anywhere. `null` when the label doesn't contain\n * the query (the option matched on a keyword or its description).\n */\nexport function matchRange(label: string, query: string): [number, number] | null {\n const folded = foldText(query)\n if (folded === '') return null\n // Fold the label one character at a time, remembering which slice of it each folded\n // character came from. A character that folds away (a combining accent) joins the one before.\n let text = ''\n const starts: number[] = []\n const ends: number[] = []\n let index = 0\n for (const char of label) {\n const next = index + char.length\n const piece = /\\s/.test(char)\n ? text === '' || text.endsWith(' ')\n ? ''\n : ' '\n : char\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLowerCase()\n if (piece === '' && !/\\s/.test(char) && ends.length > 0) ends[ends.length - 1] = next\n starts.push(...Array<number>(piece.length).fill(index))\n ends.push(...Array<number>(piece.length).fill(next))\n text += piece\n index = next\n }\n let start = -1\n if (text.startsWith(folded)) start = 0\n else {\n const boundary = /[\\s\\-–—'’/().,]/\n for (let at = text.indexOf(folded); at !== -1; at = text.indexOf(folded, at + 1)) {\n if (start === -1) start = at\n if (boundary.test(text.charAt(at - 1))) {\n start = at\n break\n }\n }\n }\n if (start === -1) return null\n return [starts[start] ?? 0, ends[start + folded.length - 1] ?? label.length]\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { FocusEvent, PointerEvent, RefObject } from 'react';
|
|
2
|
+
import type { CalendarLabels } from '../Calendar/index.js';
|
|
3
|
+
import { type SegmentLabels } from './DateSegments.js';
|
|
4
|
+
/**
|
|
5
|
+
* Every word the date and time controls say, for another language or wording. Each control
|
|
6
|
+
* reads the ones it uses.
|
|
7
|
+
*/
|
|
8
|
+
export interface DateTimeLabels extends SegmentLabels, CalendarLabels {
|
|
9
|
+
/** The calendar button and the panel it opens. Default `'Choose date'`. */
|
|
10
|
+
openCalendar: string;
|
|
11
|
+
/** The clear button. Default `'Clear'`. */
|
|
12
|
+
clear: string;
|
|
13
|
+
/** The time inside a date-time calendar. Default `'Time'`. */
|
|
14
|
+
time: string;
|
|
15
|
+
/** The start's time inside a range calendar. Default `'Start time'`. */
|
|
16
|
+
startTime: string;
|
|
17
|
+
/** The end's time inside a range calendar. Default `'End time'`. */
|
|
18
|
+
endTime: string;
|
|
19
|
+
/** The list of preset ranges. Default `'Presets'`. */
|
|
20
|
+
presets: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULT_DATE_TIME_LABELS: DateTimeLabels;
|
|
23
|
+
/** Focus the first empty part (or the first part) inside `root`. */
|
|
24
|
+
export declare function focusSegment(root: HTMLElement | null, which?: 'empty' | 'first'): void;
|
|
25
|
+
/**
|
|
26
|
+
* Clicking the box's padding or a separator focuses a part, like one native control. Events
|
|
27
|
+
* from the portalled calendar bubble here through React, so only the box's own DOM counts.
|
|
28
|
+
*/
|
|
29
|
+
export declare function handleBoxPointerDown(event: PointerEvent<HTMLElement>): void;
|
|
30
|
+
/** Whether focus is leaving the whole control: the box and, when open, its calendar panel. */
|
|
31
|
+
export declare function isLeaving(event: FocusEvent<HTMLElement>, ...parts: RefObject<HTMLElement | null>[]): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DEFAULT_SEGMENT_LABELS as e } from "./DateSegments.js";
|
|
2
|
+
//#region src/components/inputs/internal/picker.tsx
|
|
3
|
+
var t = {
|
|
4
|
+
...e,
|
|
5
|
+
previousMonth: "Previous month",
|
|
6
|
+
nextMonth: "Next month",
|
|
7
|
+
openCalendar: "Choose date",
|
|
8
|
+
clear: "Clear",
|
|
9
|
+
time: "Time",
|
|
10
|
+
startTime: "Start time",
|
|
11
|
+
endTime: "End time",
|
|
12
|
+
presets: "Presets"
|
|
13
|
+
};
|
|
14
|
+
function n(e, t = "empty") {
|
|
15
|
+
let n = Array.from(e?.querySelectorAll("[data-segment]") ?? []);
|
|
16
|
+
((t === "empty" ? n.find((e) => e.dataset.placeholder !== void 0) ?? null : null) ?? n[0])?.focus();
|
|
17
|
+
}
|
|
18
|
+
function r(e) {
|
|
19
|
+
let t = e.currentTarget, r = e.target;
|
|
20
|
+
t.contains(r) && (r.closest("[data-segment], button, a, input") || t.querySelector("[data-segment]")?.getAttribute("aria-disabled") !== "true" && (e.preventDefault(), n(t)));
|
|
21
|
+
}
|
|
22
|
+
function i(e, ...t) {
|
|
23
|
+
let n = e.relatedTarget;
|
|
24
|
+
return n instanceof Node ? !t.some((e) => e.current?.contains(n)) : !0;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { t as DEFAULT_DATE_TIME_LABELS, n as focusSegment, r as handleBoxPointerDown, i as isLeaving };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.js","names":["DEFAULT_DATE_TIME_LABELS","DEFAULT_SEGMENT_LABELS","focusSegment","segments","root","which","s","handleBoxPointerDown","event","target","isLeaving","parts","next","part"],"sources":["../../../../src/components/inputs/internal/picker.tsx"],"sourcesContent":["import type { FocusEvent, PointerEvent, RefObject } from 'react'\nimport type { CalendarLabels } from '#components/inputs/Calendar'\nimport { DEFAULT_SEGMENT_LABELS, type SegmentLabels } from './DateSegments'\n\n/**\n * Every word the date and time controls say, for another language or wording. Each control\n * reads the ones it uses.\n */\nexport interface DateTimeLabels extends SegmentLabels, CalendarLabels {\n /** The calendar button and the panel it opens. Default `'Choose date'`. */\n openCalendar: string\n /** The clear button. Default `'Clear'`. */\n clear: string\n /** The time inside a date-time calendar. Default `'Time'`. */\n time: string\n /** The start's time inside a range calendar. Default `'Start time'`. */\n startTime: string\n /** The end's time inside a range calendar. Default `'End time'`. */\n endTime: string\n /** The list of preset ranges. Default `'Presets'`. */\n presets: string\n}\n\nexport const DEFAULT_DATE_TIME_LABELS: DateTimeLabels = {\n ...DEFAULT_SEGMENT_LABELS,\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n openCalendar: 'Choose date',\n clear: 'Clear',\n time: 'Time',\n startTime: 'Start time',\n endTime: 'End time',\n presets: 'Presets',\n}\n\n/** Focus the first empty part (or the first part) inside `root`. */\nexport function focusSegment(root: HTMLElement | null, which: 'empty' | 'first' = 'empty') {\n const segments = Array.from(root?.querySelectorAll<HTMLElement>('[data-segment]') ?? [])\n const target =\n which === 'empty' ? (segments.find((s) => s.dataset.placeholder !== undefined) ?? null) : null\n ;(target ?? segments[0])?.focus()\n}\n\n/**\n * Clicking the box's padding or a separator focuses a part, like one native control. Events\n * from the portalled calendar bubble here through React, so only the box's own DOM counts.\n */\nexport function handleBoxPointerDown(event: PointerEvent<HTMLElement>) {\n const root = event.currentTarget\n const target = event.target as HTMLElement\n if (!root.contains(target)) return\n if (target.closest('[data-segment], button, a, input')) return\n if (root.querySelector('[data-segment]')?.getAttribute('aria-disabled') === 'true') return\n event.preventDefault()\n focusSegment(root)\n}\n\n/** Whether focus is leaving the whole control: the box and, when open, its calendar panel. */\nexport function isLeaving(\n event: FocusEvent<HTMLElement>,\n ...parts: RefObject<HTMLElement | null>[]\n): boolean {\n const next = event.relatedTarget\n if (!(next instanceof Node)) return true\n return !parts.some((part) => part.current?.contains(next))\n}\n"],"mappings":";;AAuBA,IAAaA,IAA2C;CACtD,GAAGC;CACH,eAAe;CACf,WAAW;CACX,cAAc;CACd,OAAO;CACP,MAAM;CACN,WAAW;CACX,SAAS;CACT,SAAS;AACX;AAGA,SAAgBC,EAAa,GAA0B,IAA2B,SAAS;CACzF,IAAMC,IAAW,MAAM,KAAKC,GAAM,iBAA8B,gBAAgB,KAAK,CAAC,CAAC;CAGtF,EADCC,MAAU,UAAWF,EAAS,MAAM,MAAMG,EAAE,QAAQ,gBAAgB,KAAA,CAAS,KAAK,OAAQ,SAChFH,EAAS,GAAA,EAAK,MAAM;AAClC;AAMA,SAAgBI,EAAqB,GAAkC;CACrE,IAAMH,IAAOI,EAAM,eACbC,IAASD,EAAM;CACrB,AAAKJ,EAAK,SAASK,CAAM,MACrBA,EAAO,QAAQ,kCAAkC,KACjDL,EAAK,cAAc,gBAAgB,CAAC,EAAE,aAAa,eAAe,MAAM,WAC5EI,EAAM,eAAe,GACrBN,EAAaE,CAAI;AACnB;AAGA,SAAgBM,EACd,GACA,GAAGC,GACM;CACT,IAAMC,IAAOJ,EAAM;CAEnB,OADMI,aAAgB,OACf,CAACD,EAAM,MAAM,MAASE,EAAK,SAAS,SAASD,CAAI,CAAC,IADrB;AAEtC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/components/inputs/internal/picker.module.css
|
|
2
|
+
var e = "kiln-picker__root", t = "kiln-picker__trailing", n = "kiln-picker__zone", r = "kiln-picker__button", i = "kiln-picker__popover", a = "kiln-picker__panel", o = "kiln-picker__timeRow", s = "kiln-picker__timeLabel", c = {
|
|
3
|
+
root: e,
|
|
4
|
+
trailing: t,
|
|
5
|
+
zone: n,
|
|
6
|
+
button: r,
|
|
7
|
+
popover: i,
|
|
8
|
+
panel: a,
|
|
9
|
+
timeRow: o,
|
|
10
|
+
timeLabel: s
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { r as button, c as default, a as panel, i as popover, e as root, s as timeLabel, o as timeRow, t as trailing, n as zone };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=picker.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.module.js","names":["root","trailing","zone","button","popover","panel","timeRow","timeLabel","picker_module_default"],"sources":["../../../../src/components/inputs/internal/picker.module.css"],"sourcesContent":["/*\n * The field box of DateInput, TimeInput and DateTimeInput (the border and states come from\n * control.module.css): the segments, then the zone, the clear button and the calendar button.\n * Also the panel their calendar opens in.\n */\n.root {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n inline-size: 100%;\n padding-inline: var(--_px);\n cursor: text;\n}\n.root:focus-within {\n outline: 2px solid var(--color-focus);\n outline-offset: 2px;\n}\n.root[data-disabled] {\n cursor: not-allowed;\n}\n\n.trailing {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--space-1);\n margin-inline-end: calc(var(--space-1) * -1);\n color: var(--color-ink-muted);\n}\n.root[data-disabled] .trailing {\n color: var(--color-ink-subtle);\n}\n\n/* The time zone after a date-time (\"AEDT\"), as quiet as an adornment. */\n.zone {\n color: var(--color-ink-subtle);\n font-size: 0.875em;\n white-space: nowrap;\n user-select: none;\n}\n\n.button {\n position: relative;\n display: inline-grid;\n place-items: center;\n inline-size: 1.75em;\n block-size: 1.75em;\n padding: 0;\n border: 0;\n border-radius: var(--radius-chip);\n background: transparent;\n color: inherit;\n font-size: inherit;\n cursor: pointer;\n}\n.button > svg {\n inline-size: 1.15em;\n block-size: 1.15em;\n}\n@media (hover: hover) {\n .button:hover:not(:disabled) {\n background: var(--color-surface-sunken);\n color: var(--color-ink);\n }\n}\n.button:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 1px;\n}\n.button:disabled {\n cursor: not-allowed;\n}\n.button[data-state='open'] {\n background: var(--color-surface-sunken);\n color: var(--color-ink);\n}\n\n/* The calendar panel: wide enough for its grid (two months for a range), never off screen. */\n.popover {\n max-inline-size: min(\n calc(100vw - 2 * var(--space-4)),\n var(--radix-popover-content-available-width, 100vw)\n );\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n}\n\n.timeRow {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-3);\n padding-block-start: var(--space-3);\n border-block-start: var(--border-width) solid var(--color-line);\n}\n.timeLabel {\n min-inline-size: 5em;\n color: var(--color-ink-muted);\n font-size: var(--text-sm);\n font-weight: var(--label-weight);\n}\n.timeRow > :last-child {\n flex: 1 1 10em;\n inline-size: auto;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/components/inputs/internal/segments.module.css
|
|
2
|
+
var e = "kiln-segments__segments", t = "kiln-segments__segment", n = "kiln-segments__literal", r = {
|
|
3
|
+
segments: e,
|
|
4
|
+
segment: t,
|
|
5
|
+
literal: n
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
export { r as default, n as literal, t as segment, e as segments };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=segments.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.module.js","names":["segments","segment","literal","segments_module_default"],"sources":["../../../../src/components/inputs/internal/segments.module.css"],"sourcesContent":["/*\n * The parts of a date or time (\"15 / 10 / 2026\", \"2:30 pm\") inside a field box. Figures are\n * tabular in the theme's numeric face, so a part never changes width as it's typed.\n *\n * Component tokens:\n * --date-segment-focus-bg default var(--color-selection)\n * --date-segment-focus-ink default var(--color-ink)\n */\n.segments {\n display: inline-flex;\n flex: 1;\n align-items: center;\n min-inline-size: 0;\n overflow: hidden;\n font-family: var(--font-numeric);\n font-stretch: var(--numeric-stretch);\n font-variant-numeric: tabular-nums lining-nums;\n white-space: nowrap;\n}\n\n.segment {\n box-sizing: content-box;\n padding-inline: 0.125em;\n border-radius: var(--radius-field);\n caret-color: transparent;\n text-align: end;\n outline: none;\n cursor: text;\n}\n.segment[data-segment='dayPeriod'] {\n text-align: start;\n}\n.segment[data-placeholder] {\n color: var(--color-ink-subtle);\n}\n.segment:focus {\n background-color: var(--date-segment-focus-bg, var(--color-selection));\n color: var(--date-segment-focus-ink, var(--color-ink));\n}\n.segment[aria-disabled='true'] {\n cursor: not-allowed;\n}\n\n.literal {\n color: var(--color-ink-subtle);\n white-space: pre;\n user-select: none;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
export interface CollapseProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/** Whether the content shows. Changing it animates the height. */
|
|
4
|
+
open: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Keep the content in the page while it's closed (hidden, so it's out of the tab order and the
|
|
7
|
+
* accessibility tree). `false` unmounts it once the close finishes, so its state resets. Default
|
|
8
|
+
* `true`.
|
|
9
|
+
*/
|
|
10
|
+
keepMounted?: boolean;
|
|
11
|
+
/** Runs when an open or close finishes, with the state it finished in. */
|
|
12
|
+
onOpenChangeComplete?: (open: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Animates its content open and closed by height. No trigger, no heading, nothing else.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* `Collapse` is the bare show-and-hide that `Accordion` and `Collapsible` give you with a button
|
|
19
|
+
* attached. Use it when something else decides whether the content shows: a switch that reveals
|
|
20
|
+
* advanced options, a filter bar, a group of nav links. It grows from nothing to the content's
|
|
21
|
+
* natural height and back, with the theme's motion tokens, and changes instantly when the reader
|
|
22
|
+
* asks for reduced motion.
|
|
23
|
+
*
|
|
24
|
+
* Closed content is `hidden`, so it's out of the tab order and away from screen readers. Wire the
|
|
25
|
+
* control that opens it with `aria-expanded` and `aria-controls` pointing at the `Collapse`'s
|
|
26
|
+
* `id`, or use {@link Collapsible | Collapsible}, which does that for you.
|
|
27
|
+
*
|
|
28
|
+
* Put padding on the content inside it, not on the `Collapse` itself, so nothing shows while it's
|
|
29
|
+
* closed.
|
|
30
|
+
*
|
|
31
|
+
* @privateRemarks
|
|
32
|
+
* The shared height animation lives in `useHeightMotion` (also used by ShowMore and
|
|
33
|
+
* NavLinksGroup): it measures from and to in px and transitions `block-size` on
|
|
34
|
+
* `data-animating`, so it works in every browser without `interpolate-size`. Accordion keeps
|
|
35
|
+
* Radix's own measured keyframes for now; moving it would change its markup.
|
|
36
|
+
*
|
|
37
|
+
* <Collapse open={advanced} id="advanced-options">…</Collapse>
|
|
38
|
+
*/
|
|
39
|
+
export declare const Collapse: import("react").ForwardRefExoticComponent<CollapseProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cx as e } from "../../../utils/cx.js";
|
|
2
|
+
import { useMergedRefs as t } from "../../inputs/internal/refs.js";
|
|
3
|
+
import { useHeightMotion as n } from "./useHeightMotion.js";
|
|
4
|
+
import r from "./Collapse.module.js";
|
|
5
|
+
import { forwardRef as i, useRef as a, useState as o } from "react";
|
|
6
|
+
import { jsx as s } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/layout/Collapse/Collapse.tsx
|
|
8
|
+
var c = i(function({ open: i, keepMounted: c = !0, onOpenChangeComplete: l, className: u, children: d, ...f }, p) {
|
|
9
|
+
let m = a(null), [h, g] = o(i);
|
|
10
|
+
return i && !h && g(!0), n(m, i, (e) => {
|
|
11
|
+
e || g(!1), l?.(e);
|
|
12
|
+
}), /* @__PURE__ */ s("div", {
|
|
13
|
+
ref: t(p, m),
|
|
14
|
+
className: e(r.collapse, u),
|
|
15
|
+
"data-state": i ? "open" : "closed",
|
|
16
|
+
hidden: !i && !h,
|
|
17
|
+
...f,
|
|
18
|
+
children: h || c ? d : null
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
//#endregion
|
|
22
|
+
export { c as Collapse };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=Collapse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collapse.js","names":["styles","Collapse_module_default","Collapse","forwardRef","rest","element","useRef","present","setPresent","useState","open","useHeightMotion","settledOpen","onOpenChangeComplete","useMergedRefs","ref","cx","className","keepMounted","children"],"sources":["../../../../src/components/layout/Collapse/Collapse.tsx"],"sourcesContent":["import { forwardRef, useRef, useState, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport { useMergedRefs } from '#components/inputs/internal/refs'\nimport { useHeightMotion } from './useHeightMotion'\nimport styles from './Collapse.module.css'\n\nexport interface CollapseProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the content shows. Changing it animates the height. */\n open: boolean\n /**\n * Keep the content in the page while it's closed (hidden, so it's out of the tab order and the\n * accessibility tree). `false` unmounts it once the close finishes, so its state resets. Default\n * `true`.\n */\n keepMounted?: boolean\n /** Runs when an open or close finishes, with the state it finished in. */\n onOpenChangeComplete?: (open: boolean) => void\n}\n\n/**\n * Animates its content open and closed by height. No trigger, no heading, nothing else.\n *\n * @remarks\n * `Collapse` is the bare show-and-hide that `Accordion` and `Collapsible` give you with a button\n * attached. Use it when something else decides whether the content shows: a switch that reveals\n * advanced options, a filter bar, a group of nav links. It grows from nothing to the content's\n * natural height and back, with the theme's motion tokens, and changes instantly when the reader\n * asks for reduced motion.\n *\n * Closed content is `hidden`, so it's out of the tab order and away from screen readers. Wire the\n * control that opens it with `aria-expanded` and `aria-controls` pointing at the `Collapse`'s\n * `id`, or use {@link Collapsible | Collapsible}, which does that for you.\n *\n * Put padding on the content inside it, not on the `Collapse` itself, so nothing shows while it's\n * closed.\n *\n * @privateRemarks\n * The shared height animation lives in `useHeightMotion` (also used by ShowMore and\n * NavLinksGroup): it measures from and to in px and transitions `block-size` on\n * `data-animating`, so it works in every browser without `interpolate-size`. Accordion keeps\n * Radix's own measured keyframes for now; moving it would change its markup.\n *\n * <Collapse open={advanced} id=\"advanced-options\">…</Collapse>\n */\nexport const Collapse = forwardRef<HTMLDivElement, CollapseProps>(function Collapse(\n { open, keepMounted = true, onOpenChangeComplete, className, children, ...rest },\n ref,\n) {\n const element = useRef<HTMLDivElement>(null)\n // Whether the content is on screen: true while open and while a close is still animating.\n const [present, setPresent] = useState(open)\n if (open && !present) setPresent(true)\n\n useHeightMotion(element, open, (settledOpen) => {\n if (!settledOpen) setPresent(false)\n onOpenChangeComplete?.(settledOpen)\n })\n\n return (\n <div\n ref={useMergedRefs(ref, element)}\n className={cx(styles.collapse, className)}\n data-state={open ? 'open' : 'closed'}\n hidden={!open && !present}\n {...rest}\n >\n {present || keepMounted ? children : null}\n </div>\n )\n})\n"],"mappings":";;;;;;;AA4CA,IAAaE,IAAWC,EAA0C,SAChE,EAAE,SAAM,iBAAc,IAAM,yBAAsB,cAAW,aAAU,GAAGC,KAC1E,GACA;CACA,IAAMC,IAAUC,EAAuB,IAAI,GAErC,CAACC,GAASC,KAAcC,EAASC,CAAI;CAQ3C,OAPIA,KAAQ,CAACH,KAASC,EAAW,EAAI,GAErCG,EAAgBN,GAASK,IAAO,MAAgB;EAE9C,AADKE,KAAaJ,EAAW,EAAK,GAClCK,IAAuBD,CAAW;CACpC,CAAC,GAGC,kBAAC,OAAD;EACE,KAAKE,EAAcC,GAAKV,CAAO;EAC/B,WAAWW,EAAGhB,EAAO,UAAUiB,CAAS;EACxC,cAAYP,IAAO,SAAS;EAC5B,QAAQ,CAACA,KAAQ,CAACH;EAClB,GAAIH;EAEH,UAAAG,KAAWW,IAAcC,IAAW;CAClC,CAAA;AAET,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Collapse.module.js","names":["collapse","Collapse_module_default"],"sources":["../../../../src/components/layout/Collapse/Collapse.module.css"],"sourcesContent":["/*\n * Component tokens: none. The timing is the theme's: --dur-3 and --ease-out, which collapse\n * under reduced motion.\n *\n * Closed, the height is 0; open, it's the content's. `useHeightMotion` sets `data-animating`\n * and an inline block-size while it moves between the two, so the transition runs only then and\n * an open Collapse never clips focus rings or popovers.\n */\n.collapse {\n min-inline-size: 0;\n}\n\n.collapse[data-state='closed'] {\n block-size: 0;\n overflow: hidden;\n}\n\n.collapse[data-animating] {\n overflow: hidden;\n transition: block-size var(--dur-3) var(--ease-out);\n}\n.collapse[data-animating][data-state='closed'] {\n transition-duration: var(--dur-2);\n}\n\n.collapse[hidden] {\n display: none;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Animates an element's height whenever `key` changes, from the height it had before the change
|
|
4
|
+
* to its natural height after it. Shared by `Collapse`, `ShowMore` and `NavLinksGroup`, so every
|
|
5
|
+
* open and close in Kiln moves the same way.
|
|
6
|
+
*
|
|
7
|
+
* The element's CSS decides the natural height in each state (`block-size: 0` when closed, a
|
|
8
|
+
* `max-block-size` clamp when collapsed) and the transition itself, through `data-animating`:
|
|
9
|
+
* `.el[data-animating] { transition: block-size var(--dur-3) var(--ease-out) }`. While it's set,
|
|
10
|
+
* the CSS should lift any clamp, since the inline `block-size` does the work. The theme's motion
|
|
11
|
+
* tokens set the timing, and under reduced motion they collapse, so the change is instant.
|
|
12
|
+
*
|
|
13
|
+
* `onSettled` runs once the height reaches its new value (at once when nothing moves), with the
|
|
14
|
+
* key it settled on. A change during a transition starts from wherever the height is.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useHeightMotion<K>(ref: RefObject<HTMLElement | null>, key: K, onSettled?: (key: K) => void): void;
|