premium-ds 0.1.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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/alert.d.ts +31 -0
- package/dist/alert.js +6 -0
- package/dist/alert.js.map +1 -0
- package/dist/avatar-group.d.ts +13 -0
- package/dist/avatar-group.js +3 -0
- package/dist/avatar-group.js.map +1 -0
- package/dist/avatar.d.ts +25 -0
- package/dist/avatar.js +3 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.d.ts +23 -0
- package/dist/badge.js +3 -0
- package/dist/badge.js.map +1 -0
- package/dist/button.d.ts +20 -0
- package/dist/button.js +3 -0
- package/dist/button.js.map +1 -0
- package/dist/checkbox.d.ts +25 -0
- package/dist/checkbox.js +3 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-2OWHZ4JT.js +36 -0
- package/dist/chunk-2OWHZ4JT.js.map +1 -0
- package/dist/chunk-34SIXSYL.js +64 -0
- package/dist/chunk-34SIXSYL.js.map +1 -0
- package/dist/chunk-37O2ZXD6.js +55 -0
- package/dist/chunk-37O2ZXD6.js.map +1 -0
- package/dist/chunk-4AZL76UJ.js +89 -0
- package/dist/chunk-4AZL76UJ.js.map +1 -0
- package/dist/chunk-4HSCN5TZ.js +86 -0
- package/dist/chunk-4HSCN5TZ.js.map +1 -0
- package/dist/chunk-5DDOOT33.js +258 -0
- package/dist/chunk-5DDOOT33.js.map +1 -0
- package/dist/chunk-5FVHWIMY.js +117 -0
- package/dist/chunk-5FVHWIMY.js.map +1 -0
- package/dist/chunk-5K6KRJGX.js +147 -0
- package/dist/chunk-5K6KRJGX.js.map +1 -0
- package/dist/chunk-5PQMQBQC.js +74 -0
- package/dist/chunk-5PQMQBQC.js.map +1 -0
- package/dist/chunk-7OCTVQ7C.js +95 -0
- package/dist/chunk-7OCTVQ7C.js.map +1 -0
- package/dist/chunk-7OPMOET7.js +39 -0
- package/dist/chunk-7OPMOET7.js.map +1 -0
- package/dist/chunk-BXXS7YRC.js +270 -0
- package/dist/chunk-BXXS7YRC.js.map +1 -0
- package/dist/chunk-CV2Q4YXX.js +272 -0
- package/dist/chunk-CV2Q4YXX.js.map +1 -0
- package/dist/chunk-EIMMDWIW.js +282 -0
- package/dist/chunk-EIMMDWIW.js.map +1 -0
- package/dist/chunk-EZ2CWTBE.js +230 -0
- package/dist/chunk-EZ2CWTBE.js.map +1 -0
- package/dist/chunk-FGHDG3Y4.js +89 -0
- package/dist/chunk-FGHDG3Y4.js.map +1 -0
- package/dist/chunk-FPP2XLKX.js +127 -0
- package/dist/chunk-FPP2XLKX.js.map +1 -0
- package/dist/chunk-G6OY35DI.js +295 -0
- package/dist/chunk-G6OY35DI.js.map +1 -0
- package/dist/chunk-H6KWJNOE.js +65 -0
- package/dist/chunk-H6KWJNOE.js.map +1 -0
- package/dist/chunk-HGILYGY3.js +45 -0
- package/dist/chunk-HGILYGY3.js.map +1 -0
- package/dist/chunk-I3BCB4Z5.js +88 -0
- package/dist/chunk-I3BCB4Z5.js.map +1 -0
- package/dist/chunk-KBWNUUWM.js +582 -0
- package/dist/chunk-KBWNUUWM.js.map +1 -0
- package/dist/chunk-KN7JFAZ6.js +113 -0
- package/dist/chunk-KN7JFAZ6.js.map +1 -0
- package/dist/chunk-MEF7PI6U.js +16 -0
- package/dist/chunk-MEF7PI6U.js.map +1 -0
- package/dist/chunk-NKGMQL6I.js +310 -0
- package/dist/chunk-NKGMQL6I.js.map +1 -0
- package/dist/chunk-NMFQRGLL.js +127 -0
- package/dist/chunk-NMFQRGLL.js.map +1 -0
- package/dist/chunk-OUBWD6CX.js +433 -0
- package/dist/chunk-OUBWD6CX.js.map +1 -0
- package/dist/chunk-PFNXVBLU.js +96 -0
- package/dist/chunk-PFNXVBLU.js.map +1 -0
- package/dist/chunk-PUPZ4HME.js +165 -0
- package/dist/chunk-PUPZ4HME.js.map +1 -0
- package/dist/chunk-QFS52OK5.js +690 -0
- package/dist/chunk-QFS52OK5.js.map +1 -0
- package/dist/chunk-QNC6O3PG.js +45 -0
- package/dist/chunk-QNC6O3PG.js.map +1 -0
- package/dist/chunk-QUHOXWBK.js +82 -0
- package/dist/chunk-QUHOXWBK.js.map +1 -0
- package/dist/chunk-UIQGSTBJ.js +106 -0
- package/dist/chunk-UIQGSTBJ.js.map +1 -0
- package/dist/chunk-UJQKVP6V.js +193 -0
- package/dist/chunk-UJQKVP6V.js.map +1 -0
- package/dist/chunk-VVPGEAC6.js +11 -0
- package/dist/chunk-VVPGEAC6.js.map +1 -0
- package/dist/chunk-XA3T5KWA.js +58 -0
- package/dist/chunk-XA3T5KWA.js.map +1 -0
- package/dist/chunk-YSHJHSJM.js +19 -0
- package/dist/chunk-YSHJHSJM.js.map +1 -0
- package/dist/chunk-YVHOAVSM.js +182 -0
- package/dist/chunk-YVHOAVSM.js.map +1 -0
- package/dist/collapse.d.ts +16 -0
- package/dist/collapse.js +3 -0
- package/dist/collapse.js.map +1 -0
- package/dist/count-badge.d.ts +11 -0
- package/dist/count-badge.js +4 -0
- package/dist/count-badge.js.map +1 -0
- package/dist/date-field.d.ts +39 -0
- package/dist/date-field.js +8 -0
- package/dist/date-field.js.map +1 -0
- package/dist/date-range-field.d.ts +30 -0
- package/dist/date-range-field.js +8 -0
- package/dist/date-range-field.js.map +1 -0
- package/dist/datetime-field.d.ts +28 -0
- package/dist/datetime-field.js +10 -0
- package/dist/datetime-field.js.map +1 -0
- package/dist/dialog.d.ts +26 -0
- package/dist/dialog.js +7 -0
- package/dist/dialog.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/motion-tokens.d.ts +29 -0
- package/dist/motion-tokens.js +3 -0
- package/dist/motion-tokens.js.map +1 -0
- package/dist/multi-select.d.ts +25 -0
- package/dist/multi-select.js +7 -0
- package/dist/multi-select.js.map +1 -0
- package/dist/number-field.d.ts +24 -0
- package/dist/number-field.js +4 -0
- package/dist/number-field.js.map +1 -0
- package/dist/otp-field.d.ts +20 -0
- package/dist/otp-field.js +3 -0
- package/dist/otp-field.js.map +1 -0
- package/dist/overlay.d.ts +31 -0
- package/dist/overlay.js +4 -0
- package/dist/overlay.js.map +1 -0
- package/dist/pagination.d.ts +24 -0
- package/dist/pagination.js +5 -0
- package/dist/pagination.js.map +1 -0
- package/dist/radio-group.d.ts +46 -0
- package/dist/radio-group.js +6 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/select-core-SAyS-8w0.d.ts +16 -0
- package/dist/select.d.ts +27 -0
- package/dist/select.js +7 -0
- package/dist/select.js.map +1 -0
- package/dist/status-badge.d.ts +17 -0
- package/dist/status-badge.js +5 -0
- package/dist/status-badge.js.map +1 -0
- package/dist/table.d.ts +65 -0
- package/dist/table.js +5 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.d.ts +44 -0
- package/dist/tabs.js +5 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tag.d.ts +28 -0
- package/dist/tag.js +5 -0
- package/dist/tag.js.map +1 -0
- package/dist/text-field.d.ts +30 -0
- package/dist/text-field.js +6 -0
- package/dist/text-field.js.map +1 -0
- package/dist/textarea.d.ts +33 -0
- package/dist/textarea.js +5 -0
- package/dist/textarea.js.map +1 -0
- package/dist/time-field.d.ts +27 -0
- package/dist/time-field.js +6 -0
- package/dist/time-field.js.map +1 -0
- package/dist/toast-store.d.ts +75 -0
- package/dist/toast-store.js +3 -0
- package/dist/toast-store.js.map +1 -0
- package/dist/toast.d.ts +3 -0
- package/dist/toast.js +6 -0
- package/dist/toast.js.map +1 -0
- package/dist/toggle-tag.d.ts +24 -0
- package/dist/toggle-tag.js +4 -0
- package/dist/toggle-tag.js.map +1 -0
- package/dist/toggle.d.ts +21 -0
- package/dist/toggle.js +3 -0
- package/dist/toggle.js.map +1 -0
- package/dist/tooltip.d.ts +27 -0
- package/dist/tooltip.js +4 -0
- package/dist/tooltip.js.map +1 -0
- package/llms.txt +165 -0
- package/package.json +205 -0
- package/src/components/alert/Alert.tsx +118 -0
- package/src/components/alert/alert.css +136 -0
- package/src/components/avatar/Avatar.tsx +128 -0
- package/src/components/avatar/AvatarGroup.tsx +50 -0
- package/src/components/avatar/avatar.css +200 -0
- package/src/components/badge/Badge.tsx +66 -0
- package/src/components/badge/CountBadge.tsx +46 -0
- package/src/components/badge/StatusBadge.tsx +132 -0
- package/src/components/badge/badge.css +243 -0
- package/src/components/button/Button.tsx +68 -0
- package/src/components/button/button.css +222 -0
- package/src/components/checkbox/Checkbox.tsx +90 -0
- package/src/components/checkbox/checkbox.css +179 -0
- package/src/components/date-picker/DateField.tsx +362 -0
- package/src/components/date-picker/DateRangeField.tsx +533 -0
- package/src/components/date-picker/DateTimeField.tsx +177 -0
- package/src/components/date-picker/TimeField.tsx +100 -0
- package/src/components/date-picker/date-picker.css +591 -0
- package/src/components/date-picker/date-utils.ts +55 -0
- package/src/components/date-picker/field-shell.tsx +78 -0
- package/src/components/date-picker/glide-pill.tsx +81 -0
- package/src/components/date-picker/time-core.tsx +305 -0
- package/src/components/dialog/Dialog.tsx +181 -0
- package/src/components/dialog/dialog.css +170 -0
- package/src/components/glass/glass.css +100 -0
- package/src/components/icon/Icon.tsx +76 -0
- package/src/components/icon/IconSlot.tsx +11 -0
- package/src/components/icon/icon.css +33 -0
- package/src/components/input/NumberField.tsx +117 -0
- package/src/components/input/OtpField.tsx +118 -0
- package/src/components/input/TextField.tsx +123 -0
- package/src/components/input/input.css +335 -0
- package/src/components/motion/Collapse.tsx +33 -0
- package/src/components/motion/collapse.css +41 -0
- package/src/components/overlay/Overlay.tsx +239 -0
- package/src/components/overlay/overlay-core.tsx +565 -0
- package/src/components/overlay/overlay.css +119 -0
- package/src/components/overlay/sheet-drag.tsx +146 -0
- package/src/components/pagination/Pagination.tsx +140 -0
- package/src/components/pagination/pagination.css +48 -0
- package/src/components/radio-group/RadioGroup.tsx +182 -0
- package/src/components/radio-group/radio-group.css +277 -0
- package/src/components/select/MultiSelect.tsx +251 -0
- package/src/components/select/Select.tsx +235 -0
- package/src/components/select/select-core.tsx +417 -0
- package/src/components/select/select.css +386 -0
- package/src/components/table/Table.tsx +433 -0
- package/src/components/table/table.css +348 -0
- package/src/components/tabs/Tabs.tsx +371 -0
- package/src/components/tabs/tabs.css +228 -0
- package/src/components/tag/Tag.tsx +145 -0
- package/src/components/tag/ToggleTag.tsx +125 -0
- package/src/components/tag/tag.css +248 -0
- package/src/components/textarea/Textarea.tsx +197 -0
- package/src/components/textarea/textarea.css +219 -0
- package/src/components/toast/Toast.tsx +349 -0
- package/src/components/toast/toast-store.ts +266 -0
- package/src/components/toast/toast.css +233 -0
- package/src/components/toggle/Toggle.tsx +94 -0
- package/src/components/toggle/toggle.css +152 -0
- package/src/components/tooltip/Tooltip.tsx +365 -0
- package/src/components/tooltip/tooltip.css +86 -0
- package/src/index.ts +42 -0
- package/src/styles.css +39 -0
- package/src/tokens/avatar.css +20 -0
- package/src/tokens/color.css +56 -0
- package/src/tokens/elevation.css +20 -0
- package/src/tokens/fonts.css +3 -0
- package/src/tokens/glass.css +21 -0
- package/src/tokens/icons.css +7 -0
- package/src/tokens/layers.css +6 -0
- package/src/tokens/motion-tokens.ts +72 -0
- package/src/tokens/motion.css +49 -0
- package/src/tokens/radius.css +11 -0
- package/src/tokens/semantic.css +75 -0
- package/src/tokens/spacing.css +26 -0
- package/src/tokens/typography.css +54 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use client';import { Icon } from './chunk-KBWNUUWM.js';
|
|
2
|
+
import { Collapse } from './chunk-YSHJHSJM.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var RING_C = (2 * Math.PI * 7).toFixed(2);
|
|
7
|
+
function Textarea({
|
|
8
|
+
id,
|
|
9
|
+
label,
|
|
10
|
+
required,
|
|
11
|
+
optional,
|
|
12
|
+
placeholder,
|
|
13
|
+
helper,
|
|
14
|
+
error,
|
|
15
|
+
warning,
|
|
16
|
+
success,
|
|
17
|
+
value = "",
|
|
18
|
+
onChange,
|
|
19
|
+
onSubmit,
|
|
20
|
+
max,
|
|
21
|
+
minRows = 3,
|
|
22
|
+
maxRows = 10,
|
|
23
|
+
warnAt = 20,
|
|
24
|
+
hint,
|
|
25
|
+
size,
|
|
26
|
+
disabled,
|
|
27
|
+
readOnly,
|
|
28
|
+
className = "",
|
|
29
|
+
...rest
|
|
30
|
+
}) {
|
|
31
|
+
const taRef = React.useRef(null);
|
|
32
|
+
const stackRef = React.useRef(null);
|
|
33
|
+
const mirrorRef = React.useRef(null);
|
|
34
|
+
const text = value ?? "";
|
|
35
|
+
const count = text.length;
|
|
36
|
+
const over = max ? Math.max(count - max, 0) : 0;
|
|
37
|
+
const remaining = max ? max - count : 0;
|
|
38
|
+
const meterState = over ? "is-over" : max && remaining <= warnAt ? "is-near" : "";
|
|
39
|
+
const state = error ? "is-error" : warning ? "is-warning" : success ? "is-success" : "";
|
|
40
|
+
const msg = error || warning || success || helper;
|
|
41
|
+
const msgIcon = error ? "warning-circle" : warning ? "warning" : success ? "check-circle" : null;
|
|
42
|
+
const resize = () => {
|
|
43
|
+
const el = taRef.current, stack = stackRef.current;
|
|
44
|
+
if (!el || !stack) return;
|
|
45
|
+
const start = stack.offsetHeight;
|
|
46
|
+
el.style.height = "auto";
|
|
47
|
+
el.style.height = el.scrollHeight + "px";
|
|
48
|
+
const content = el.offsetHeight;
|
|
49
|
+
const maxPx = parseFloat(getComputedStyle(stack).maxHeight) || Infinity;
|
|
50
|
+
const target = Math.min(content, maxPx);
|
|
51
|
+
if (target === start) {
|
|
52
|
+
stack.style.overflowY = content > maxPx ? "auto" : "clip";
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
stack.style.overflowY = "clip";
|
|
56
|
+
stack.style.height = start + "px";
|
|
57
|
+
void stack.offsetHeight;
|
|
58
|
+
stack.style.height = target + "px";
|
|
59
|
+
};
|
|
60
|
+
React.useLayoutEffect(resize, [text, size]);
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
window.addEventListener("resize", resize);
|
|
63
|
+
return () => window.removeEventListener("resize", resize);
|
|
64
|
+
}, []);
|
|
65
|
+
const onKeyDown = (e) => {
|
|
66
|
+
if (onSubmit && (e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
onSubmit(text);
|
|
69
|
+
}
|
|
70
|
+
rest.onKeyDown && rest.onKeyDown(e);
|
|
71
|
+
};
|
|
72
|
+
const cls = ["fld", "fld--txa", size === "lg" && "fld--lg", state, className].filter(Boolean).join(" ");
|
|
73
|
+
const boxCls = ["txa", disabled && "is-disabled", readOnly && "is-readonly"].filter(Boolean).join(" ");
|
|
74
|
+
return /* @__PURE__ */ jsxs("div", { className: cls, children: [
|
|
75
|
+
label && /* @__PURE__ */ jsxs("label", { className: "fld__label", htmlFor: id, children: [
|
|
76
|
+
label,
|
|
77
|
+
required && /* @__PURE__ */ jsx("span", { className: "fld__req", "aria-hidden": "true", children: "*" }),
|
|
78
|
+
optional && /* @__PURE__ */ jsx("span", { className: "fld__optional", children: "(optional)" })
|
|
79
|
+
] }),
|
|
80
|
+
/* @__PURE__ */ jsxs(
|
|
81
|
+
"div",
|
|
82
|
+
{
|
|
83
|
+
className: boxCls,
|
|
84
|
+
style: { "--txa-min-rows": minRows, "--txa-max-rows": maxRows },
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ jsxs("div", { className: "txa__stack", ref: stackRef, children: [
|
|
87
|
+
/* @__PURE__ */ jsxs("div", { className: "txa__mirror", ref: mirrorRef, "aria-hidden": "true", children: [
|
|
88
|
+
over ? text.slice(0, max) : text,
|
|
89
|
+
over ? /* @__PURE__ */ jsx("mark", { children: text.slice(max) }) : null,
|
|
90
|
+
"\n"
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx(
|
|
93
|
+
"textarea",
|
|
94
|
+
{
|
|
95
|
+
id,
|
|
96
|
+
className: "txa__input",
|
|
97
|
+
ref: taRef,
|
|
98
|
+
rows: minRows,
|
|
99
|
+
value: text,
|
|
100
|
+
placeholder,
|
|
101
|
+
disabled,
|
|
102
|
+
readOnly,
|
|
103
|
+
onChange,
|
|
104
|
+
onKeyDown,
|
|
105
|
+
onScroll: () => {
|
|
106
|
+
if (mirrorRef.current) mirrorRef.current.scrollTop = taRef.current.scrollTop;
|
|
107
|
+
},
|
|
108
|
+
"aria-invalid": error ? true : void 0,
|
|
109
|
+
...rest
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
] }),
|
|
113
|
+
(max || hint) && /* @__PURE__ */ jsxs("div", { className: "txa__bar", children: [
|
|
114
|
+
hint && /* @__PURE__ */ jsx("span", { className: "txa__hint", children: hint }),
|
|
115
|
+
max && /* @__PURE__ */ jsxs("span", { className: ["txa__meter", meterState].filter(Boolean).join(" "), children: [
|
|
116
|
+
/* @__PURE__ */ jsx("span", { className: "txa__count", children: over || remaining <= warnAt ? remaining : `${count} / ${max}` }),
|
|
117
|
+
/* @__PURE__ */ jsxs(
|
|
118
|
+
"svg",
|
|
119
|
+
{
|
|
120
|
+
className: "txa__ring",
|
|
121
|
+
viewBox: "0 0 16 16",
|
|
122
|
+
"aria-hidden": "true",
|
|
123
|
+
style: {
|
|
124
|
+
"--txa-ring-c": RING_C,
|
|
125
|
+
"--txa-ring-p": Math.min(count / max, 1)
|
|
126
|
+
},
|
|
127
|
+
children: [
|
|
128
|
+
/* @__PURE__ */ jsx("circle", { className: "txa__ring-trk", cx: "8", cy: "8", r: "7" }),
|
|
129
|
+
/* @__PURE__ */ jsx("circle", { className: "txa__ring-prg", cx: "8", cy: "8", r: "7" })
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
] })
|
|
134
|
+
] })
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
),
|
|
138
|
+
/* @__PURE__ */ jsx(Collapse, { open: !!msg, className: "fld__msg-wrap", children: /* @__PURE__ */ jsxs("div", { className: "fld__msg", children: [
|
|
139
|
+
msgIcon && /* @__PURE__ */ jsx(Icon, { name: msgIcon, size: "sm", weight: "fill" }),
|
|
140
|
+
msg
|
|
141
|
+
] }) })
|
|
142
|
+
] });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { Textarea };
|
|
146
|
+
//# sourceMappingURL=chunk-5K6KRJGX.js.map
|
|
147
|
+
//# sourceMappingURL=chunk-5K6KRJGX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/textarea/Textarea.tsx"],"names":[],"mappings":"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","file":"chunk-5K6KRJGX.js","sourcesContent":["'use client';\n\n// Textarea.tsx - multiline input: TextField anatomy plus auto-grow, char meter, over-limit highlight, ⌘/Ctrl+↵ submit.\n\nimport * as React from 'react';\nimport { Icon } from '../icon/Icon';\nimport { Collapse } from '../motion/Collapse';\n\nconst RING_C = (2 * Math.PI * 7).toFixed(2);\n\nexport interface TextareaProps extends Omit<\n React.TextareaHTMLAttributes<HTMLTextAreaElement>,\n 'size' | 'rows' | 'onSubmit'\n> {\n id?: string;\n /** Label text (sentence case). */\n label?: React.ReactNode;\n required?: boolean;\n optional?: boolean;\n /** Neutral helper - shown when there's no validation message. */\n helper?: React.ReactNode;\n /** Sets the matching state (border + icon + colour). error wins over warning/success/helper. */\n error?: React.ReactNode;\n warning?: React.ReactNode;\n success?: React.ReactNode;\n value?: string;\n onChange?: React.ChangeEventHandler<HTMLTextAreaElement>;\n /** Fired on ⌘/Ctrl+Enter with the current text. */\n onSubmit?: (value: string) => void;\n /** Soft char limit: shows the meter + over-limit highlight. Does NOT truncate (use native maxLength for a hard stop). */\n max?: number;\n /** Visible rows before growing (default 3) and the cap before it scrolls (default 10). */\n minRows?: number;\n maxRows?: number;\n /** Remaining-chars threshold that flips the meter amber. Default 20. */\n warnAt?: number;\n /** Footer hint, left of the meter - e.g. a ⌘↵ affordance. */\n hint?: React.ReactNode;\n /** md (default) - lg (prominent composer). */\n size?: 'md' | 'lg';\n}\n\nexport function Textarea({\n id,\n label,\n required,\n optional,\n placeholder,\n helper,\n error,\n warning,\n success,\n value = '',\n onChange,\n onSubmit,\n max,\n minRows = 3,\n maxRows = 10,\n warnAt = 20,\n hint,\n size,\n disabled,\n readOnly,\n className = '',\n ...rest\n}: TextareaProps) {\n const taRef = React.useRef<HTMLTextAreaElement>(null);\n const stackRef = React.useRef<HTMLDivElement>(null);\n const mirrorRef = React.useRef<HTMLDivElement>(null);\n const text = value ?? '';\n const count = text.length;\n const over = max ? Math.max(count - max, 0) : 0;\n const remaining = max ? max - count : 0;\n const meterState = over ? 'is-over' : max && remaining <= warnAt ? 'is-near' : '';\n\n const state = error ? 'is-error' : warning ? 'is-warning' : success ? 'is-success' : '';\n const msg = error || warning || success || helper;\n const msgIcon = error ? 'warning-circle' : warning ? 'warning' : success ? 'check-circle' : null;\n\n // Auto-grow without a caret jump: the .txa__stack wrapper animates its height and is overflow:clip while growing (a clip box can't scroll to the caret); scroll is enabled only past max-height.\n const resize = () => {\n const el = taRef.current,\n stack = stackRef.current;\n if (!el || !stack) return;\n const start = stack.offsetHeight; // capture the start height before mutating layout below\n el.style.height = 'auto';\n el.style.height = el.scrollHeight + 'px';\n const content = el.offsetHeight;\n const maxPx = parseFloat(getComputedStyle(stack).maxHeight) || Infinity;\n const target = Math.min(content, maxPx);\n if (target === start) {\n stack.style.overflowY = content > maxPx ? 'auto' : 'clip';\n return;\n }\n stack.style.overflowY = 'clip';\n stack.style.height = start + 'px';\n void stack.offsetHeight; // force a reflow so the height transition runs from start\n stack.style.height = target + 'px';\n };\n React.useLayoutEffect(resize, [text, size]);\n React.useEffect(() => {\n window.addEventListener('resize', resize);\n return () => window.removeEventListener('resize', resize);\n }, []);\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (onSubmit && (e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n e.preventDefault();\n onSubmit(text);\n }\n rest.onKeyDown && rest.onKeyDown(e);\n };\n\n const cls = ['fld', 'fld--txa', size === 'lg' && 'fld--lg', state, className]\n .filter(Boolean)\n .join(' ');\n const boxCls = ['txa', disabled && 'is-disabled', readOnly && 'is-readonly']\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={cls}>\n {label && (\n <label className=\"fld__label\" htmlFor={id}>\n {label}\n {required && (\n <span className=\"fld__req\" aria-hidden=\"true\">\n *\n </span>\n )}\n {optional && <span className=\"fld__optional\">(optional)</span>}\n </label>\n )}\n <div\n className={boxCls}\n style={{ '--txa-min-rows': minRows, '--txa-max-rows': maxRows } as React.CSSProperties}\n >\n <div className=\"txa__stack\" ref={stackRef}>\n <div className=\"txa__mirror\" ref={mirrorRef} aria-hidden=\"true\">\n {over ? text.slice(0, max) : text}\n {over ? <mark>{text.slice(max)}</mark> : null}\n {'\\n'}\n </div>\n <textarea\n id={id}\n className=\"txa__input\"\n ref={taRef}\n rows={minRows}\n value={text}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n onChange={onChange}\n onKeyDown={onKeyDown}\n onScroll={() => {\n if (mirrorRef.current) mirrorRef.current.scrollTop = taRef.current.scrollTop;\n }}\n aria-invalid={error ? true : undefined}\n {...rest}\n />\n </div>\n {(max || hint) && (\n <div className=\"txa__bar\">\n {hint && <span className=\"txa__hint\">{hint}</span>}\n {max && (\n <span className={['txa__meter', meterState].filter(Boolean).join(' ')}>\n <span className=\"txa__count\">\n {over || remaining <= warnAt ? remaining : `${count} / ${max}`}\n </span>\n <svg\n className=\"txa__ring\"\n viewBox=\"0 0 16 16\"\n aria-hidden=\"true\"\n style={\n {\n '--txa-ring-c': RING_C,\n '--txa-ring-p': Math.min(count / max, 1),\n } as React.CSSProperties\n }\n >\n <circle className=\"txa__ring-trk\" cx=\"8\" cy=\"8\" r=\"7\" />\n <circle className=\"txa__ring-prg\" cx=\"8\" cy=\"8\" r=\"7\" />\n </svg>\n </span>\n )}\n </div>\n )}\n </div>\n <Collapse open={!!msg} className=\"fld__msg-wrap\">\n <div className=\"fld__msg\">\n {msgIcon && <Icon name={msgIcon} size=\"sm\" weight=\"fill\" />}\n {msg}\n </div>\n </Collapse>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client';import * as React from 'react';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/components/toggle/Toggle.tsx
|
|
5
|
+
var { useState } = React;
|
|
6
|
+
function Toggle({
|
|
7
|
+
checked,
|
|
8
|
+
defaultChecked = false,
|
|
9
|
+
disabled = false,
|
|
10
|
+
size = "md",
|
|
11
|
+
label,
|
|
12
|
+
description,
|
|
13
|
+
className = "",
|
|
14
|
+
onChange,
|
|
15
|
+
...rest
|
|
16
|
+
}) {
|
|
17
|
+
const controlled = checked !== void 0;
|
|
18
|
+
const [internal, setInternal] = useState(!!defaultChecked);
|
|
19
|
+
const isOn = controlled ? !!checked : internal;
|
|
20
|
+
const classes = ["sw", size === "sm" ? "sw--sm" : "", disabled ? "sw--disabled" : "", className].filter(Boolean).join(" ");
|
|
21
|
+
const [pressed, setPressed] = useState(false);
|
|
22
|
+
function press(on) {
|
|
23
|
+
return () => {
|
|
24
|
+
if (!disabled) setPressed(on);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function handleChange(e) {
|
|
28
|
+
if (!controlled) setInternal(e.target.checked);
|
|
29
|
+
if (onChange) onChange(e);
|
|
30
|
+
}
|
|
31
|
+
return /* @__PURE__ */ jsxs(
|
|
32
|
+
"label",
|
|
33
|
+
{
|
|
34
|
+
className: classes,
|
|
35
|
+
onPointerDown: press(true),
|
|
36
|
+
onPointerUp: press(false),
|
|
37
|
+
onPointerLeave: press(false),
|
|
38
|
+
onPointerCancel: press(false),
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
"input",
|
|
42
|
+
{
|
|
43
|
+
type: "checkbox",
|
|
44
|
+
role: "switch",
|
|
45
|
+
className: "sw__input",
|
|
46
|
+
disabled,
|
|
47
|
+
checked: isOn,
|
|
48
|
+
onChange: handleChange,
|
|
49
|
+
...rest,
|
|
50
|
+
defaultChecked: void 0
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"span",
|
|
55
|
+
{
|
|
56
|
+
className: "sw__track",
|
|
57
|
+
"data-on": isOn ? "true" : void 0,
|
|
58
|
+
"data-pressed": pressed ? "true" : void 0,
|
|
59
|
+
"aria-hidden": "true",
|
|
60
|
+
children: /* @__PURE__ */ jsx("span", { className: "sw__thumb" })
|
|
61
|
+
}
|
|
62
|
+
),
|
|
63
|
+
label || description ? /* @__PURE__ */ jsxs("span", { className: "sw__text", children: [
|
|
64
|
+
label ? /* @__PURE__ */ jsx("span", { className: "sw__label", children: label }) : null,
|
|
65
|
+
description ? /* @__PURE__ */ jsx("span", { className: "sw__desc", children: description }) : null
|
|
66
|
+
] }) : null
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Toggle };
|
|
73
|
+
//# sourceMappingURL=chunk-5PQMQBQC.js.map
|
|
74
|
+
//# sourceMappingURL=chunk-5PQMQBQC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/toggle/Toggle.tsx"],"names":[],"mappings":";;;;AAMA,IAAM,EAAE,UAAS,GAAI,KAAA;AAsBd,SAAS,MAAA,CAAO;AAAA,EACrB,OAAA;AAAA,EACA,cAAA,GAAiB,KAAA;AAAA,EACjB,QAAA,GAAW,KAAA;AAAA,EACX,IAAA,GAAO,IAAA;AAAA,EACP,KAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,MAAM,aAAa,OAAA,KAAY,MAAA;AAC/B,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,IAAI,QAAA,CAAS,CAAC,CAAC,cAAc,CAAA;AACzD,EAAA,MAAM,IAAA,GAAO,UAAA,GAAa,CAAC,CAAC,OAAA,GAAU,QAAA;AAEtC,EAAA,MAAM,UAAU,CAAC,IAAA,EAAM,IAAA,KAAS,IAAA,GAAO,WAAW,EAAA,EAAI,QAAA,GAAW,cAAA,GAAiB,EAAA,EAAI,SAAS,CAAA,CAC5F,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,SAAS,MAAM,EAAA,EAAa;AAC1B,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,CAAC,QAAA,EAAU,UAAA,CAAW,EAAE,CAAA;AAAA,IAC9B,CAAA;AAAA,EACF;AAEA,EAAA,SAAS,aAAa,CAAA,EAAwC;AAC5D,IAAA,IAAI,CAAC,UAAA,EAAY,WAAA,CAAY,CAAA,CAAE,OAAO,OAAO,CAAA;AAC7C,IAAA,IAAI,QAAA,WAAmB,CAAC,CAAA;AAAA,EAC1B;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACX,aAAA,EAAe,MAAM,IAAI,CAAA;AAAA,MACzB,WAAA,EAAa,MAAM,KAAK,CAAA;AAAA,MACxB,cAAA,EAAgB,MAAM,KAAK,CAAA;AAAA,MAC3B,eAAA,EAAiB,MAAM,KAAK,CAAA;AAAA,MAE5B,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,UAAA;AAAA,YACL,IAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,WAAA;AAAA,YACV,QAAA;AAAA,YACA,OAAA,EAAS,IAAA;AAAA,YACT,QAAA,EAAU,YAAA;AAAA,YACT,GAAG,IAAA;AAAA,YACJ,cAAA,EAAgB;AAAA;AAAA,SAClB;AAAA,wBACA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,WAAA;AAAA,YACV,SAAA,EAAS,OAAO,MAAA,GAAS,MAAA;AAAA,YACzB,cAAA,EAAc,UAAU,MAAA,GAAS,MAAA;AAAA,YACjC,aAAA,EAAY,MAAA;AAAA,YAEZ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,WAAA,EAAY;AAAA;AAAA,SAC9B;AAAA,QACC,KAAA,IAAS,WAAA,mBACR,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,UAAA,EACb,QAAA,EAAA;AAAA,UAAA,KAAA,mBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,WAAA,EAAa,iBAAM,CAAA,GAAU,IAAA;AAAA,UACrD,8BAAc,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,uBAAY,CAAA,GAAU;AAAA,SAAA,EACnE,CAAA,GACE;AAAA;AAAA;AAAA,GACN;AAEJ","file":"chunk-5PQMQBQC.js","sourcesContent":["'use client';\n\n// Toggle - binary on/off switch for an immediate setting (vs. Checkbox, which stages a choice).\n\nimport * as React from 'react';\n\nconst { useState } = React;\n\nexport interface ToggleProps extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'size' | 'type'\n> {\n /** Controlled checked state. Omit for uncontrolled (use `defaultChecked`). */\n checked?: boolean;\n /** Uncontrolled initial state. */\n defaultChecked?: boolean;\n /** Disabled - inert and de-emphasized (faded track, retains its position). */\n disabled?: boolean;\n /** Track size: `md` 36x20 - `sm` 28x16 for dense settings/table rows. @default 'md' */\n size?: 'sm' | 'md';\n /** Label text beside the track. */\n label?: React.ReactNode;\n /** Optional secondary line under the label (settings rows). */\n description?: React.ReactNode;\n /** Fires on flip - read `e.target.checked`. */\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n}\n\nexport function Toggle({\n checked,\n defaultChecked = false,\n disabled = false,\n size = 'md',\n label,\n description,\n className = '',\n onChange,\n ...rest\n}: ToggleProps) {\n const controlled = checked !== undefined;\n const [internal, setInternal] = useState(!!defaultChecked);\n const isOn = controlled ? !!checked : internal;\n\n const classes = ['sw', size === 'sm' ? 'sw--sm' : '', disabled ? 'sw--disabled' : '', className]\n .filter(Boolean)\n .join(' ');\n\n const [pressed, setPressed] = useState(false);\n function press(on: boolean) {\n return () => {\n if (!disabled) setPressed(on);\n };\n }\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n if (!controlled) setInternal(e.target.checked);\n if (onChange) onChange(e);\n }\n\n return (\n <label\n className={classes}\n onPointerDown={press(true)}\n onPointerUp={press(false)}\n onPointerLeave={press(false)}\n onPointerCancel={press(false)}\n >\n <input\n type=\"checkbox\"\n role=\"switch\"\n className=\"sw__input\"\n disabled={disabled}\n checked={isOn}\n onChange={handleChange}\n {...rest}\n defaultChecked={undefined}\n />\n <span\n className=\"sw__track\"\n data-on={isOn ? 'true' : undefined}\n data-pressed={pressed ? 'true' : undefined}\n aria-hidden=\"true\"\n >\n <span className=\"sw__thumb\"></span>\n </span>\n {label || description ? (\n <span className=\"sw__text\">\n {label ? <span className=\"sw__label\">{label}</span> : null}\n {description ? <span className=\"sw__desc\">{description}</span> : null}\n </span>\n ) : null}\n </label>\n );\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use client';import { useRef } from 'react';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/components/input/OtpField.tsx
|
|
5
|
+
function OtpField({
|
|
6
|
+
length = 6,
|
|
7
|
+
value = "",
|
|
8
|
+
onChange,
|
|
9
|
+
group,
|
|
10
|
+
error,
|
|
11
|
+
disabled,
|
|
12
|
+
size,
|
|
13
|
+
className = ""
|
|
14
|
+
}) {
|
|
15
|
+
const refs = useRef([]);
|
|
16
|
+
const chars = String(value).slice(0, length).padEnd(length).split("");
|
|
17
|
+
const emit = (s) => onChange && onChange(s.replace(/ +$/, "").slice(0, length));
|
|
18
|
+
const setAt = (i, ch) => {
|
|
19
|
+
const a = chars.slice();
|
|
20
|
+
a[i] = ch || " ";
|
|
21
|
+
emit(a.join(""));
|
|
22
|
+
};
|
|
23
|
+
const caretEnd = (el) => {
|
|
24
|
+
if (!el) return;
|
|
25
|
+
const n = el.value.length;
|
|
26
|
+
try {
|
|
27
|
+
el.setSelectionRange(n, n);
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const go = (j) => {
|
|
32
|
+
const el = refs.current[j];
|
|
33
|
+
if (el) {
|
|
34
|
+
el.focus();
|
|
35
|
+
caretEnd(el);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const cls = ["otp", size === "sm" ? "otp--sm" : "", error ? "is-error" : "", className].filter(Boolean).join(" ");
|
|
39
|
+
const cells = [];
|
|
40
|
+
for (let i = 0; i < length; i++) {
|
|
41
|
+
if (group && i > 0 && i % group === 0)
|
|
42
|
+
cells.push(/* @__PURE__ */ jsx("span", { className: "otp__sep" }, `sep${i}`));
|
|
43
|
+
cells.push(
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
"input",
|
|
46
|
+
{
|
|
47
|
+
ref: (el) => {
|
|
48
|
+
refs.current[i] = el;
|
|
49
|
+
},
|
|
50
|
+
className: "otp__slot",
|
|
51
|
+
inputMode: "numeric",
|
|
52
|
+
autoComplete: "one-time-code",
|
|
53
|
+
disabled,
|
|
54
|
+
value: chars[i].trim(),
|
|
55
|
+
"data-filled": chars[i].trim() ? "true" : "false",
|
|
56
|
+
onFocus: (e) => caretEnd(e.target),
|
|
57
|
+
onMouseDown: (e) => {
|
|
58
|
+
e.preventDefault();
|
|
59
|
+
go(i);
|
|
60
|
+
},
|
|
61
|
+
onChange: (e) => {
|
|
62
|
+
const ch = e.target.value.replace(/[^\d]/g, "").slice(-1);
|
|
63
|
+
setAt(i, ch);
|
|
64
|
+
if (ch && i < length - 1) go(i + 1);
|
|
65
|
+
},
|
|
66
|
+
onKeyDown: (e) => {
|
|
67
|
+
if (e.key === "Backspace" && !chars[i].trim() && i > 0) {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
setAt(i - 1, "");
|
|
70
|
+
go(i - 1);
|
|
71
|
+
} else if (e.key === "ArrowLeft" && i > 0) {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
go(i - 1);
|
|
74
|
+
} else if (e.key === "ArrowRight" && i < length - 1) {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
go(i + 1);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onPaste: (e) => {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
const d = (e.clipboardData.getData("text") || "").replace(/[^\d]/g, "");
|
|
82
|
+
emit(chars.slice(0, i).join("") + d);
|
|
83
|
+
refs.current[Math.min(i + d.length, length - 1)]?.focus();
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
i
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return /* @__PURE__ */ jsx("div", { className: cls, children: cells });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { OtpField };
|
|
94
|
+
//# sourceMappingURL=chunk-7OCTVQ7C.js.map
|
|
95
|
+
//# sourceMappingURL=chunk-7OCTVQ7C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/input/OtpField.tsx"],"names":[],"mappings":"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","file":"chunk-7OCTVQ7C.js","sourcesContent":["'use client';\n\n// OtpField.tsx - segmented one-time-code input: mono slots, auto-advance, arrow nav, paste-to-fill, grouping.\n\nimport { useRef } from 'react';\nimport type {\n ChangeEvent,\n ClipboardEvent,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n} from 'react';\n\nexport interface OtpFieldProps {\n /** Number of slots. @default 6 */\n length?: number;\n /** Controlled value (digit string). */\n value?: string;\n /** Called with the next value string. */\n onChange?: (value: string) => void;\n /** Insert a separator every N slots (e.g. 3 - \"-------\"). */\n group?: number;\n /** Error state (red slots + ring). */\n error?: boolean;\n disabled?: boolean;\n size?: 'sm';\n className?: string;\n}\n\nexport function OtpField({\n length = 6,\n value = '',\n onChange,\n group,\n error,\n disabled,\n size,\n className = '',\n}: OtpFieldProps) {\n const refs = useRef<(HTMLInputElement | null)[]>([]);\n const chars = String(value).slice(0, length).padEnd(length).split('');\n const emit = (s: string) => onChange && onChange(s.replace(/ +$/, '').slice(0, length));\n const setAt = (i: number, ch: string) => {\n const a = chars.slice();\n a[i] = ch || ' ';\n emit(a.join(''));\n };\n // place caret at the end (no selection highlight); replacement handled by slice(-1)\n const caretEnd = (el: HTMLInputElement | null) => {\n if (!el) return;\n const n = el.value.length;\n try {\n el.setSelectionRange(n, n);\n } catch {}\n };\n const go = (j: number) => {\n const el = refs.current[j];\n if (el) {\n el.focus();\n caretEnd(el);\n }\n };\n\n const cls = ['otp', size === 'sm' ? 'otp--sm' : '', error ? 'is-error' : '', className]\n .filter(Boolean)\n .join(' ');\n\n const cells: ReactNode[] = [];\n for (let i = 0; i < length; i++) {\n if (group && i > 0 && i % group === 0)\n cells.push(<span key={`sep${i}`} className=\"otp__sep\" />);\n cells.push(\n <input\n key={i}\n ref={(el) => {\n refs.current[i] = el;\n }}\n className=\"otp__slot\"\n inputMode=\"numeric\"\n autoComplete=\"one-time-code\"\n disabled={disabled}\n value={chars[i].trim()}\n data-filled={chars[i].trim() ? 'true' : 'false'}\n onFocus={(e: FocusEvent<HTMLInputElement>) => caretEnd(e.target)}\n onMouseDown={(e: MouseEvent<HTMLInputElement>) => {\n e.preventDefault();\n go(i);\n }}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n const ch = e.target.value.replace(/[^\\d]/g, '').slice(-1);\n setAt(i, ch);\n if (ch && i < length - 1) go(i + 1);\n }}\n onKeyDown={(e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Backspace' && !chars[i].trim() && i > 0) {\n e.preventDefault();\n setAt(i - 1, '');\n go(i - 1);\n } else if (e.key === 'ArrowLeft' && i > 0) {\n e.preventDefault();\n go(i - 1);\n } else if (e.key === 'ArrowRight' && i < length - 1) {\n e.preventDefault();\n go(i + 1);\n }\n }}\n onPaste={(e: ClipboardEvent<HTMLInputElement>) => {\n e.preventDefault();\n const d = (e.clipboardData.getData('text') || '').replace(/[^\\d]/g, '');\n emit(chars.slice(0, i).join('') + d);\n refs.current[Math.min(i + d.length, length - 1)]?.focus();\n }}\n />,\n );\n }\n return <div className={cls}>{cells}</div>;\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use client';import * as React from 'react';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
// src/components/avatar/AvatarGroup.tsx
|
|
5
|
+
function AvatarGroup({
|
|
6
|
+
children,
|
|
7
|
+
max = 5,
|
|
8
|
+
size = "md",
|
|
9
|
+
className = "",
|
|
10
|
+
...rest
|
|
11
|
+
}) {
|
|
12
|
+
const items = React.Children.toArray(children);
|
|
13
|
+
const visible = max > 0 ? items.slice(0, max) : items;
|
|
14
|
+
const overflow = items.length - visible.length;
|
|
15
|
+
return /* @__PURE__ */ jsxs("span", { className: ["avatar-group", className].filter(Boolean).join(" "), ...rest, children: [
|
|
16
|
+
visible.map(
|
|
17
|
+
(child, i) => React.isValidElement(child) ? React.cloneElement(child, {
|
|
18
|
+
size,
|
|
19
|
+
key: child.key ?? i
|
|
20
|
+
}) : child
|
|
21
|
+
),
|
|
22
|
+
overflow > 0 && /* @__PURE__ */ jsx(
|
|
23
|
+
"span",
|
|
24
|
+
{
|
|
25
|
+
className: `avatar avatar--${size} avatar--overflow`,
|
|
26
|
+
role: "img",
|
|
27
|
+
"aria-label": `${overflow} more`,
|
|
28
|
+
children: /* @__PURE__ */ jsx("span", { className: "avatar__face", children: /* @__PURE__ */ jsxs("span", { className: "avatar__initials", children: [
|
|
29
|
+
"+",
|
|
30
|
+
overflow
|
|
31
|
+
] }) })
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
] });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { AvatarGroup };
|
|
38
|
+
//# sourceMappingURL=chunk-7OPMOET7.js.map
|
|
39
|
+
//# sourceMappingURL=chunk-7OPMOET7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/avatar/AvatarGroup.tsx"],"names":[],"mappings":";;;;AAeO,SAAS,WAAA,CAAY;AAAA,EAC1B,QAAA;AAAA,EACA,GAAA,GAAM,CAAA;AAAA,EACN,IAAA,GAAO,IAAA;AAAA,EACP,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,EAAqB;AACnB,EAAA,MAAM,KAAA,GAAc,KAAA,CAAA,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA;AAC7C,EAAA,MAAM,UAAU,GAAA,GAAM,CAAA,GAAI,MAAM,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA,GAAI,KAAA;AAChD,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,OAAA,CAAQ,MAAA;AAExC,EAAA,uBACE,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,CAAC,gBAAgB,SAAS,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,EAAI,GAAG,IAAA,EACzE,QAAA,EAAA;AAAA,IAAA,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,KAAA,EAAO,CAAA,KACb,qBAAe,KAAK,CAAA,GAChB,mBAAa,KAAA,EAAoD;AAAA,QACrE,IAAA;AAAA,QACA,GAAA,EAAK,MAAM,GAAA,IAAO;AAAA,OACnB,CAAA,GACD;AAAA,KACN;AAAA,IACC,WAAW,CAAA,oBACV,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,kBAAkB,IAAI,CAAA,iBAAA,CAAA;AAAA,QACjC,IAAA,EAAK,KAAA;AAAA,QACL,YAAA,EAAY,GAAG,QAAQ,CAAA,KAAA,CAAA;AAAA,QAEvB,8BAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBACd,QAAA,kBAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,kBAAA,EAAmB,QAAA,EAAA;AAAA,UAAA,GAAA;AAAA,UAAE;AAAA,SAAA,EAAS,CAAA,EAChD;AAAA;AAAA;AACF,GAAA,EAEJ,CAAA;AAEJ","file":"chunk-7OPMOET7.js","sourcesContent":["'use client';\n\n// AvatarGroup - stacks Avatars with overlap + a \"+N\" overflow chip; CSS drives the hover-spread.\n\nimport * as React from 'react';\nimport type { AvatarSize } from './Avatar';\n\nexport interface AvatarGroupProps extends React.HTMLAttributes<HTMLSpanElement> {\n children: React.ReactNode;\n /** Max visible avatars before \"+N\" overflow chip. Default 5. */\n max?: number;\n /** Uniform size applied to all children. Default 'md'. */\n size?: AvatarSize;\n}\n\nexport function AvatarGroup({\n children,\n max = 5,\n size = 'md',\n className = '',\n ...rest\n}: AvatarGroupProps) {\n const items = React.Children.toArray(children);\n const visible = max > 0 ? items.slice(0, max) : items;\n const overflow = items.length - visible.length;\n\n return (\n <span className={['avatar-group', className].filter(Boolean).join(' ')} {...rest}>\n {visible.map((child, i) =>\n React.isValidElement(child)\n ? React.cloneElement(child as React.ReactElement<{ size?: AvatarSize }>, {\n size,\n key: child.key ?? i,\n })\n : child,\n )}\n {overflow > 0 && (\n <span\n className={`avatar avatar--${size} avatar--overflow`}\n role=\"img\"\n aria-label={`${overflow} more`}\n >\n <span className=\"avatar__face\">\n <span className=\"avatar__initials\">+{overflow}</span>\n </span>\n </span>\n )}\n </span>\n );\n}\n"]}
|