@plastic-js/tsumiki 0.1.71 → 0.1.73

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.
@@ -44,7 +44,7 @@ var iconClass = css({
44
44
  height: "22px"
45
45
  });
46
46
  var BackToTop = (props = {}) => {
47
- const [local] = splitProps(mergeProps$1({ threshold: 200 }, props), [
47
+ const [local] = splitProps(mergeProps$1({ threshold: 350 }, props), [
48
48
  "className",
49
49
  "threshold",
50
50
  "target",
@@ -35,6 +35,11 @@ var formatDateLabel = (date) => {
35
35
  if (!date) return "";
36
36
  return `${MONTH_NAMES_SHORT[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
37
37
  };
38
+ var toISO = (date) => {
39
+ const m = String(date.getMonth() + 1).padStart(2, "0");
40
+ const d = String(date.getDate()).padStart(2, "0");
41
+ return `${date.getFullYear()}-${m}-${d}`;
42
+ };
38
43
  var parseDate = (v) => {
39
44
  if (!v) return null;
40
45
  if (v instanceof Date) return isNaN(v.getTime()) ? null : v;
@@ -331,7 +336,7 @@ var DatePicker = (props = {}) => {
331
336
  const confirm = () => {
332
337
  const date = toDate(tempYear(), tempMonth(), tempDay());
333
338
  selectedValue(date);
334
- local.onValueChange?.(date);
339
+ local.onValueChange?.(toISO(date));
335
340
  closeSheet();
336
341
  };
337
342
  const cancel = () => {
@@ -0,0 +1,224 @@
1
+ import { jsx, mergeProps, setProp, template } from "@plastic-js/plastic/jsx-runtime";
2
+ import { css } from "@emotion/css";
3
+ import { Loop, mergeProps as mergeProps$1, splitProps } from "@plastic-js/plastic";
4
+ //#region src/components/PinInput.jsx
5
+ var _tmpl = template("<input maxLength=\"1\">");
6
+ var read = (v) => typeof v === "function" ? v() : v;
7
+ var rootClass = css({
8
+ display: "inline-flex",
9
+ alignItems: "center",
10
+ gap: "var(--tsu-spacing-sm)",
11
+ fontFamily: "inherit"
12
+ });
13
+ var sizeClasses = {
14
+ xs: css({
15
+ "--_pin-box": "var(--tsu-comp-height-xs)",
16
+ "--_pin-font": "var(--tsu-comp-font-size-xs)",
17
+ "--_pin-radius": "var(--tsu-radius-l1-xs)"
18
+ }),
19
+ sm: css({
20
+ "--_pin-box": "var(--tsu-comp-height-sm)",
21
+ "--_pin-font": "var(--tsu-comp-font-size-sm)",
22
+ "--_pin-radius": "var(--tsu-radius-l1-sm)"
23
+ }),
24
+ md: css({
25
+ "--_pin-box": "var(--tsu-comp-height-md)",
26
+ "--_pin-font": "var(--tsu-comp-font-size-md)",
27
+ "--_pin-radius": "var(--tsu-radius-l1-md)"
28
+ }),
29
+ lg: css({
30
+ "--_pin-box": "var(--tsu-comp-height-lg)",
31
+ "--_pin-font": "var(--tsu-comp-font-size-lg)",
32
+ "--_pin-radius": "var(--tsu-radius-l1-lg)"
33
+ }),
34
+ xl: css({
35
+ "--_pin-box": "var(--tsu-comp-height-xl)",
36
+ "--_pin-font": "var(--tsu-comp-font-size-xl)",
37
+ "--_pin-radius": "var(--tsu-radius-l1-xl)"
38
+ })
39
+ };
40
+ var variantClasses = {
41
+ solid: css({
42
+ backgroundColor: "var(--tsu-bg-control)",
43
+ border: "1px solid transparent"
44
+ }),
45
+ outline: css({ border: "1px solid var(--_pin-border)" })
46
+ };
47
+ var intentClasses = {
48
+ default: css({
49
+ "--_pin-border": "var(--tsu-accent-outline-border)",
50
+ "--_pin-border-focus": "var(--tsu-accent-outline-border-hover)"
51
+ }),
52
+ neutral: css({
53
+ "--_pin-border": "var(--tsu-neutral-outline-border)",
54
+ "--_pin-border-focus": "var(--tsu-neutral-outline-border-hover)"
55
+ })
56
+ };
57
+ var boxBaseClass = css({
58
+ width: "var(--_pin-box, var(--tsu-comp-height-md))",
59
+ height: "var(--_pin-box, var(--tsu-comp-height-md))",
60
+ padding: 0,
61
+ borderRadius: "var(--_pin-radius, var(--tsu-radius-l1-md))",
62
+ color: "var(--tsu-fg)",
63
+ fontFamily: "inherit",
64
+ fontSize: "var(--_pin-font, var(--tsu-comp-font-size-md))",
65
+ fontWeight: 600,
66
+ textAlign: "center",
67
+ WebkitAppearance: "none",
68
+ appearance: "none",
69
+ outline: "none",
70
+ touchAction: "manipulation",
71
+ transition: "border-color var(--tsu-transition-fast), background-color var(--tsu-transition-fast), box-shadow var(--tsu-transition-fast)",
72
+ "&:focus": {
73
+ borderColor: "var(--_pin-border-focus, var(--tsu-accent-outline-border-hover))",
74
+ backgroundColor: "var(--tsu-focus-bg)",
75
+ boxShadow: "0 0 0 1px var(--_pin-border-focus, var(--tsu-accent-outline-border-hover))"
76
+ }
77
+ });
78
+ var errorClass = css({
79
+ borderColor: "var(--tsu-danger-outline-border) !important",
80
+ "&:focus": {
81
+ borderColor: "var(--tsu-danger-outline-border) !important",
82
+ boxShadow: "0 0 0 1px var(--tsu-danger-outline-border) !important"
83
+ }
84
+ });
85
+ var disabledClass = css({
86
+ opacity: "var(--tsu-disabled-opacity)",
87
+ cursor: "not-allowed"
88
+ });
89
+ var PinInput = (props = {}) => {
90
+ const [local, rest] = splitProps(mergeProps$1({
91
+ length: 4,
92
+ size: "md",
93
+ type: "numeric",
94
+ variant: "outline",
95
+ intent: "default",
96
+ mask: false,
97
+ disabled: false,
98
+ invalid: false
99
+ }, props), [
100
+ "value",
101
+ "onValueChange",
102
+ "onComplete",
103
+ "length",
104
+ "size",
105
+ "type",
106
+ "variant",
107
+ "intent",
108
+ "mask",
109
+ "disabled",
110
+ "invalid",
111
+ "className",
112
+ "inputClassName"
113
+ ]);
114
+ const refs = {};
115
+ const boxSize = () => read(local.length) || 4;
116
+ const isNumeric = () => read(local.type) === "numeric";
117
+ const value = () => (read(local.value) || "").slice(0, boxSize());
118
+ const clean = (str) => {
119
+ if (!str) return "";
120
+ return isNumeric() ? str.replace(/\D/g, "") : str.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
121
+ };
122
+ const focusBox = (index) => {
123
+ const el = refs[index];
124
+ if (el && typeof el.focus === "function") el.focus();
125
+ };
126
+ const commit = (next) => {
127
+ local.onValueChange?.(next);
128
+ if (next.length === boxSize()) local.onComplete?.(next);
129
+ };
130
+ const handleInput = (index) => (e) => {
131
+ const char = clean(e.target.value).slice(0, 1);
132
+ const base = value();
133
+ const next = base.slice(0, index) + char + base.slice(index + 1);
134
+ if (char && index < boxSize() - 1) focusBox(index + 1);
135
+ commit(next);
136
+ };
137
+ const handleKeyDown = (index) => (e) => {
138
+ if (e.key === "Backspace" && !e.target.value && index > 0) {
139
+ e.preventDefault();
140
+ const prev = index - 1;
141
+ const base = value();
142
+ commit(base.slice(0, prev) + base.slice(prev + 1));
143
+ focusBox(prev);
144
+ return;
145
+ }
146
+ if (e.key === "ArrowLeft" && index > 0) {
147
+ e.preventDefault();
148
+ focusBox(index - 1);
149
+ return;
150
+ }
151
+ if (e.key === "ArrowRight" && index < boxSize() - 1) {
152
+ e.preventDefault();
153
+ focusBox(index + 1);
154
+ return;
155
+ }
156
+ if (e.key === "Home") {
157
+ e.preventDefault();
158
+ focusBox(0);
159
+ return;
160
+ }
161
+ if (e.key === "End") {
162
+ e.preventDefault();
163
+ focusBox(boxSize() - 1);
164
+ }
165
+ };
166
+ const handlePaste = (index) => (e) => {
167
+ e.preventDefault();
168
+ const text = clean(e.clipboardData?.getData("text")?.trim());
169
+ if (!text) return;
170
+ const base = value();
171
+ commit((base.slice(0, index) + text + base.slice(index + text.length)).slice(0, boxSize()));
172
+ focusBox(Math.min(index + text.length, boxSize() - 1));
173
+ };
174
+ const handleFocus = (e) => e.target.select();
175
+ const boxClassName = (index) => {
176
+ const variant = read(local.variant) === "solid" ? "solid" : "outline";
177
+ let intent = read(local.intent);
178
+ if (intent === "neutral" && variant === "solid") intent = "default";
179
+ return [
180
+ boxBaseClass,
181
+ variantClasses[variant],
182
+ intentClasses[intent] ?? intentClasses.default,
183
+ read(local.invalid) && errorClass,
184
+ read(local.disabled) && disabledClass,
185
+ read(local.inputClassName)
186
+ ].filter(Boolean).join(" ");
187
+ };
188
+ return jsx("div", mergeProps({ className: () => [
189
+ rootClass,
190
+ sizeClasses[read(local.size)] ?? sizeClasses.md,
191
+ read(local.className)
192
+ ].filter(Boolean).join(" ") }, rest, { children: jsx(Loop, mergeProps({
193
+ each: () => Array.from({ length: boxSize() }),
194
+ children: (_, indexSignal) => {
195
+ const index = indexSignal();
196
+ return (() => {
197
+ const _el0 = _tmpl.cloneNode(true);
198
+ setProp(_el0, "key", () => index);
199
+ setProp(_el0, "ref", (el) => {
200
+ refs[index] = el;
201
+ });
202
+ setProp(_el0, "type", () => read(local.mask) ? "password" : "text");
203
+ setProp(_el0, "inputMode", () => isNumeric() ? "numeric" : void 0);
204
+ setProp(_el0, "autoComplete", () => index === 0 ? "one-time-code" : void 0);
205
+ setProp(_el0, "aria-label", () => `Character ${index + 1} of ${boxSize()}`);
206
+ setProp(_el0, "aria-invalid", () => read(local.invalid) ? "true" : "false");
207
+ setProp(_el0, "data-invalid", () => read(local.invalid) ? "" : void 0);
208
+ setProp(_el0, "value", () => {
209
+ read(local.mask);
210
+ return value()[index] || "";
211
+ });
212
+ setProp(_el0, "onInput", () => handleInput(index));
213
+ setProp(_el0, "onKeyDown", () => handleKeyDown(index));
214
+ setProp(_el0, "onPaste", () => handlePaste(index));
215
+ setProp(_el0, "onFocus", () => handleFocus);
216
+ setProp(_el0, "disabled", () => read(local.disabled));
217
+ setProp(_el0, "className", () => boxClassName(index));
218
+ return _el0;
219
+ })();
220
+ }
221
+ })) }));
222
+ };
223
+ //#endregion
224
+ export { PinInput as default };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ import Menu, { MenuContent, MenuItem, MenuSeparator, MenuTrigger } from "./compo
32
32
  import MoneyInput from "./components/MoneyInput.js";
33
33
  import NumberInput from "./components/NumberInput.js";
34
34
  import Pagination from "./components/Pagination.js";
35
+ import PinInput from "./components/PinInput.js";
35
36
  import Popover from "./components/Popover.js";
36
37
  import Presence_default from "./components/Presence.js";
37
38
  import Progress, { ProgressLabel } from "./components/Progress.js";
@@ -58,4 +59,4 @@ import ToggleGroup, { ToggleGroupItem } from "./components/ToggleGroup.js";
58
59
  import FilterGroup from "./components/FilterGroup.js";
59
60
  import Tour, { TourCloseTrigger, TourContent } from "./components/Tour.js";
60
61
  import TreeView, { TreeViewBranch, TreeViewBranchContent, TreeViewBranchControl, TreeViewBranchTrigger, TreeViewItem } from "./components/TreeView.js";
61
- export { AccordionRoot as Accordion, AccordionContent, AccordionItem, AccordionTrigger, Avatar, AvatarFallback, AvatarImage, BackToTop, Badge, BottomNavigation, BottomNavigationItem, BottomSheet, Button, Card, CardNumberInput, Carousel_default as Carousel, CarouselAutoplayTrigger, CarouselControl, CarouselIndicator, CarouselIndicatorGroup, CarouselItem, CarouselItemGroup, CarouselNextTrigger, CarouselPrevTrigger, CarouselProgressText, Checkbox, ClearTrigger, Clipboard, CloseButton, Collapsible, CollapsibleContent, CollapsibleTrigger, ColorPicker, Root as Combobox, ComboboxContent, Input as ComboboxInput, ComboboxItem, ConfirmDialog, DatePicker, Dialog, Root$1 as Drawer, DrawerContent, DrawerTrigger, Field, Fieldset, FileUpload, FileUploadClearTrigger, FileUploadItem, FileUploadItemGroup, FilterGroup, FocusTrap_default as FocusTrap, Icon, Input$1 as Input, Link, Listbox, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, MoneyInput, NumberInput, Pagination, Popover, Portal_default as Portal, Presence_default as Presence, Progress, ProgressLabel, RadioGroup, RatingGroup, SafeArea, SearchInput, Select, SelectItem, SelectPc, SelectTrigger, SignaturePad, Skeleton, Slider, Spinner, Splitter, SplitterPanel, SplitterResizeTrigger, SplitterResizeTriggerIndicator, Steps, StickyHeader, SwipeReveal, Switch, Tabs, Tag, TagsInput, Toast, ToastCloseTrigger, ToastDescription, ToastIcon, ToastTitle, ToastToaster, Toggle, ToggleGroup, ToggleGroupItem, Tour, TourCloseTrigger, TourContent, TreeView, TreeViewBranch, TreeViewBranchContent, TreeViewBranchControl, TreeViewBranchTrigger, TreeViewItem, confirm, createToaster };
62
+ export { AccordionRoot as Accordion, AccordionContent, AccordionItem, AccordionTrigger, Avatar, AvatarFallback, AvatarImage, BackToTop, Badge, BottomNavigation, BottomNavigationItem, BottomSheet, Button, Card, CardNumberInput, Carousel_default as Carousel, CarouselAutoplayTrigger, CarouselControl, CarouselIndicator, CarouselIndicatorGroup, CarouselItem, CarouselItemGroup, CarouselNextTrigger, CarouselPrevTrigger, CarouselProgressText, Checkbox, ClearTrigger, Clipboard, CloseButton, Collapsible, CollapsibleContent, CollapsibleTrigger, ColorPicker, Root as Combobox, ComboboxContent, Input as ComboboxInput, ComboboxItem, ConfirmDialog, DatePicker, Dialog, Root$1 as Drawer, DrawerContent, DrawerTrigger, Field, Fieldset, FileUpload, FileUploadClearTrigger, FileUploadItem, FileUploadItemGroup, FilterGroup, FocusTrap_default as FocusTrap, Icon, Input$1 as Input, Link, Listbox, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, MoneyInput, NumberInput, Pagination, PinInput, Popover, Portal_default as Portal, Presence_default as Presence, Progress, ProgressLabel, RadioGroup, RatingGroup, SafeArea, SearchInput, Select, SelectItem, SelectPc, SelectTrigger, SignaturePad, Skeleton, Slider, Spinner, Splitter, SplitterPanel, SplitterResizeTrigger, SplitterResizeTriggerIndicator, Steps, StickyHeader, SwipeReveal, Switch, Tabs, Tag, TagsInput, Toast, ToastCloseTrigger, ToastDescription, ToastIcon, ToastTitle, ToastToaster, Toggle, ToggleGroup, ToggleGroupItem, Tour, TourCloseTrigger, TourContent, TreeView, TreeViewBranch, TreeViewBranchContent, TreeViewBranchControl, TreeViewBranchTrigger, TreeViewItem, confirm, createToaster };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plastic-js/tsumiki",
3
- "version": "0.1.71",
3
+ "version": "0.1.73",
4
4
  "description": "A UI component library for Plastic JS.",
5
5
  "license": "MIT",
6
6
  "author": "tigre",