@plastic-js/tsumiki 0.1.18 → 0.1.19

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.
@@ -0,0 +1,458 @@
1
+ import Icon from "../Icon.js";
2
+ import { makeWheel } from "./wheel.js";
3
+ import { Fragment, insert, jsx, mergeProps, setProp, template } from "@plastic-js/plastic/jsx-runtime";
4
+ import { css } from "@emotion/css";
5
+ import { createEffect, createSignal, splitProps } from "@plastic-js/plastic";
6
+ //#region src/components/DatePickerMobile/index.jsx
7
+ var _tmpl6 = template("<button type=\"button\"></button>");
8
+ var _tmpl5 = template("<div><div role=\"presentation\" aria-hidden=\"true\"></div><div role=\"dialog\" aria-label=\"Date picker\"><div><button type=\"button\">Cancel</button><span>Select Date</span><button type=\"button\">Done</button></div><div></div><div></div><div></div><!></div></div>");
9
+ var _tmpl4 = template("<span></span>");
10
+ var _tmpl3 = template("<button type=\"button\"><!><span></span></button>");
11
+ var _tmpl2 = template("<div></div>");
12
+ var _tmpl = template("<div><div><span>Year</span><div><div></div><div></div></div></div><div><span>Month</span><div><div></div><div></div></div></div><div><span>Day</span><div><div></div><div></div></div></div></div>");
13
+ var MONTH_NAMES_SHORT = [
14
+ "Jan",
15
+ "Feb",
16
+ "Mar",
17
+ "Apr",
18
+ "May",
19
+ "Jun",
20
+ "Jul",
21
+ "Aug",
22
+ "Sep",
23
+ "Oct",
24
+ "Nov",
25
+ "Dec"
26
+ ];
27
+ var daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
28
+ var YEARS = Array.from({ length: 200 }, (_, i) => 1900 + i);
29
+ var MONTHS = Array.from({ length: 12 }, (_, i) => i);
30
+ var getDays = (year, month) => {
31
+ const count = daysInMonth(year, month);
32
+ return Array.from({ length: count }, (_, i) => i + 1);
33
+ };
34
+ var toDate = (year, month, day) => new Date(year, month, day);
35
+ var formatDateLabel = (date) => {
36
+ if (!date) return "";
37
+ return `${MONTH_NAMES_SHORT[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
38
+ };
39
+ var calendarSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"/><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/></svg>";
40
+ var triggerWrapperClass = css({
41
+ position: "relative",
42
+ width: "100%",
43
+ background: "none",
44
+ border: "none",
45
+ padding: 0,
46
+ font: "inherit",
47
+ cursor: "pointer",
48
+ color: "inherit",
49
+ outline: "none",
50
+ borderRadius: "10px",
51
+ "&:focus-visible": { boxShadow: "0 0 0 2px var(--accent)" }
52
+ });
53
+ var triggerClass = css({
54
+ width: "100%",
55
+ height: "42px",
56
+ padding: "0 36px 0 14px",
57
+ background: "rgba(255,255,255,0.06)",
58
+ border: "1px solid var(--border)",
59
+ borderRadius: "10px",
60
+ color: "var(--ink)",
61
+ fontSize: "16px",
62
+ fontFamily: "inherit",
63
+ outline: "none",
64
+ boxSizing: "border-box",
65
+ display: "flex",
66
+ alignItems: "center",
67
+ cursor: "pointer"
68
+ });
69
+ var triggerPlaceholderClass = css({ color: "var(--muted)" });
70
+ var triggerValueClass = css({ color: "var(--ink)" });
71
+ var calendarIconClass = css({
72
+ position: "absolute",
73
+ right: "10px",
74
+ top: "50%",
75
+ transform: "translateY(-50%)",
76
+ width: "18px",
77
+ height: "18px",
78
+ color: "var(--muted)",
79
+ pointerEvents: "none"
80
+ });
81
+ var overlayClass = css({
82
+ position: "fixed",
83
+ inset: 0,
84
+ zIndex: 1e3,
85
+ display: "flex",
86
+ flexDirection: "column",
87
+ justifyContent: "flex-end",
88
+ pointerEvents: "none"
89
+ });
90
+ var backdropClass = css({
91
+ position: "absolute",
92
+ inset: 0,
93
+ background: "rgba(0,0,0,0.5)",
94
+ opacity: 0,
95
+ transition: "opacity 240ms ease"
96
+ });
97
+ var sheetClass = css({
98
+ position: "relative",
99
+ width: "100%",
100
+ display: "flex",
101
+ flexDirection: "column",
102
+ background: "var(--surface)",
103
+ borderTop: "1px solid var(--border)",
104
+ borderRadius: "18px 18px 0 0",
105
+ boxShadow: "0 -8px 32px rgba(0,0,0,0.4)",
106
+ paddingBottom: "env(safe-area-inset-bottom, 0px)",
107
+ transform: "translateY(100%)",
108
+ transition: "transform 280ms cubic-bezier(0.32, 0.72, 0, 1)"
109
+ });
110
+ var openClass = css({
111
+ pointerEvents: "auto",
112
+ [`& .${backdropClass}`]: { opacity: 1 },
113
+ [`& .${sheetClass}`]: { transform: "translateY(0)" }
114
+ });
115
+ var toolbarClass = css({
116
+ display: "flex",
117
+ justifyContent: "space-between",
118
+ alignItems: "center",
119
+ padding: "12px 16px",
120
+ borderBottom: "1px solid var(--border)",
121
+ flexShrink: 0
122
+ });
123
+ var toolbarBtnClass = css({
124
+ background: "none",
125
+ border: "none",
126
+ padding: "6px 0",
127
+ color: "var(--accent)",
128
+ fontSize: "16px",
129
+ fontFamily: "inherit",
130
+ cursor: "pointer",
131
+ WebkitTapHighlightColor: "transparent"
132
+ });
133
+ var toolbarTitleClass = css({
134
+ fontSize: "15px",
135
+ fontWeight: 600,
136
+ color: "var(--ink)"
137
+ });
138
+ var wheelAreaClass = css({
139
+ display: "flex",
140
+ justifyContent: "center",
141
+ alignItems: "stretch",
142
+ padding: "12px 0 20px",
143
+ position: "relative"
144
+ });
145
+ var gradientOverlayClass = css({
146
+ position: "absolute",
147
+ left: 0,
148
+ right: 0,
149
+ pointerEvents: "none",
150
+ zIndex: 2
151
+ });
152
+ var columnWrapperClass = css({
153
+ flex: 1,
154
+ display: "flex",
155
+ flexDirection: "column",
156
+ alignItems: "center",
157
+ overflow: "hidden",
158
+ position: "relative"
159
+ });
160
+ var columnLabelClass = css({
161
+ fontSize: "11px",
162
+ color: "var(--muted)",
163
+ textTransform: "uppercase",
164
+ letterSpacing: "0.5px",
165
+ marginBottom: "6px",
166
+ fontWeight: 500
167
+ });
168
+ var columnViewportClass = css({
169
+ width: "100%",
170
+ height: `180px`,
171
+ overflow: "hidden",
172
+ position: "relative",
173
+ touchAction: "none"
174
+ });
175
+ var columnListClass = css({ willChange: "transform" });
176
+ var highlightBarClass = css({
177
+ position: "absolute",
178
+ top: `72px`,
179
+ left: "10%",
180
+ right: "10%",
181
+ height: `36px`,
182
+ borderRadius: "8px",
183
+ background: "rgba(255,255,255,0.06)",
184
+ pointerEvents: "none",
185
+ zIndex: 1
186
+ });
187
+ var itemBaseClass = css({
188
+ height: `36px`,
189
+ display: "flex",
190
+ alignItems: "center",
191
+ justifyContent: "center",
192
+ fontSize: "20px",
193
+ color: "var(--muted)",
194
+ userSelect: "none",
195
+ whiteSpace: "nowrap",
196
+ overflow: "hidden",
197
+ textOverflow: "ellipsis",
198
+ padding: "0 4px",
199
+ boxSizing: "border-box"
200
+ });
201
+ var selectedItemClass = css({
202
+ color: "var(--ink)",
203
+ fontWeight: 600,
204
+ fontSize: "22px"
205
+ });
206
+ var clearRowClass = css({
207
+ display: "flex",
208
+ alignItems: "center",
209
+ justifyContent: "center",
210
+ height: "44px",
211
+ gap: "6px",
212
+ color: "var(--accent)",
213
+ fontSize: "15px",
214
+ fontFamily: "inherit",
215
+ background: "none",
216
+ border: "none",
217
+ borderTop: "1px solid var(--border)",
218
+ cursor: "pointer",
219
+ width: "100%",
220
+ flexShrink: 0,
221
+ padding: 0,
222
+ "&:active": { background: "rgba(255,255,255,0.04)" }
223
+ });
224
+ function CalendarIconComp() {
225
+ return jsx(Icon, mergeProps({
226
+ svg: calendarSvg,
227
+ size: 18,
228
+ strokeWidth: 1.5
229
+ }));
230
+ }
231
+ function Columns({ y, m, days, selDay, tempYear, tempMonth, tempDay }) {
232
+ const yearWheel = makeWheel(YEARS, YEARS.indexOf(y));
233
+ const monthWheel = makeWheel(MONTHS, m);
234
+ const dayWheel = makeWheel(days, selDay - 1);
235
+ return () => {
236
+ const _el0 = _tmpl.cloneNode(true);
237
+ const _el1 = _el0.firstChild;
238
+ const _el2 = _el1.firstChild;
239
+ const _el3 = _el1.firstChild.nextSibling;
240
+ const _el4 = _el3.firstChild;
241
+ const _el5 = _el3.firstChild.nextSibling;
242
+ const _el6 = _el0.firstChild.nextSibling;
243
+ const _el7 = _el6.firstChild;
244
+ const _el8 = _el6.firstChild.nextSibling;
245
+ const _el9 = _el8.firstChild;
246
+ const _el10 = _el8.firstChild.nextSibling;
247
+ const _el11 = _el0.firstChild.nextSibling.nextSibling;
248
+ const _el12 = _el11.firstChild;
249
+ const _el13 = _el11.firstChild.nextSibling;
250
+ const _el14 = _el13.firstChild;
251
+ const _el15 = _el13.firstChild.nextSibling;
252
+ setProp(_el2, "className", () => columnLabelClass);
253
+ setProp(_el4, "className", () => highlightBarClass);
254
+ insert(_el5, () => YEARS.map((item, i) => () => {
255
+ const _el0 = _tmpl2.cloneNode(true);
256
+ insert(_el0, () => String(item));
257
+ setProp(_el0, "className", () => `${itemBaseClass} ${i === YEARS.indexOf(y) ? selectedItemClass : ""}`);
258
+ setProp(_el0, "key", () => i);
259
+ return _el0;
260
+ }));
261
+ setProp(_el5, "ref", (el) => {
262
+ if (el) yearWheel.mount(el);
263
+ });
264
+ setProp(_el5, "className", () => columnListClass);
265
+ setProp(_el5, "onPointerDown", (e) => yearWheel.handlePointerDown(e));
266
+ setProp(_el5, "onPointerMove", (e) => yearWheel.handlePointerMove(e, e.currentTarget));
267
+ setProp(_el5, "onPointerUp", (e) => yearWheel.handlePointerUp(e, e.currentTarget, (idx) => {
268
+ const newYear = YEARS[idx];
269
+ tempYear(newYear);
270
+ const maxDay = daysInMonth(newYear, tempYear());
271
+ if (tempDay() > maxDay) tempDay(maxDay);
272
+ }));
273
+ setProp(_el5, "onPointerCancel", (e) => yearWheel.handlePointerCancel(e, e.currentTarget));
274
+ setProp(_el3, "className", () => columnViewportClass);
275
+ setProp(_el1, "className", () => columnWrapperClass);
276
+ setProp(_el7, "className", () => columnLabelClass);
277
+ setProp(_el9, "className", () => highlightBarClass);
278
+ insert(_el10, () => MONTHS.map((item, i) => () => {
279
+ const _el0 = _tmpl2.cloneNode(true);
280
+ insert(_el0, () => MONTH_NAMES_SHORT[item]);
281
+ setProp(_el0, "className", () => `${itemBaseClass} ${i === m ? selectedItemClass : ""}`);
282
+ setProp(_el0, "key", () => i);
283
+ return _el0;
284
+ }));
285
+ setProp(_el10, "ref", (el) => {
286
+ if (el) monthWheel.mount(el);
287
+ });
288
+ setProp(_el10, "className", () => columnListClass);
289
+ setProp(_el10, "onPointerDown", (e) => monthWheel.handlePointerDown(e));
290
+ setProp(_el10, "onPointerMove", (e) => monthWheel.handlePointerMove(e, e.currentTarget));
291
+ setProp(_el10, "onPointerUp", (e) => monthWheel.handlePointerUp(e, e.currentTarget, (idx) => {
292
+ tempMonth(idx);
293
+ const maxDay = daysInMonth(tempYear(), idx);
294
+ if (tempDay() > maxDay) tempDay(maxDay);
295
+ }));
296
+ setProp(_el10, "onPointerCancel", (e) => monthWheel.handlePointerCancel(e, e.currentTarget));
297
+ setProp(_el8, "className", () => columnViewportClass);
298
+ setProp(_el6, "className", () => columnWrapperClass);
299
+ setProp(_el12, "className", () => columnLabelClass);
300
+ setProp(_el14, "className", () => highlightBarClass);
301
+ insert(_el15, () => days.map((item, i) => () => {
302
+ const _el0 = _tmpl2.cloneNode(true);
303
+ insert(_el0, () => String(item));
304
+ setProp(_el0, "className", () => `${itemBaseClass} ${i === selDay - 1 ? selectedItemClass : ""}`);
305
+ setProp(_el0, "key", () => i);
306
+ return _el0;
307
+ }));
308
+ setProp(_el15, "ref", (el) => {
309
+ if (el) dayWheel.mount(el);
310
+ });
311
+ setProp(_el15, "className", () => columnListClass);
312
+ setProp(_el15, "onPointerDown", (e) => dayWheel.handlePointerDown(e));
313
+ setProp(_el15, "onPointerMove", (e) => dayWheel.handlePointerMove(e, e.currentTarget));
314
+ setProp(_el15, "onPointerUp", (e) => dayWheel.handlePointerUp(e, e.currentTarget, (idx) => tempDay(idx + 1)));
315
+ setProp(_el15, "onPointerCancel", (e) => dayWheel.handlePointerCancel(e, e.currentTarget));
316
+ setProp(_el13, "className", () => columnViewportClass);
317
+ setProp(_el11, "className", () => columnWrapperClass);
318
+ setProp(_el0, "style", () => ({
319
+ display: "flex",
320
+ width: "100%"
321
+ }));
322
+ return _el0;
323
+ };
324
+ }
325
+ var DatePickerMobile = (props) => {
326
+ const [local] = splitProps(props, [
327
+ "value",
328
+ "onValueChange",
329
+ "placeholder",
330
+ "clearable",
331
+ "clearLabel",
332
+ "backdropClassName",
333
+ "backdropStyle"
334
+ ]);
335
+ const open = createSignal(false);
336
+ const resolveValue = () => {
337
+ return (typeof local.value === "function" ? local.value() : local.value) ?? null;
338
+ };
339
+ const tempYear = createSignal(2e3);
340
+ const tempMonth = createSignal(0);
341
+ const tempDay = createSignal(1);
342
+ createEffect(() => {
343
+ if (!open()) return;
344
+ const onKey = (e) => {
345
+ if (e.key === "Escape") cancel();
346
+ };
347
+ document.addEventListener("keydown", onKey);
348
+ const prevOverflow = document.body.style.overflow;
349
+ document.body.style.overflow = "hidden";
350
+ return () => {
351
+ document.removeEventListener("keydown", onKey);
352
+ document.body.style.overflow = prevOverflow;
353
+ };
354
+ });
355
+ const openSheet = () => {
356
+ const d = resolveValue() || /* @__PURE__ */ new Date();
357
+ tempYear(d.getFullYear());
358
+ tempMonth(d.getMonth());
359
+ tempDay(Math.min(d.getDate(), daysInMonth(d.getFullYear(), d.getMonth())));
360
+ open(true);
361
+ };
362
+ const confirm = () => {
363
+ const date = toDate(tempYear(), tempMonth(), tempDay());
364
+ local.onValueChange?.(date);
365
+ open(false);
366
+ };
367
+ const cancel = () => {
368
+ open(false);
369
+ };
370
+ const clear = () => {
371
+ local.onValueChange?.(null);
372
+ open(false);
373
+ };
374
+ const dayItems = () => getDays(tempYear(), tempMonth());
375
+ return jsx(Fragment, { children: [() => {
376
+ const _el0 = _tmpl3.cloneNode(true);
377
+ const _el1 = _el0.firstChild;
378
+ const _el2 = _el0.firstChild.nextSibling;
379
+ insert(_el0, () => {
380
+ const d = resolveValue();
381
+ return () => {
382
+ const _el0 = _tmpl4.cloneNode(true);
383
+ insert(_el0, () => d ? formatDateLabel(d) : local.placeholder || "Select date");
384
+ setProp(_el0, "className", () => `${triggerClass} ${d ? triggerValueClass : triggerPlaceholderClass}`);
385
+ return _el0;
386
+ };
387
+ }, _el1);
388
+ insert(_el2, () => jsx(CalendarIconComp, {}));
389
+ setProp(_el2, "className", () => calendarIconClass);
390
+ setProp(_el0, "className", () => triggerWrapperClass);
391
+ setProp(_el0, "onClick", () => openSheet);
392
+ return _el0;
393
+ }, () => {
394
+ if (!open()) return null;
395
+ const y = tempYear();
396
+ const m = tempMonth();
397
+ const days = dayItems();
398
+ const selDay = tempDay();
399
+ return () => {
400
+ const _el0 = _tmpl5.cloneNode(true);
401
+ const _el1 = _el0.firstChild;
402
+ const _el2 = _el0.firstChild.nextSibling;
403
+ const _el3 = _el2.firstChild;
404
+ const _el4 = _el3.firstChild;
405
+ const _el5 = _el3.firstChild.nextSibling;
406
+ const _el6 = _el3.firstChild.nextSibling.nextSibling;
407
+ const _el7 = _el2.firstChild.nextSibling;
408
+ const _el8 = _el2.firstChild.nextSibling.nextSibling;
409
+ const _el9 = _el2.firstChild.nextSibling.nextSibling.nextSibling;
410
+ const _el10 = _el2.firstChild.nextSibling.nextSibling.nextSibling.nextSibling;
411
+ setProp(_el1, "className", () => `${backdropClass} ${local.backdropClassName || ""}`);
412
+ setProp(_el1, "style", () => local.backdropStyle);
413
+ setProp(_el1, "onClick", () => cancel);
414
+ setProp(_el4, "className", () => toolbarBtnClass);
415
+ setProp(_el4, "onClick", () => cancel);
416
+ setProp(_el5, "className", () => toolbarTitleClass);
417
+ setProp(_el6, "className", () => toolbarBtnClass);
418
+ setProp(_el6, "onClick", () => confirm);
419
+ setProp(_el3, "className", () => toolbarClass);
420
+ setProp(_el7, "className", () => gradientOverlayClass);
421
+ setProp(_el7, "style", () => ({
422
+ top: 0,
423
+ height: `72px`,
424
+ background: "linear-gradient(to bottom, var(--surface) 0%, transparent 100%)"
425
+ }));
426
+ setProp(_el8, "className", () => gradientOverlayClass);
427
+ setProp(_el8, "style", () => ({
428
+ bottom: 0,
429
+ height: `72px`,
430
+ background: "linear-gradient(to top, var(--surface) 0%, transparent 100%)"
431
+ }));
432
+ insert(_el9, () => jsx(Columns, mergeProps({
433
+ y,
434
+ m,
435
+ days,
436
+ selDay,
437
+ tempYear,
438
+ tempMonth,
439
+ tempDay
440
+ })));
441
+ setProp(_el9, "className", () => wheelAreaClass);
442
+ insert(_el2, () => local.clearable && (() => {
443
+ const _el0 = _tmpl6.cloneNode(true);
444
+ insert(_el0, () => local.clearLabel || "Clear");
445
+ setProp(_el0, "className", () => clearRowClass);
446
+ setProp(_el0, "onClick", () => clear);
447
+ return _el0;
448
+ }), _el10);
449
+ setProp(_el2, "className", () => sheetClass);
450
+ setProp(_el0, "className", () => `${overlayClass} ${openClass}`);
451
+ return _el0;
452
+ };
453
+ }] });
454
+ };
455
+ //#endregion
456
+ export { DatePickerMobile as default };
457
+
458
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["css","createEffect","createSignal","splitProps","Icon","CENTER_OFFSET","ITEM_HEIGHT","makeWheel","_tmpl6","_template","_tmpl5","_tmpl4","_tmpl3","_tmpl2","_tmpl","MONTH_NAMES_SHORT","daysInMonth","year","month","Date","getDate","YEARS","Array","from","length","_","i","MONTHS","getDays","count","toDate","day","formatDateLabel","date","getMonth","getFullYear","calendarSvg","triggerWrapperClass","position","width","background","border","padding","font","cursor","color","outline","borderRadius","boxShadow","triggerClass","height","fontSize","fontFamily","boxSizing","display","alignItems","triggerPlaceholderClass","triggerValueClass","calendarIconClass","right","top","transform","pointerEvents","overlayClass","inset","zIndex","flexDirection","justifyContent","backdropClass","opacity","transition","sheetClass","borderTop","paddingBottom","openClass","toolbarClass","borderBottom","flexShrink","toolbarBtnClass","WebkitTapHighlightColor","toolbarTitleClass","fontWeight","wheelAreaClass","gradientOverlayClass","left","columnWrapperClass","flex","overflow","columnLabelClass","textTransform","letterSpacing","marginBottom","columnViewportClass","touchAction","columnListClass","willChange","highlightBarClass","itemBaseClass","userSelect","whiteSpace","textOverflow","selectedItemClass","clearRowClass","gap","CalendarIconComp","_jsx","_mergeProps","svg","size","strokeWidth","Columns","y","m","days","selDay","tempYear","tempMonth","tempDay","yearWheel","indexOf","monthWheel","dayWheel","_el0","cloneNode","_el1","firstChild","_el2","_el3","nextSibling","_el4","_el5","_el6","_el7","_el8","_el9","_el10","_el11","_el12","_el13","_el14","_el15","_setProp","_insert","map","item","String","el","mount","e","handlePointerDown","handlePointerMove","currentTarget","handlePointerUp","idx","newYear","maxDay","handlePointerCancel","DatePickerMobile","props","local","open","resolveValue","v","value","onKey","key","cancel","document","addEventListener","prevOverflow","body","style","removeEventListener","openSheet","d","Math","min","confirm","onValueChange","clear","dayItems","_Fragment","children","placeholder","backdropClassName","backdropStyle","bottom","clearable","clearLabel"],"sources":["../../../src/components/DatePickerMobile/index.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createEffect, createSignal, splitProps } from '@plastic-js/plastic'\nimport Icon from '../Icon.jsx'\nimport { CENTER_OFFSET, ITEM_HEIGHT, makeWheel } from './wheel.js'\n\n// ── Date helpers ──────────────────────────────────────────────────────────\nconst MONTH_NAMES_SHORT = [\n\t'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n\t'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n]\n\nconst daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate()\n\nconst YEARS = Array.from({ length: 200 }, (_, i) => 1900 + i)\nconst MONTHS = Array.from({ length: 12 }, (_, i) => i)\n\nconst getDays = (year, month) => {\n\tconst count = daysInMonth(year, month)\n\treturn Array.from({ length: count }, (_, i) => i + 1)\n}\n\nconst toDate = (year, month, day) => new Date(year, month, day)\n\nconst formatDateLabel = (date) => {\n\tif (!date) return ''\n\treturn `${MONTH_NAMES_SHORT[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`\n}\n\n// ── SVGs ───────────────────────────────────────────────────────────────────\nconst calendarSvg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"/><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"/></svg>'\n\n// ── Styles ─────────────────────────────────────────────────────────────────\nconst triggerWrapperClass = css({\n\tposition: 'relative',\n\twidth: '100%',\n\tbackground: 'none',\n\tborder: 'none',\n\tpadding: 0,\n\tfont: 'inherit',\n\tcursor: 'pointer',\n\tcolor: 'inherit',\n\toutline: 'none',\n\tborderRadius: '10px',\n\t'&:focus-visible': { boxShadow: '0 0 0 2px var(--accent)' },\n})\n\nconst triggerClass = css({\n\twidth: '100%',\n\theight: '42px',\n\tpadding: '0 36px 0 14px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\toutline: 'none',\n\tboxSizing: 'border-box',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tcursor: 'pointer',\n})\n\nconst triggerPlaceholderClass = css({\n\tcolor: 'var(--muted)',\n})\n\nconst triggerValueClass = css({\n\tcolor: 'var(--ink)',\n})\n\nconst calendarIconClass = css({\n\tposition: 'absolute',\n\tright: '10px',\n\ttop: '50%',\n\ttransform: 'translateY(-50%)',\n\twidth: '18px',\n\theight: '18px',\n\tcolor: 'var(--muted)',\n\tpointerEvents: 'none',\n})\n\nconst overlayClass = css({\n\tposition: 'fixed',\n\tinset: 0,\n\tzIndex: 1000,\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tjustifyContent: 'flex-end',\n\tpointerEvents: 'none',\n})\n\nconst backdropClass = css({\n\tposition: 'absolute',\n\tinset: 0,\n\tbackground: 'rgba(0,0,0,0.5)',\n\topacity: 0,\n\ttransition: 'opacity 240ms ease',\n})\n\nconst sheetClass = css({\n\tposition: 'relative',\n\twidth: '100%',\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\tbackground: 'var(--surface)',\n\tborderTop: '1px solid var(--border)',\n\tborderRadius: '18px 18px 0 0',\n\tboxShadow: '0 -8px 32px rgba(0,0,0,0.4)',\n\tpaddingBottom: 'env(safe-area-inset-bottom, 0px)',\n\ttransform: 'translateY(100%)',\n\ttransition: 'transform 280ms cubic-bezier(0.32, 0.72, 0, 1)',\n})\n\nconst openClass = css({\n\tpointerEvents: 'auto',\n\t[`& .${backdropClass}`]: { opacity: 1 },\n\t[`& .${sheetClass}`]: { transform: 'translateY(0)' },\n})\n\nconst toolbarClass = css({\n\tdisplay: 'flex',\n\tjustifyContent: 'space-between',\n\talignItems: 'center',\n\tpadding: '12px 16px',\n\tborderBottom: '1px solid var(--border)',\n\tflexShrink: 0,\n})\n\nconst toolbarBtnClass = css({\n\tbackground: 'none',\n\tborder: 'none',\n\tpadding: '6px 0',\n\tcolor: 'var(--accent)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\tcursor: 'pointer',\n\tWebkitTapHighlightColor: 'transparent',\n})\n\nconst toolbarTitleClass = css({\n\tfontSize: '15px',\n\tfontWeight: 600,\n\tcolor: 'var(--ink)',\n})\n\nconst wheelAreaClass = css({\n\tdisplay: 'flex',\n\tjustifyContent: 'center',\n\talignItems: 'stretch',\n\tpadding: '12px 0 20px',\n\tposition: 'relative',\n})\n\nconst gradientOverlayClass = css({\n\tposition: 'absolute',\n\tleft: 0,\n\tright: 0,\n\tpointerEvents: 'none',\n\tzIndex: 2,\n})\n\nconst columnWrapperClass = css({\n\tflex: 1,\n\tdisplay: 'flex',\n\tflexDirection: 'column',\n\talignItems: 'center',\n\toverflow: 'hidden',\n\tposition: 'relative',\n})\n\nconst columnLabelClass = css({\n\tfontSize: '11px',\n\tcolor: 'var(--muted)',\n\ttextTransform: 'uppercase',\n\tletterSpacing: '0.5px',\n\tmarginBottom: '6px',\n\tfontWeight: 500,\n})\n\nconst columnViewportClass = css({\n\twidth: '100%',\n\theight: `${CENTER_OFFSET * 2 + ITEM_HEIGHT}px`,\n\toverflow: 'hidden',\n\tposition: 'relative',\n\ttouchAction: 'none',\n})\n\nconst columnListClass = css({\n\twillChange: 'transform',\n})\n\nconst highlightBarClass = css({\n\tposition: 'absolute',\n\ttop: `${CENTER_OFFSET}px`,\n\tleft: '10%',\n\tright: '10%',\n\theight: `${ITEM_HEIGHT}px`,\n\tborderRadius: '8px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tpointerEvents: 'none',\n\tzIndex: 1,\n})\n\nconst itemBaseClass = css({\n\theight: `${ITEM_HEIGHT}px`,\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'center',\n\tfontSize: '20px',\n\tcolor: 'var(--muted)',\n\tuserSelect: 'none',\n\twhiteSpace: 'nowrap',\n\toverflow: 'hidden',\n\ttextOverflow: 'ellipsis',\n\tpadding: '0 4px',\n\tboxSizing: 'border-box',\n})\n\nconst selectedItemClass = css({\n\tcolor: 'var(--ink)',\n\tfontWeight: 600,\n\tfontSize: '22px',\n})\n\nconst clearRowClass = css({\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'center',\n\theight: '44px',\n\tgap: '6px',\n\tcolor: 'var(--accent)',\n\tfontSize: '15px',\n\tfontFamily: 'inherit',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderTop: '1px solid var(--border)',\n\tcursor: 'pointer',\n\twidth: '100%',\n\tflexShrink: 0,\n\tpadding: 0,\n\t'&:active': { background: 'rgba(255,255,255,0.04)' },\n})\n\n// ── CalendarIcon ───────────────────────────────────────────────────────────\nfunction CalendarIconComp() {\n\treturn <Icon svg={calendarSvg} size={18} strokeWidth={1.5} />\n}\n\n// ── Columns ────────────────────────────────────────────────────────────────\n//\n// Renders the three wheel columns (year / month / day). Receives all data as\n// plain props so it can be used as a normal Plastic component.\nfunction Columns({ y, m, days, selDay, tempYear, tempMonth, tempDay }) {\n\tconst yearWheel = makeWheel(YEARS, YEARS.indexOf(y))\n\tconst monthWheel = makeWheel(MONTHS, m)\n\tconst dayWheel = makeWheel(days, selDay - 1)\n\n\treturn (\n\t\t<div style={{ display: 'flex', width: '100%' }}>\n\t\t\t<div className={columnWrapperClass}>\n\t\t\t\t<span className={columnLabelClass}>Year</span>\n\t\t\t\t<div className={columnViewportClass}>\n\t\t\t\t\t<div className={highlightBarClass} />\n\t\t\t\t\t<div\n\t\t\t\t\t\tref={(el) => { if (el) yearWheel.mount(el) }}\n\t\t\t\t\t\tclassName={columnListClass}\n\t\t\t\t\t\tonPointerDown={(e) => yearWheel.handlePointerDown(e)}\n\t\t\t\t\t\tonPointerMove={(e) => yearWheel.handlePointerMove(e, e.currentTarget)}\n\t\t\t\t\t\tonPointerUp={(e) => yearWheel.handlePointerUp(e, e.currentTarget, (idx) => {\n\t\t\t\t\t\t\tconst newYear = YEARS[idx]\n\t\t\t\t\t\t\ttempYear(newYear)\n\t\t\t\t\t\t\tconst maxDay = daysInMonth(newYear, tempYear())\n\t\t\t\t\t\t\tif (tempDay() > maxDay) tempDay(maxDay)\n\t\t\t\t\t\t})}\n\t\t\t\t\t\tonPointerCancel={(e) => yearWheel.handlePointerCancel(e, e.currentTarget)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{YEARS.map((item, i) => (\n\t\t\t\t\t\t\t<div className={`${itemBaseClass} ${i === YEARS.indexOf(y) ? selectedItemClass : ''}`} key={i}>{String(item)}</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className={columnWrapperClass}>\n\t\t\t\t<span className={columnLabelClass}>Month</span>\n\t\t\t\t<div className={columnViewportClass}>\n\t\t\t\t\t<div className={highlightBarClass} />\n\t\t\t\t\t<div\n\t\t\t\t\t\tref={(el) => { if (el) monthWheel.mount(el) }}\n\t\t\t\t\t\tclassName={columnListClass}\n\t\t\t\t\t\tonPointerDown={(e) => monthWheel.handlePointerDown(e)}\n\t\t\t\t\t\tonPointerMove={(e) => monthWheel.handlePointerMove(e, e.currentTarget)}\n\t\t\t\t\t\tonPointerUp={(e) => monthWheel.handlePointerUp(e, e.currentTarget, (idx) => {\n\t\t\t\t\t\t\ttempMonth(idx)\n\t\t\t\t\t\t\tconst maxDay = daysInMonth(tempYear(), idx)\n\t\t\t\t\t\t\tif (tempDay() > maxDay) tempDay(maxDay)\n\t\t\t\t\t\t})}\n\t\t\t\t\t\tonPointerCancel={(e) => monthWheel.handlePointerCancel(e, e.currentTarget)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{MONTHS.map((item, i) => (\n\t\t\t\t\t\t\t<div className={`${itemBaseClass} ${i === m ? selectedItemClass : ''}`} key={i}>{MONTH_NAMES_SHORT[item]}</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className={columnWrapperClass}>\n\t\t\t\t<span className={columnLabelClass}>Day</span>\n\t\t\t\t<div className={columnViewportClass}>\n\t\t\t\t\t<div className={highlightBarClass} />\n\t\t\t\t\t<div\n\t\t\t\t\t\tref={(el) => { if (el) dayWheel.mount(el) }}\n\t\t\t\t\t\tclassName={columnListClass}\n\t\t\t\t\t\tonPointerDown={(e) => dayWheel.handlePointerDown(e)}\n\t\t\t\t\t\tonPointerMove={(e) => dayWheel.handlePointerMove(e, e.currentTarget)}\n\t\t\t\t\t\tonPointerUp={(e) => dayWheel.handlePointerUp(e, e.currentTarget, (idx) => tempDay(idx + 1))}\n\t\t\t\t\t\tonPointerCancel={(e) => dayWheel.handlePointerCancel(e, e.currentTarget)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{days.map((item, i) => (\n\t\t\t\t\t\t\t<div className={`${itemBaseClass} ${i === selDay - 1 ? selectedItemClass : ''}`} key={i}>{String(item)}</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n// ── DatePickerMobile ───────────────────────────────────────────────────────\n//\n// A mobile bottom-sheet date picker with iOS-style wheel columns for\n// year, month, and day. The trigger visually mimics <input type=\"date\">.\n//\n// Props:\n// value Date | (() => Date | null) — current selected date\n// onValueChange (Date | null) => void — called when user confirms\n// placeholder string — trigger placeholder text (default \"Select date\")\n// clearable boolean — show a \"Clear\" row in the sheet\n// clearLabel string — label for the clear row (default \"Clear\")\n// backdropClassName className for the backdrop\n// backdropStyle inline style for the backdrop\nconst DatePickerMobile = (props) => {\n\tconst [local] = splitProps(props, [\n\t\t'value', 'onValueChange', 'placeholder',\n\t\t'clearable', 'clearLabel',\n\t\t'backdropClassName', 'backdropStyle',\n\t])\n\n\tconst open = createSignal(false)\n\n\tconst resolveValue = () => {\n\t\tconst v = typeof local.value === 'function' ? local.value() : local.value\n\t\treturn v ?? null\n\t}\n\n\tconst tempYear = createSignal(2000)\n\tconst tempMonth = createSignal(0)\n\tconst tempDay = createSignal(1)\n\n\tcreateEffect(() => {\n\t\tif (!open()) return\n\t\tconst onKey = (e) => { if (e.key === 'Escape') cancel() }\n\t\tdocument.addEventListener('keydown', onKey)\n\t\tconst prevOverflow = document.body.style.overflow\n\t\tdocument.body.style.overflow = 'hidden'\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('keydown', onKey)\n\t\t\tdocument.body.style.overflow = prevOverflow\n\t\t}\n\t})\n\n\tconst openSheet = () => {\n\t\tconst d = resolveValue() || new Date()\n\t\ttempYear(d.getFullYear())\n\t\ttempMonth(d.getMonth())\n\t\ttempDay(Math.min(d.getDate(), daysInMonth(d.getFullYear(), d.getMonth())))\n\t\topen(true)\n\t}\n\n\tconst confirm = () => {\n\t\tconst date = toDate(tempYear(), tempMonth(), tempDay())\n\t\tlocal.onValueChange?.(date)\n\t\topen(false)\n\t}\n\n\tconst cancel = () => {\n\t\topen(false)\n\t}\n\n\tconst clear = () => {\n\t\tlocal.onValueChange?.(null)\n\t\topen(false)\n\t}\n\n\tconst dayItems = () => getDays(tempYear(), tempMonth())\n\n\treturn (\n\t\t<>\n\t\t\t<button type='button' className={triggerWrapperClass} onClick={openSheet}>\n\t\t\t\t{() => {\n\t\t\t\t\tconst d = resolveValue()\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span className={`${triggerClass} ${d ? triggerValueClass : triggerPlaceholderClass}`}>\n\t\t\t\t\t\t\t{d ? formatDateLabel(d) : (local.placeholder || 'Select date')}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t}}\n\t\t\t\t<span className={calendarIconClass}>\n\t\t\t\t\t<CalendarIconComp />\n\t\t\t\t</span>\n\t\t\t</button>\n\n\t\t\t{() => {\n\t\t\t\tif (!open()) return null\n\t\t\t\tconst y = tempYear()\n\t\t\t\tconst m = tempMonth()\n\t\t\t\tconst days = dayItems()\n\t\t\t\tconst selDay = tempDay()\n\n\t\t\t\treturn (\n\t\t\t\t\t<div className={`${overlayClass} ${openClass}`}>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclassName={`${backdropClass} ${local.backdropClassName || ''}`}\n\t\t\t\t\t\t\tstyle={local.backdropStyle}\n\t\t\t\t\t\t\trole='presentation'\n\t\t\t\t\t\t\taria-hidden='true'\n\t\t\t\t\t\t\tonClick={cancel}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div className={sheetClass} role='dialog' aria-label='Date picker'>\n\t\t\t\t\t\t\t<div className={toolbarClass}>\n\t\t\t\t\t\t\t\t<button className={toolbarBtnClass} type='button' onClick={cancel}>Cancel</button>\n\t\t\t\t\t\t\t\t<span className={toolbarTitleClass}>Select Date</span>\n\t\t\t\t\t\t\t\t<button className={toolbarBtnClass} type='button' onClick={confirm}>Done</button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className={gradientOverlayClass} style={{ top: 0, height: `${CENTER_OFFSET}px`, background: 'linear-gradient(to bottom, var(--surface) 0%, transparent 100%)' }} />\n\t\t\t\t\t\t\t<div className={gradientOverlayClass} style={{ bottom: 0, height: `${CENTER_OFFSET}px`, background: 'linear-gradient(to top, var(--surface) 0%, transparent 100%)' }} />\n\t\t\t\t\t\t\t<div className={wheelAreaClass}>\n\t\t\t\t\t\t\t\t<Columns\n\t\t\t\t\t\t\t\t\ty={y}\n\t\t\t\t\t\t\t\t\tm={m}\n\t\t\t\t\t\t\t\t\tdays={days}\n\t\t\t\t\t\t\t\t\tselDay={selDay}\n\t\t\t\t\t\t\t\t\ttempYear={tempYear}\n\t\t\t\t\t\t\t\t\ttempMonth={tempMonth}\n\t\t\t\t\t\t\t\t\ttempDay={tempDay}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{local.clearable && (\n\t\t\t\t\t\t\t\t<button className={clearRowClass} type='button' onClick={clear}>\n\t\t\t\t\t\t\t\t\t{local.clearLabel || 'Clear'}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t)\n\t\t\t}}\n\t\t</>\n\t)\n}\n\nexport default DatePickerMobile\n"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ function clampOffset(offset, itemCount) {
2
+ const max = 72;
3
+ const min = 72 - Math.max(0, itemCount - 1) * 36;
4
+ return Math.max(min, Math.min(max, offset));
5
+ }
6
+ function getIndexFromOffset(offset, itemCount) {
7
+ const raw = Math.round((72 - offset) / 36);
8
+ return Math.max(0, Math.min(itemCount - 1, raw));
9
+ }
10
+ function snapAnimation(el, from, to, onComplete) {
11
+ const duration = 180;
12
+ const startTime = performance.now();
13
+ function tick(now) {
14
+ const t = Math.min((now - startTime) / duration, 1);
15
+ const ease = 1 - Math.pow(1 - t, 3);
16
+ const current = from + (to - from) * ease;
17
+ el.style.transform = `translateY(${current}px)`;
18
+ if (t < 1) requestAnimationFrame(tick);
19
+ else onComplete?.();
20
+ }
21
+ requestAnimationFrame(tick);
22
+ }
23
+ function makeWheel(items, index) {
24
+ let translateY = clampOffset(72 - index * 36, items.length);
25
+ let drag = null;
26
+ let animFrame = null;
27
+ return {
28
+ mount(el) {
29
+ el.style.transform = `translateY(${translateY}px)`;
30
+ },
31
+ destroy() {
32
+ cancelAnimationFrame(animFrame);
33
+ drag = null;
34
+ },
35
+ handlePointerDown(e) {
36
+ e.preventDefault();
37
+ cancelAnimationFrame(animFrame);
38
+ drag = {
39
+ startY: e.clientY,
40
+ startTranslate: translateY,
41
+ lastY: e.clientY,
42
+ lastTime: performance.now(),
43
+ velocity: 0
44
+ };
45
+ },
46
+ handlePointerMove(e, el) {
47
+ if (!drag) return;
48
+ const dy = e.clientY - drag.startY;
49
+ const now = performance.now();
50
+ const dt = now - drag.lastTime;
51
+ if (dt > 0) drag.velocity = (e.clientY - drag.lastY) / dt;
52
+ drag.lastY = e.clientY;
53
+ drag.lastTime = now;
54
+ const offset = clampOffset(drag.startTranslate + dy, items.length);
55
+ translateY = offset;
56
+ el.style.transform = `translateY(${offset}px)`;
57
+ },
58
+ handlePointerUp(e, el, onChange) {
59
+ if (!drag) return;
60
+ const vel = drag.velocity;
61
+ drag = null;
62
+ let finalOffset = translateY;
63
+ if (Math.abs(vel) > .3) finalOffset = clampOffset(finalOffset + vel * 120, items.length);
64
+ const idx = getIndexFromOffset(finalOffset, items.length);
65
+ const target = clampOffset(72 - idx * 36, items.length);
66
+ translateY = target;
67
+ snapAnimation(el, finalOffset, target);
68
+ onChange(idx);
69
+ },
70
+ handlePointerCancel(e, el) {
71
+ if (!drag) return;
72
+ const target = clampOffset(72 - getIndexFromOffset(translateY, items.length) * 36, items.length);
73
+ translateY = target;
74
+ snapAnimation(el, translateY, target);
75
+ drag = null;
76
+ }
77
+ };
78
+ }
79
+ //#endregion
80
+ export { makeWheel };
81
+
82
+ //# sourceMappingURL=wheel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wheel.js","names":[],"sources":["../../../src/components/DatePickerMobile/wheel.js"],"sourcesContent":["// ── Wheel constants ──────────────────────────────────────────────────────\nexport const ITEM_HEIGHT = 36\nexport const VISIBLE_ITEMS = 5\nexport const CONTAINER_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS\nexport const CENTER_OFFSET = (CONTAINER_HEIGHT - ITEM_HEIGHT) / 2\n\n// ── Math helpers ─────────────────────────────────────────────────────────\nexport function clampOffset(offset, itemCount) {\n\tconst max = CENTER_OFFSET\n\tconst min = CENTER_OFFSET - Math.max(0, itemCount - 1) * ITEM_HEIGHT\n\treturn Math.max(min, Math.min(max, offset))\n}\n\nexport function getIndexFromOffset(offset, itemCount) {\n\tconst raw = Math.round((CENTER_OFFSET - offset) / ITEM_HEIGHT)\n\treturn Math.max(0, Math.min(itemCount - 1, raw))\n}\n\nexport function snapAnimation(el, from, to, onComplete) {\n\tconst duration = 180\n\tconst startTime = performance.now()\n\tfunction tick(now) {\n\t\tconst t = Math.min((now - startTime) / duration, 1)\n\t\tconst ease = 1 - Math.pow(1 - t, 3)\n\t\tconst current = from + (to - from) * ease\n\t\tel.style.transform = `translateY(${current}px)`\n\t\tif (t < 1) {\n\t\t\trequestAnimationFrame(tick)\n\t\t} else {\n\t\t\tonComplete?.()\n\t\t}\n\t}\n\trequestAnimationFrame(tick)\n}\n\n// ── Wheel controller factory ─────────────────────────────────────────────\n//\n// Creates a mutable wheel-scroll controller for one column. All state is kept\n// in plain closures — no Plastic signals — so it works without lifecycle\n// constraints.\nexport function makeWheel(items, index) {\n\tlet translateY = clampOffset(CENTER_OFFSET - index * ITEM_HEIGHT, items.length)\n\tlet drag = null\n\tlet animFrame = null\n\treturn {\n\t\tmount(el) {\n\t\t\tel.style.transform = `translateY(${translateY}px)`\n\t\t},\n\t\tdestroy() {\n\t\t\tcancelAnimationFrame(animFrame)\n\t\t\tdrag = null\n\t\t},\n\t\thandlePointerDown(e) {\n\t\t\te.preventDefault()\n\t\t\tcancelAnimationFrame(animFrame)\n\t\t\tdrag = { startY: e.clientY, startTranslate: translateY, lastY: e.clientY, lastTime: performance.now(), velocity: 0 }\n\t\t},\n\t\thandlePointerMove(e, el) {\n\t\t\tif (!drag) return\n\t\t\tconst dy = e.clientY - drag.startY\n\t\t\tconst now = performance.now()\n\t\t\tconst dt = now - drag.lastTime\n\t\t\tif (dt > 0) drag.velocity = (e.clientY - drag.lastY) / dt\n\t\t\tdrag.lastY = e.clientY\n\t\t\tdrag.lastTime = now\n\t\t\tconst offset = clampOffset(drag.startTranslate + dy, items.length)\n\t\t\ttranslateY = offset\n\t\t\tel.style.transform = `translateY(${offset}px)`\n\t\t},\n\t\thandlePointerUp(e, el, onChange) {\n\t\t\tif (!drag) return\n\t\t\tconst vel = drag.velocity\n\t\t\tdrag = null\n\t\t\tlet finalOffset = translateY\n\t\t\tif (Math.abs(vel) > 0.3) finalOffset = clampOffset(finalOffset + vel * 120, items.length)\n\t\t\tconst idx = getIndexFromOffset(finalOffset, items.length)\n\t\t\tconst target = clampOffset(CENTER_OFFSET - idx * ITEM_HEIGHT, items.length)\n\t\t\ttranslateY = target\n\t\t\tsnapAnimation(el, finalOffset, target)\n\t\t\tonChange(idx)\n\t\t},\n\t\thandlePointerCancel(e, el) {\n\t\t\tif (!drag) return\n\t\t\tconst idx = getIndexFromOffset(translateY, items.length)\n\t\t\tconst target = clampOffset(CENTER_OFFSET - idx * ITEM_HEIGHT, items.length)\n\t\t\ttranslateY = target\n\t\t\tsnapAnimation(el, translateY, target)\n\t\t\tdrag = null\n\t\t},\n\t}\n}\n"],"mappings":"AAOA,SAAgB,YAAY,QAAQ,WAAW;CAC9C,MAAM,MAAA;CACN,MAAM,MAAA,KAAsB,KAAK,IAAI,GAAG,YAAY,CAAC,IAAA;CACrD,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,MAAM,CAAC;AAC3C;AAEA,SAAgB,mBAAmB,QAAQ,WAAW;CACrD,MAAM,MAAM,KAAK,OAAA,KAAuB,UAAA,EAAqB;CAC7D,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,YAAY,GAAG,GAAG,CAAC;AAChD;AAEA,SAAgB,cAAc,IAAI,MAAM,IAAI,YAAY;CACvD,MAAM,WAAW;CACjB,MAAM,YAAY,YAAY,IAAI;CAClC,SAAS,KAAK,KAAK;EAClB,MAAM,IAAI,KAAK,KAAK,MAAM,aAAa,UAAU,CAAC;EAClD,MAAM,OAAO,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EAClC,MAAM,UAAU,QAAQ,KAAK,QAAQ;EACrC,GAAG,MAAM,YAAY,cAAc,QAAQ;EAC3C,IAAI,IAAI,GACP,sBAAsB,IAAI;OAE1B,aAAa;CAEf;CACA,sBAAsB,IAAI;AAC3B;AAOA,SAAgB,UAAU,OAAO,OAAO;CACvC,IAAI,aAAa,YAAA,KAA4B,QAAA,IAAqB,MAAM,MAAM;CAC9E,IAAI,OAAO;CACX,IAAI,YAAY;CAChB,OAAO;EACN,MAAM,IAAI;GACT,GAAG,MAAM,YAAY,cAAc,WAAW;EAC/C;EACA,UAAU;GACT,qBAAqB,SAAS;GAC9B,OAAO;EACR;EACA,kBAAkB,GAAG;GACpB,EAAE,eAAe;GACjB,qBAAqB,SAAS;GAC9B,OAAO;IAAE,QAAQ,EAAE;IAAS,gBAAgB;IAAY,OAAO,EAAE;IAAS,UAAU,YAAY,IAAI;IAAG,UAAU;GAAE;EACpH;EACA,kBAAkB,GAAG,IAAI;GACxB,IAAI,CAAC,MAAM;GACX,MAAM,KAAK,EAAE,UAAU,KAAK;GAC5B,MAAM,MAAM,YAAY,IAAI;GAC5B,MAAM,KAAK,MAAM,KAAK;GACtB,IAAI,KAAK,GAAG,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;GACvD,KAAK,QAAQ,EAAE;GACf,KAAK,WAAW;GAChB,MAAM,SAAS,YAAY,KAAK,iBAAiB,IAAI,MAAM,MAAM;GACjE,aAAa;GACb,GAAG,MAAM,YAAY,cAAc,OAAO;EAC3C;EACA,gBAAgB,GAAG,IAAI,UAAU;GAChC,IAAI,CAAC,MAAM;GACX,MAAM,MAAM,KAAK;GACjB,OAAO;GACP,IAAI,cAAc;GAClB,IAAI,KAAK,IAAI,GAAG,IAAI,IAAK,cAAc,YAAY,cAAc,MAAM,KAAK,MAAM,MAAM;GACxF,MAAM,MAAM,mBAAmB,aAAa,MAAM,MAAM;GACxD,MAAM,SAAS,YAAA,KAA4B,MAAA,IAAmB,MAAM,MAAM;GAC1E,aAAa;GACb,cAAc,IAAI,aAAa,MAAM;GACrC,SAAS,GAAG;EACb;EACA,oBAAoB,GAAG,IAAI;GAC1B,IAAI,CAAC,MAAM;GAEX,MAAM,SAAS,YAAA,KADH,mBAAmB,YAAY,MAAM,MACN,IAAA,IAAmB,MAAM,MAAM;GAC1E,aAAa;GACb,cAAc,IAAI,YAAY,MAAM;GACpC,OAAO;EACR;CACD;AACD"}
@@ -8,7 +8,9 @@ var _tmpl2 = template("<div><input type=\"text\" placeholder=\"Filter…\"><butt
8
8
  var _tmpl = template("<svg fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>");
9
9
  var inputWrapperClass = css({
10
10
  position: "relative",
11
- marginBottom: "6px"
11
+ marginBottom: "6px",
12
+ "& button": { visibility: "hidden" },
13
+ "&:focus-within button": { visibility: "visible" }
12
14
  });
13
15
  var inputClass = css({
14
16
  width: "100%",
@@ -1 +1 @@
1
- {"version":3,"file":"FilterableSelectMobile.js","names":["css","createSignal","splitProps","SelectMobile","_tmpl3","_template","_tmpl2","_tmpl","inputWrapperClass","position","marginBottom","inputClass","width","height","padding","background","border","borderRadius","color","fontSize","fontFamily","outline","boxSizing","borderColor","clearButtonClass","right","top","transform","display","alignItems","justifyContent","cursor","XIcon","cloneNode","noResultsClass","textAlign","defaultItemToValue","item","value","defaultItemToLabel","label","String","defaultFilter","query","itemToLabel","toLowerCase","includes","FilterableSelectMobile","props","local","itemToValue","filter","inputEl","filteredItems","q","trim","list","items","handleOpenChange","isOpen","autoFocus","queueMicrotask","focus","_jsx","Root","_mergeProps","onValueChange","onOpenChange","children","Trigger","placeholder","Content","clearable","clearLabel","backdropClassName","backdropStyle","_el0","_el1","firstChild","_el2","nextSibling","_setProp","el","e","target","stopPropagation","preventScroll","_insert","preventDefault","length","map","Item","key"],"sources":["../../src/components/FilterableSelectMobile.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createSignal, splitProps } from '@plastic-js/plastic'\nimport { SelectMobile } from './SelectMobile/index.jsx'\n\n// ── Styles ───────────────────────────────────────────────────────────────\nconst inputWrapperClass = css({\n\tposition: 'relative',\n\tmarginBottom: '6px',\n})\n\nconst inputClass = css({\n\twidth: '100%',\n\theight: '42px',\n\tpadding: '0 36px 0 14px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\toutline: 'none',\n\tboxSizing: 'border-box',\n\t'&:focus': { borderColor: 'var(--accent)' },\n\t'&::placeholder': { color: 'var(--muted)' },\n})\n\nconst clearButtonClass = css({\n\tposition: 'absolute',\n\tright: '8px',\n\ttop: '50%',\n\ttransform: 'translateY(-50%)',\n\twidth: '24px',\n\theight: '24px',\n\tpadding: '4px',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'center',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderRadius: '4px',\n\tcolor: 'var(--muted)',\n\tcursor: 'pointer',\n\t'&:hover': { color: 'var(--ink)' },\n\t'& svg': { width: '100%', height: '100%' },\n})\n\nfunction XIcon(){\n\treturn (\n\t\t<svg\n\t\t\tfill='none' stroke='currentColor' strokeLinecap='round' strokeLinejoin='round'\n\t\t\tstrokeWidth='2' viewBox='0 0 24 24'\n\t\t>\n\t\t\t<line x1='18' y1='6' x2='6' y2='18' />\n\t\t\t<line x1='6' y1='6' x2='18' y2='18' />\n\t\t</svg>\n\t)\n}\n\nconst noResultsClass = css({\n\tpadding: '20px 14px',\n\ttextAlign: 'center',\n\tcolor: 'var(--muted)',\n\tfontSize: '14px',\n})\n\n// ── Default accessors ────────────────────────────────────────────────────\nconst defaultItemToValue = item=> item?.value ?? item\nconst defaultItemToLabel = item=> item?.label ?? String(item)\nconst defaultFilter = (item, query, itemToLabel)=> itemToLabel(item).toLowerCase().includes(query)\n\n// ── FilterableSelectMobile ───────────────────────────────────────────────\n//\n// A mobile bottom-sheet select with a filter input at the top of the list.\n// Wraps SelectMobile internally — exposes a flat single-component API.\n//\n// Props:\n// items data array (or getter)\n// value current value (string | getter)\n// onValueChange (value) => void\n// itemToValue (item) => string — default item.value ?? item\n// itemToLabel (item) => string — default item.label ?? String(item)\n// placeholder trigger placeholder text — default \"Select\"\n// filter (item, query, itemToLabel) => boolean — default substring match\n// clearable show a \"clear\" row\n// clearLabel label for the clear row\n// backdropClassName className for the backdrop\n// backdropStyle inline style for the backdrop\n// autoFocus auto-focus the filter input when sheet opens — default false\nconst FilterableSelectMobile = (props)=> {\n\tconst [local] = splitProps(props, [\n\t\t'items', 'value', 'onValueChange',\n\t\t'itemToValue', 'itemToLabel',\n\t\t'placeholder', 'filter',\n\t\t'clearable', 'clearLabel',\n\t\t'backdropClassName', 'backdropStyle',\n\t\t'autoFocus',\n\t])\n\n\tconst itemToValue = local.itemToValue ?? defaultItemToValue\n\tconst itemToLabel = local.itemToLabel ?? defaultItemToLabel\n\tconst filter = local.filter ?? defaultFilter\n\n\tconst query = createSignal('')\n\tlet inputEl = null\n\n\t// Reactive filter — recomputes on typing and items changes.\n\tconst filteredItems = ()=> {\n\t\tconst q = query().trim().toLowerCase()\n\t\tconst list = typeof local.items === 'function' ? local.items() : (local.items ?? [])\n\t\treturn q ? list.filter(item=> filter(item, q, itemToLabel)) : list\n\t}\n\n\t// Auto-focus the input when the sheet opens; clear query on close.\n\tconst handleOpenChange = (isOpen)=> {\n\t\tif (isOpen){\n\t\t\tif (local.autoFocus) queueMicrotask(()=> inputEl?.focus())\n\t\t} else {\n\t\t\tquery('')\n\t\t}\n\t}\n\n\treturn (\n\t\t<SelectMobile.Root\n\t\t\tvalue={local.value}\n\t\t\tonValueChange={local.onValueChange}\n\t\t\titems={local.items}\n\t\t\titemToValue={itemToValue}\n\t\t\titemToLabel={itemToLabel}\n\t\t\tonOpenChange={handleOpenChange}\n\t\t>\n\t\t\t<SelectMobile.Trigger placeholder={local.placeholder} />\n\t\t\t<SelectMobile.Content\n\t\t\t\tclearable={local.clearable}\n\t\t\t\tclearLabel={local.clearLabel}\n\t\t\t\tbackdropClassName={local.backdropClassName}\n\t\t\t\tbackdropStyle={local.backdropStyle}\n\t\t\t>\n\t\t\t\t<div className={inputWrapperClass}>\n\t\t\t\t\t<input\n\t\t\t\t\t\tref={el=> { inputEl = el }}\n\t\t\t\t\t\ttype='text'\n\t\t\t\t\t\tclassName={inputClass}\n\t\t\t\t\t\tplaceholder='Filter…'\n\t\t\t\t\t\tvalue={query}\n\t\t\t\t\t\tonInput={e=> query(e.target.value)}\n\t\t\t\t\t\tonClick={e=> e.stopPropagation()}\n\t\t\t\t\t\tonPointerDown={e=> {\n\t\t\t\t\t\t\t// Defense-in-depth for Chrome iOS (WebKit) focus-lock bug.\n\t\t\t\t\t\t\t// The primary fix is in SelectMobile.Content (no <Portal>).\n\t\t\t\t\t\t\t// This handler ensures focus moves to the input even if a\n\t\t\t\t\t\t\t// previous button element still holds focus.\n\t\t\t\t\t\t\te.target.focus({ preventScroll: true })\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tclassName={clearButtonClass}\n\t\t\t\t\t\tonClick={e=> {\n\t\t\t\t\t\t\te.stopPropagation()\n\t\t\t\t\t\t\tquery('')\n\t\t\t\t\t\t\tinputEl?.focus()\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonPointerDown={e=> e.preventDefault()}\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\taria-label='Clear search'\n\t\t\t\t\t>\n\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t{()=> {\n\t\t\t\t\tconst list = filteredItems()\n\t\t\t\t\tif (list.length === 0){\n\t\t\t\t\t\treturn <div className={noResultsClass}>No results</div>\n\t\t\t\t\t}\n\t\t\t\t\treturn list.map(item => (\n\t\t\t\t\t\t<SelectMobile.Item item={item} key={itemToValue(item)} />\n\t\t\t\t\t))\n\t\t\t\t}}\n\t\t\t</SelectMobile.Content>\n\t\t</SelectMobile.Root>\n\t)\n}\n\nexport default FilterableSelectMobile"],"mappings":"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"}
1
+ {"version":3,"file":"FilterableSelectMobile.js","names":["css","createSignal","splitProps","SelectMobile","_tmpl3","_template","_tmpl2","_tmpl","inputWrapperClass","position","marginBottom","visibility","inputClass","width","height","padding","background","border","borderRadius","color","fontSize","fontFamily","outline","boxSizing","borderColor","clearButtonClass","right","top","transform","display","alignItems","justifyContent","cursor","XIcon","cloneNode","noResultsClass","textAlign","defaultItemToValue","item","value","defaultItemToLabel","label","String","defaultFilter","query","itemToLabel","toLowerCase","includes","FilterableSelectMobile","props","local","itemToValue","filter","inputEl","filteredItems","q","trim","list","items","handleOpenChange","isOpen","autoFocus","queueMicrotask","focus","_jsx","Root","_mergeProps","onValueChange","onOpenChange","children","Trigger","placeholder","Content","clearable","clearLabel","backdropClassName","backdropStyle","_el0","_el1","firstChild","_el2","nextSibling","_setProp","el","e","target","stopPropagation","preventScroll","_insert","preventDefault","length","map","Item","key"],"sources":["../../src/components/FilterableSelectMobile.jsx"],"sourcesContent":["import { css } from '@emotion/css'\nimport { createSignal, splitProps } from '@plastic-js/plastic'\nimport { SelectMobile } from './SelectMobile/index.jsx'\n\n// ── Styles ───────────────────────────────────────────────────────────────\nconst inputWrapperClass = css({\n\tposition: 'relative',\n\tmarginBottom: '6px',\n\t'& button': { visibility: 'hidden' },\n\t'&:focus-within button': { visibility: 'visible' },\n})\n\nconst inputClass = css({\n\twidth: '100%',\n\theight: '42px',\n\tpadding: '0 36px 0 14px',\n\tbackground: 'rgba(255,255,255,0.06)',\n\tborder: '1px solid var(--border)',\n\tborderRadius: '10px',\n\tcolor: 'var(--ink)',\n\tfontSize: '16px',\n\tfontFamily: 'inherit',\n\toutline: 'none',\n\tboxSizing: 'border-box',\n\t'&:focus': { borderColor: 'var(--accent)' },\n\t'&::placeholder': { color: 'var(--muted)' },\n})\n\nconst clearButtonClass = css({\n\tposition: 'absolute',\n\tright: '8px',\n\ttop: '50%',\n\ttransform: 'translateY(-50%)',\n\twidth: '24px',\n\theight: '24px',\n\tpadding: '4px',\n\tdisplay: 'flex',\n\talignItems: 'center',\n\tjustifyContent: 'center',\n\tbackground: 'none',\n\tborder: 'none',\n\tborderRadius: '4px',\n\tcolor: 'var(--muted)',\n\tcursor: 'pointer',\n\t'&:hover': { color: 'var(--ink)' },\n\t'& svg': { width: '100%', height: '100%' },\n})\n\nfunction XIcon(){\n\treturn (\n\t\t<svg\n\t\t\tfill='none' stroke='currentColor' strokeLinecap='round' strokeLinejoin='round'\n\t\t\tstrokeWidth='2' viewBox='0 0 24 24'\n\t\t>\n\t\t\t<line x1='18' y1='6' x2='6' y2='18' />\n\t\t\t<line x1='6' y1='6' x2='18' y2='18' />\n\t\t</svg>\n\t)\n}\n\nconst noResultsClass = css({\n\tpadding: '20px 14px',\n\ttextAlign: 'center',\n\tcolor: 'var(--muted)',\n\tfontSize: '14px',\n})\n\n// ── Default accessors ────────────────────────────────────────────────────\nconst defaultItemToValue = item=> item?.value ?? item\nconst defaultItemToLabel = item=> item?.label ?? String(item)\nconst defaultFilter = (item, query, itemToLabel)=> itemToLabel(item).toLowerCase().includes(query)\n\n// ── FilterableSelectMobile ───────────────────────────────────────────────\n//\n// A mobile bottom-sheet select with a filter input at the top of the list.\n// Wraps SelectMobile internally — exposes a flat single-component API.\n//\n// Props:\n// items data array (or getter)\n// value current value (string | getter)\n// onValueChange (value) => void\n// itemToValue (item) => string — default item.value ?? item\n// itemToLabel (item) => string — default item.label ?? String(item)\n// placeholder trigger placeholder text — default \"Select\"\n// filter (item, query, itemToLabel) => boolean — default substring match\n// clearable show a \"clear\" row\n// clearLabel label for the clear row\n// backdropClassName className for the backdrop\n// backdropStyle inline style for the backdrop\n// autoFocus auto-focus the filter input when sheet opens — default false\nconst FilterableSelectMobile = (props)=> {\n\tconst [local] = splitProps(props, [\n\t\t'items', 'value', 'onValueChange',\n\t\t'itemToValue', 'itemToLabel',\n\t\t'placeholder', 'filter',\n\t\t'clearable', 'clearLabel',\n\t\t'backdropClassName', 'backdropStyle',\n\t\t'autoFocus',\n\t])\n\n\tconst itemToValue = local.itemToValue ?? defaultItemToValue\n\tconst itemToLabel = local.itemToLabel ?? defaultItemToLabel\n\tconst filter = local.filter ?? defaultFilter\n\n\tconst query = createSignal('')\n\tlet inputEl = null\n\n\t// Reactive filter — recomputes on typing and items changes.\n\tconst filteredItems = ()=> {\n\t\tconst q = query().trim().toLowerCase()\n\t\tconst list = typeof local.items === 'function' ? local.items() : (local.items ?? [])\n\t\treturn q ? list.filter(item=> filter(item, q, itemToLabel)) : list\n\t}\n\n\t// Auto-focus the input when the sheet opens; clear query on close.\n\tconst handleOpenChange = (isOpen)=> {\n\t\tif (isOpen){\n\t\t\tif (local.autoFocus) queueMicrotask(()=> inputEl?.focus())\n\t\t} else {\n\t\t\tquery('')\n\t\t}\n\t}\n\n\treturn (\n\t\t<SelectMobile.Root\n\t\t\tvalue={local.value}\n\t\t\tonValueChange={local.onValueChange}\n\t\t\titems={local.items}\n\t\t\titemToValue={itemToValue}\n\t\t\titemToLabel={itemToLabel}\n\t\t\tonOpenChange={handleOpenChange}\n\t\t>\n\t\t\t<SelectMobile.Trigger placeholder={local.placeholder} />\n\t\t\t<SelectMobile.Content\n\t\t\t\tclearable={local.clearable}\n\t\t\t\tclearLabel={local.clearLabel}\n\t\t\t\tbackdropClassName={local.backdropClassName}\n\t\t\t\tbackdropStyle={local.backdropStyle}\n\t\t\t>\n\t\t\t\t<div className={inputWrapperClass}>\n\t\t\t\t\t<input\n\t\t\t\t\t\tref={el=> { inputEl = el }}\n\t\t\t\t\t\ttype='text'\n\t\t\t\t\t\tclassName={inputClass}\n\t\t\t\t\t\tplaceholder='Filter…'\n\t\t\t\t\t\tvalue={query}\n\t\t\t\t\t\tonInput={e=> query(e.target.value)}\n\t\t\t\t\t\tonClick={e=> e.stopPropagation()}\n\t\t\t\t\t\tonPointerDown={e=> {\n\t\t\t\t\t\t\t// Defense-in-depth for Chrome iOS (WebKit) focus-lock bug.\n\t\t\t\t\t\t\t// The primary fix is in SelectMobile.Content (no <Portal>).\n\t\t\t\t\t\t\t// This handler ensures focus moves to the input even if a\n\t\t\t\t\t\t\t// previous button element still holds focus.\n\t\t\t\t\t\t\te.target.focus({ preventScroll: true })\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype='button'\n\t\t\t\t\t\tclassName={clearButtonClass}\n\t\t\t\t\t\tonClick={e=> {\n\t\t\t\t\t\t\te.stopPropagation()\n\t\t\t\t\t\t\tquery('')\n\t\t\t\t\t\t\tinputEl?.focus()\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonPointerDown={e=> e.preventDefault()}\n\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\taria-label='Clear search'\n\t\t\t\t\t>\n\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t{()=> {\n\t\t\t\t\tconst list = filteredItems()\n\t\t\t\t\tif (list.length === 0){\n\t\t\t\t\t\treturn <div className={noResultsClass}>No results</div>\n\t\t\t\t\t}\n\t\t\t\t\treturn list.map(item => (\n\t\t\t\t\t\t<SelectMobile.Item item={item} key={itemToValue(item)} />\n\t\t\t\t\t))\n\t\t\t\t}}\n\t\t\t</SelectMobile.Content>\n\t\t</SelectMobile.Root>\n\t)\n}\n\nexport default FilterableSelectMobile"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import Dialog_default from "./components/Dialog.js";
13
13
  import ConfirmDialog from "./components/ConfirmDialog.js";
14
14
  import DateInput_default from "./components/DateInput.js";
15
15
  import DatePicker_default from "./components/DatePicker.js";
16
+ import DatePickerMobile from "./components/DatePickerMobile/index.js";
16
17
  import Drawer_default from "./components/Drawer.js";
17
18
  import Field_default from "./components/Field.js";
18
19
  import Fieldset_default from "./components/Fieldset.js";
@@ -49,4 +50,4 @@ import ToggleGroup_default from "./components/ToggleGroup.js";
49
50
  import Tooltip_default from "./components/Tooltip.js";
50
51
  import Tour_default from "./components/Tour.js";
51
52
  import TreeView_default from "./components/TreeView.js";
52
- export { Accordion_default as Accordion, Avatar_default as Avatar, CardNumberInput, Carousel_default as Carousel, Checkbox_default as Checkbox, Clipboard_default as Clipboard, Collapsible_default as Collapsible, ColorPicker_default as ColorPicker, Combobox_default as Combobox, ConfirmDialog, DateInput_default as DateInput, DatePicker_default as DatePicker, Dialog_default as Dialog, Drawer_default as Drawer, Field_default as Field, Fieldset_default as Fieldset, FileUpload_default as FileUpload, FilterableSelect, FilterableSelectMobile, FocusTrap_default as FocusTrap, HoverCard_default as HoverCard, Icon, Listbox_default as Listbox, Menu_default as Menu, MoneyInput, NumberInput_default as NumberInput, Pagination_default as Pagination, Popover_default as Popover, Portal_default as Portal, Presence_default as Presence, Progress_default as Progress, RadioGroup_default as RadioGroup, RatingGroup_default as RatingGroup, SearchInput, Select_default as Select, SelectMobile, SignaturePad_default as SignaturePad, Skeleton, Slider_default as Slider, Splitter_default as Splitter, Steps_default as Steps, SwipeReveal, Switch_default as Switch, Tabs_default as Tabs, TagsInput_default as TagsInput, Toast_default as Toast, Toggle_default as Toggle, ToggleGroup_default as ToggleGroup, Tooltip_default as Tooltip, Tour_default as Tour, TreeView_default as TreeView };
53
+ export { Accordion_default as Accordion, Avatar_default as Avatar, CardNumberInput, Carousel_default as Carousel, Checkbox_default as Checkbox, Clipboard_default as Clipboard, Collapsible_default as Collapsible, ColorPicker_default as ColorPicker, Combobox_default as Combobox, ConfirmDialog, DateInput_default as DateInput, DatePicker_default as DatePicker, DatePickerMobile, Dialog_default as Dialog, Drawer_default as Drawer, Field_default as Field, Fieldset_default as Fieldset, FileUpload_default as FileUpload, FilterableSelect, FilterableSelectMobile, FocusTrap_default as FocusTrap, HoverCard_default as HoverCard, Icon, Listbox_default as Listbox, Menu_default as Menu, MoneyInput, NumberInput_default as NumberInput, Pagination_default as Pagination, Popover_default as Popover, Portal_default as Portal, Presence_default as Presence, Progress_default as Progress, RadioGroup_default as RadioGroup, RatingGroup_default as RatingGroup, SearchInput, Select_default as Select, SelectMobile, SignaturePad_default as SignaturePad, Skeleton, Slider_default as Slider, Splitter_default as Splitter, Steps_default as Steps, SwipeReveal, Switch_default as Switch, Tabs_default as Tabs, TagsInput_default as TagsInput, Toast_default as Toast, Toggle_default as Toggle, ToggleGroup_default as ToggleGroup, Tooltip_default as Tooltip, Tour_default as Tour, TreeView_default as TreeView };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plastic-js/tsumiki",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "A UI component library for Plastic JS.",
5
5
  "license": "MIT",
6
6
  "author": "tigre",