@godxjp/ui 13.7.0 → 13.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/index.js +4 -4
- package/dist/{checkbox-ChJ2PyIz.d.ts → checkbox-bBfLARyF.d.ts} +1 -1
- package/dist/{chunk-CSTUENE6.js → chunk-2JOJYHG2.js} +4 -4
- package/dist/{chunk-TNFAUPEV.js → chunk-3UTHNXKB.js} +4 -4
- package/dist/{chunk-IRPZJKLU.js → chunk-4FGE5XVC.js} +10 -0
- package/dist/{chunk-C7W5BO7R.js → chunk-5732TWQF.js} +22 -1
- package/dist/{chunk-IMERLXSC.js → chunk-5LTW2LWF.js} +6 -1
- package/dist/{chunk-SXECWZZV.js → chunk-6SZKFJYY.js} +8 -8
- package/dist/{chunk-QMGNMDQG.js → chunk-76YSDJDP.js} +5 -5
- package/dist/chunk-7PBKPDBJ.js +881 -0
- package/dist/{chunk-QTEPKNQE.js → chunk-B6S6LTWT.js} +1 -1
- package/dist/{chunk-GOJQHYED.js → chunk-DBVZ73ML.js} +9 -5
- package/dist/{chunk-I472SSN2.js → chunk-E3Z3XCQR.js} +4 -3
- package/dist/{chunk-ZYJRZLMZ.js → chunk-HIEGUYPP.js} +1 -1
- package/dist/{chunk-W3AS2GEC.js → chunk-HNL7CJFO.js} +5 -5
- package/dist/{chunk-76S3TQFH.js → chunk-IAJOP2Z3.js} +31 -13
- package/dist/{chunk-RBXVCWXL.js → chunk-IESBK6XZ.js} +2 -2
- package/dist/{chunk-LFO5BJ4H.js → chunk-ION2KFXK.js} +2 -2
- package/dist/{chunk-QPRBPE4S.js → chunk-IRBI2EZ2.js} +4 -4
- package/dist/{chunk-3KPEZ5CF.js → chunk-J2DEWIYY.js} +1 -1
- package/dist/{chunk-6AIYMYSG.js → chunk-K24AQV4R.js} +1 -1
- package/dist/{chunk-B23A5CPA.js → chunk-KZ7ZDNUN.js} +3 -3
- package/dist/{chunk-6EKAEN6T.js → chunk-MSRJC3RT.js} +3 -3
- package/dist/{chunk-O3F3KF2B.js → chunk-N2WBUCVY.js} +4 -4
- package/dist/{chunk-MUUO7SPN.js → chunk-NU2SOVTU.js} +9 -3
- package/dist/{chunk-B7R7DHZF.js → chunk-NZBAFFWP.js} +1 -1
- package/dist/{chunk-ZOMIELKI.js → chunk-Q3KUZG4P.js} +1 -1
- package/dist/{chunk-LTKHPOE3.js → chunk-QROC2RMH.js} +2 -2
- package/dist/{chunk-P5KPCT6R.js → chunk-QVBOICFU.js} +2 -0
- package/dist/{chunk-3JQDPNTA.js → chunk-R2TXLS7S.js} +1 -1
- package/dist/{chunk-JXGDDD46.js → chunk-TRBD4RXJ.js} +4 -4
- package/dist/{chunk-KW54IV4X.js → chunk-UT6DAJUL.js} +3 -3
- package/dist/{chunk-2FJ5TMQU.js → chunk-X6AJ5HEI.js} +1 -1
- package/dist/{chunk-5L77S5CL.js → chunk-XBFUROAY.js} +1 -1
- package/dist/chunk-YXVJFYQE.js +191 -0
- package/dist/components/admin/index.d.ts +4 -4
- package/dist/components/admin/index.js +30 -30
- package/dist/components/data-display/badge.js +3 -3
- package/dist/components/data-display/card.d.ts +6 -4
- package/dist/components/data-display/card.js +1 -1
- package/dist/components/data-display/carousel.js +3 -3
- package/dist/components/data-display/index.js +11 -11
- package/dist/components/data-display/scroll-area.js +1 -1
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +4 -4
- package/dist/components/data-entry/cascader.d.ts +2 -2
- package/dist/components/data-entry/cascader.js +5 -5
- package/dist/components/data-entry/checkbox.d.ts +3 -3
- package/dist/components/data-entry/color-picker.d.ts +2 -2
- package/dist/components/data-entry/color-picker.js +4 -4
- package/dist/components/data-entry/date-picker.d.ts +2 -2
- package/dist/components/data-entry/date-picker.js +6 -6
- package/dist/components/data-entry/date-range-picker.d.ts +7 -5
- package/dist/components/data-entry/date-range-picker.js +5 -6
- package/dist/components/data-entry/index.d.ts +25 -7
- package/dist/components/data-entry/index.js +25 -25
- package/dist/components/data-entry/input.js +3 -3
- package/dist/components/data-entry/radio.d.ts +2 -2
- package/dist/components/data-entry/select.d.ts +2 -2
- package/dist/components/data-entry/select.js +5 -5
- package/dist/components/data-entry/slider.d.ts +2 -2
- package/dist/components/data-entry/switch.d.ts +2 -2
- package/dist/components/data-entry/textarea.js +3 -3
- package/dist/components/data-entry/time-input.js +2 -2
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +5 -5
- package/dist/components/data-entry/transfer.d.ts +3 -3
- package/dist/components/data-entry/transfer.js +7 -7
- package/dist/components/data-entry/tree-select.d.ts +2 -2
- package/dist/components/data-entry/tree-select.js +6 -6
- package/dist/components/data-entry/upload.d.ts +3 -3
- package/dist/components/data-entry/upload.js +7 -7
- package/dist/components/data-grid/index.js +9 -9
- package/dist/components/feedback/alert.js +5 -5
- package/dist/components/feedback/dialog.js +5 -5
- package/dist/components/feedback/index.js +10 -10
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +1 -1
- package/dist/components/general/button.js +3 -3
- package/dist/components/general/index.js +3 -3
- package/dist/components/layout/index.d.ts +4 -4
- package/dist/components/layout/index.js +5 -5
- package/dist/components/navigation/index.js +9 -9
- package/dist/components/navigation/pagination.js +6 -6
- package/dist/components/navigation/steps.js +3 -3
- package/dist/components/query/index.js +5 -5
- package/dist/components/ui/index.d.ts +3 -3
- package/dist/components/ui/index.js +32 -32
- package/dist/{data-entry.prop-CyiZuEI8.d.ts → data-entry.prop-BSUaseKh.d.ts} +41 -3
- package/dist/{flex-X2EFU1d5.d.ts → flex-1Cy46L0M.d.ts} +1 -1
- package/dist/form/index.js +1 -1
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +43 -43
- package/dist/{layout.prop-D2be7gOo.d.ts → layout.prop-fCz-Vlie.d.ts} +2 -0
- package/dist/lib/datetime/index.js +1 -1
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/index.d.ts +2 -2
- package/dist/props/index.js +1 -1
- package/dist/props/registry.d.ts +10 -0
- package/dist/props/registry.js +1 -1
- package/dist/{search-input--ui38eQV.d.ts → search-input-D4v1JGOA.d.ts} +1 -1
- package/dist/styles/alert-layout.css +2 -2
- package/dist/styles/card-layout.css +10 -10
- package/dist/styles/control.css +8 -8
- package/dist/styles/data-display-layout.css +7 -7
- package/dist/styles/data-entry-layout.css +2 -2
- package/dist/styles/dialog-layout.css +1 -1
- package/dist/styles/form-layout.css +5 -5
- package/dist/styles/index.css +1 -1
- package/dist/styles/layout.css +10 -10
- package/dist/styles/navigation-layout.css +5 -5
- package/dist/styles/shell-layout.css +10 -10
- package/dist/styles/table-layout.css +6 -6
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/card.css +4 -0
- package/dist/tokens/components/form.css +11 -0
- package/dist/tokens/semantic/layout.css +11 -0
- package/package.json +5 -3
- package/dist/chunk-3ZNSR2NL.js +0 -467
- package/dist/chunk-G7A6SUIN.js +0 -183
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
min-width: 0;
|
|
29
29
|
flex-direction: column;
|
|
30
30
|
overflow: hidden;
|
|
31
|
-
border-
|
|
31
|
+
border-inline-end: 1px solid hsl(var(--border));
|
|
32
32
|
background: hsl(var(--card));
|
|
33
33
|
color: hsl(var(--foreground));
|
|
34
34
|
}
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
background: transparent;
|
|
138
138
|
color: inherit;
|
|
139
139
|
font-family: inherit;
|
|
140
|
-
text-align:
|
|
140
|
+
text-align: start;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
.sb-product {
|
|
@@ -241,7 +241,7 @@
|
|
|
241
241
|
cursor: pointer;
|
|
242
242
|
font-family: inherit;
|
|
243
243
|
font-size: var(--font-size-sm);
|
|
244
|
-
text-align:
|
|
244
|
+
text-align: start;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
.sb-nav-item:hover,
|
|
@@ -297,7 +297,7 @@
|
|
|
297
297
|
|
|
298
298
|
/* Collapsible group trigger chevron (rotates when open). */
|
|
299
299
|
.sb-nav-group-trigger .sb-chevron {
|
|
300
|
-
margin-
|
|
300
|
+
margin-inline-start: auto;
|
|
301
301
|
flex: 0 0 auto;
|
|
302
302
|
opacity: 0.6;
|
|
303
303
|
transition: transform 150ms ease;
|
|
@@ -314,8 +314,8 @@
|
|
|
314
314
|
flex-direction: column;
|
|
315
315
|
gap: 2px;
|
|
316
316
|
margin: 2px 0 var(--space-1) calc(var(--space-2) + 0.6875rem);
|
|
317
|
-
padding-
|
|
318
|
-
border-
|
|
317
|
+
padding-inline-start: var(--space-3);
|
|
318
|
+
border-inline-start: 1px solid hsl(var(--border));
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
.sb-nav-item--sub {
|
|
@@ -383,7 +383,7 @@
|
|
|
383
383
|
color: inherit;
|
|
384
384
|
cursor: pointer;
|
|
385
385
|
font-family: inherit;
|
|
386
|
-
text-align:
|
|
386
|
+
text-align: start;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
.sb-user:hover,
|
|
@@ -416,7 +416,7 @@
|
|
|
416
416
|
|
|
417
417
|
.sb-user-live {
|
|
418
418
|
position: absolute;
|
|
419
|
-
|
|
419
|
+
inset-inline-end: -1px;
|
|
420
420
|
bottom: -1px;
|
|
421
421
|
width: 0.5625rem;
|
|
422
422
|
height: 0.5625rem;
|
|
@@ -572,7 +572,7 @@
|
|
|
572
572
|
.kbd {
|
|
573
573
|
display: inline-flex;
|
|
574
574
|
align-items: center;
|
|
575
|
-
margin-
|
|
575
|
+
margin-inline-start: auto;
|
|
576
576
|
padding: 1px 5px;
|
|
577
577
|
border: 1px solid hsl(var(--border));
|
|
578
578
|
border-bottom-width: 2px;
|
|
@@ -617,7 +617,7 @@
|
|
|
617
617
|
.tb-bell-dot {
|
|
618
618
|
position: absolute;
|
|
619
619
|
top: 0.35rem;
|
|
620
|
-
|
|
620
|
+
inset-inline-end: 0.35rem;
|
|
621
621
|
width: 0.375rem;
|
|
622
622
|
height: 0.375rem;
|
|
623
623
|
border-radius: var(--radius-pill);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[data-slot="table-head"] {
|
|
7
7
|
height: var(--table-row-height);
|
|
8
8
|
padding: var(--table-cell-padding-y) var(--table-cell-space-x);
|
|
9
|
-
text-align:
|
|
9
|
+
text-align: start;
|
|
10
10
|
vertical-align: middle;
|
|
11
11
|
background: hsl(var(--secondary));
|
|
12
12
|
font-size: var(--font-size-xs);
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
[data-slot="table-head"]:has([role="checkbox"]) {
|
|
19
|
-
padding-
|
|
19
|
+
padding-inline-end: 0;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/* A column with an empty header (icon / action column) shouldn't paint the
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
[data-slot="table-cell"]:has([role="checkbox"]) {
|
|
40
|
-
padding-
|
|
40
|
+
padding-inline-end: 0;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
.ui-data-table-toolbar {
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
content: "";
|
|
126
126
|
position: absolute;
|
|
127
127
|
top: 0;
|
|
128
|
-
|
|
128
|
+
inset-inline-end: var(--space-page-active-x);
|
|
129
129
|
bottom: 0;
|
|
130
130
|
z-index: 20;
|
|
131
131
|
width: 1.75rem;
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
[data-slot="card-content"][data-flush] .ui-data-table-scroll::after {
|
|
142
|
-
|
|
142
|
+
inset-inline-end: 0;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
[data-slot="card-content"][data-flush] .ui-data-table-surface {
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
.ui-data-table-scroll::after {
|
|
157
|
-
|
|
157
|
+
inset-inline-end: 0;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
package/dist/tokens/base.css
CHANGED
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
--card-border: var(--border);
|
|
16
16
|
--card-header-background: var(--muted);
|
|
17
17
|
--card-header-background-alpha: 0.55;
|
|
18
|
+
/* Banded-header divider — tokenised (rule #44) so a service theme can make it
|
|
19
|
+
* dashed / heavier / none without forking CSS. Pair with
|
|
20
|
+
* --card-header-background-alpha: 0 for a quiet borderless-band header. */
|
|
21
|
+
--card-header-border-bottom: 1px solid hsl(var(--card-border));
|
|
18
22
|
--card-radius: var(--radius);
|
|
19
23
|
--stat-card-label-font-size: var(--font-size-xs);
|
|
20
24
|
--stat-card-label-font-weight: var(--font-weight-medium);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* Form layout tokens: horizontal-layout label column geometry. */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
/* Width of the label column in horizontal/inline layout. A service theme sets
|
|
5
|
+
* this once (e.g. 110px) to align every form to its design grid; the Form/
|
|
6
|
+
* FormField `labelWidth` prop overrides per form/field. */
|
|
7
|
+
--form-label-width: max-content;
|
|
8
|
+
|
|
9
|
+
/* Column gap between the label and its control in horizontal/inline layout. */
|
|
10
|
+
--form-label-gap: var(--space-4); /* 16px */
|
|
11
|
+
}
|
|
@@ -22,6 +22,17 @@
|
|
|
22
22
|
--space-page-active-y: var(--space-page-y);
|
|
23
23
|
--space-section-active: var(--space-section);
|
|
24
24
|
|
|
25
|
+
/* Full-bleed rule under the PageContainer header. OFF by default — the title/body
|
|
26
|
+
* gap already separates them; a divider is a service-theme opt-in:
|
|
27
|
+
* `--page-header-divider: 1px solid hsl(var(--border));` */
|
|
28
|
+
--page-header-divider: none;
|
|
29
|
+
|
|
30
|
+
/* Bottom inset of the page header, sized so title→body distance (this pad + the
|
|
31
|
+
* --space-section-active container gap) EQUALS the page's top padding — the title
|
|
32
|
+
* band reads vertically balanced (24 above / 24 below by default), instead of the
|
|
33
|
+
* old fixed 16px pad that left 24 above vs 32 below. */
|
|
34
|
+
--page-header-pad-bottom: calc(var(--space-page-active-y) - var(--space-section-active));
|
|
35
|
+
|
|
25
36
|
/* Section "chrome" padding — the SHARED inset for header / body / footer of every overlay-ish
|
|
26
37
|
* surface (Dialog · Sheet · Drawer · Card). One global knob: a service sets these once instead of
|
|
27
38
|
* per-component. Vertical is tightened (16 vs the old 24) and density-aware (see density.css);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@10.29.1",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -266,14 +266,15 @@
|
|
|
266
266
|
"test:watch": "vitest",
|
|
267
267
|
"test:coverage": "vitest run --coverage",
|
|
268
268
|
"check:example-imports": "node scripts/check-example-imports.mjs",
|
|
269
|
-
"verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm test",
|
|
270
|
-
"verify:release": "pnpm typecheck && pnpm lint && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:mcp-prop-sync && pnpm test",
|
|
269
|
+
"verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm test",
|
|
270
|
+
"verify:release": "pnpm typecheck && pnpm lint && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:rtl && pnpm check:mcp-sync && pnpm check:mcp-orphans && pnpm check:mcp-prop-sync && pnpm test",
|
|
271
271
|
"check:mcp-sync": "node scripts/check-mcp-sync.mjs",
|
|
272
272
|
"check:mcp-orphans": "node scripts/check-mcp-orphans.mjs",
|
|
273
273
|
"check:mcp-prop-sync": "node scripts/check-mcp-prop-sync.mjs",
|
|
274
274
|
"check:prop-vocabulary": "node scripts/check-prop-vocabulary.mjs",
|
|
275
275
|
"check:token-tiers": "node scripts/check-token-tiers.mjs",
|
|
276
276
|
"check:control-sizing": "node scripts/check-control-sizing.mjs",
|
|
277
|
+
"check:rtl": "node scripts/check-rtl.mjs",
|
|
277
278
|
"check:core-isolation": "node scripts/check-core-isolation.mjs",
|
|
278
279
|
"release": "node scripts/release.mjs",
|
|
279
280
|
"preview": "node preview/scripts/kill-port.mjs && vite --config preview/vite.config.ts --port 6008 --strictPort",
|
|
@@ -281,6 +282,7 @@
|
|
|
281
282
|
"docs:sync-primitives": "node preview/scripts/sync-primitive-docs.mjs && prettier --write \"docs/primitives/**/*.tsx\"",
|
|
282
283
|
"audit": "node scripts/ui-audit.mjs",
|
|
283
284
|
"build": "tsup && node scripts/copy-styles.mjs",
|
|
285
|
+
"dev": "node scripts/dev.mjs",
|
|
284
286
|
"prepublishOnly": "pnpm run build"
|
|
285
287
|
},
|
|
286
288
|
"peerDependencies": {
|
package/dist/chunk-3ZNSR2NL.js
DELETED
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
import { Input } from './chunk-6AIYMYSG.js';
|
|
2
|
-
import { Button } from './chunk-5L77S5CL.js';
|
|
3
|
-
import { useTranslation } from './chunk-QTEPKNQE.js';
|
|
4
|
-
import { cn } from './chunk-U7N2A7A3.js';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import { ChevronUp, ChevronDown, EyeOff, Eye, Minus, Star, X } from 'lucide-react';
|
|
7
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
-
import { OTPInput, OTPInputContext } from 'input-otp';
|
|
9
|
-
|
|
10
|
-
function decimalsOf(n) {
|
|
11
|
-
if (!Number.isFinite(n)) return 0;
|
|
12
|
-
const s = String(n);
|
|
13
|
-
const dot = s.indexOf(".");
|
|
14
|
-
return dot === -1 ? 0 : s.length - dot - 1;
|
|
15
|
-
}
|
|
16
|
-
function clamp(n, min, max) {
|
|
17
|
-
let out = n;
|
|
18
|
-
if (min != null && out < min) out = min;
|
|
19
|
-
if (max != null && out > max) out = max;
|
|
20
|
-
return out;
|
|
21
|
-
}
|
|
22
|
-
function roundTo(n, precision) {
|
|
23
|
-
if (!Number.isFinite(n)) return n;
|
|
24
|
-
const factor = 10 ** precision;
|
|
25
|
-
return Math.round((n + Number.EPSILON) * factor) / factor;
|
|
26
|
-
}
|
|
27
|
-
var NumberInput = React.forwardRef(
|
|
28
|
-
({
|
|
29
|
-
value: controlledValue,
|
|
30
|
-
defaultValue = null,
|
|
31
|
-
onValueChange,
|
|
32
|
-
min,
|
|
33
|
-
max,
|
|
34
|
-
step = 1,
|
|
35
|
-
precision,
|
|
36
|
-
disabled,
|
|
37
|
-
readOnly,
|
|
38
|
-
size = "md",
|
|
39
|
-
placeholder,
|
|
40
|
-
prefix,
|
|
41
|
-
suffix,
|
|
42
|
-
name,
|
|
43
|
-
id,
|
|
44
|
-
className,
|
|
45
|
-
"aria-label": ariaLabel,
|
|
46
|
-
"aria-labelledby": ariaLabelledby,
|
|
47
|
-
"aria-describedby": ariaDescribedby,
|
|
48
|
-
"data-testid": dataTestId
|
|
49
|
-
}, ref) => {
|
|
50
|
-
const { t, locale } = useTranslation();
|
|
51
|
-
const isControlled = controlledValue !== void 0;
|
|
52
|
-
const [internal, setInternal] = React.useState(defaultValue);
|
|
53
|
-
const numericValue = isControlled ? controlledValue ?? null : internal;
|
|
54
|
-
const effectivePrecision = precision ?? decimalsOf(step);
|
|
55
|
-
const formatter = React.useMemo(
|
|
56
|
-
() => new Intl.NumberFormat(locale, {
|
|
57
|
-
minimumFractionDigits: 0,
|
|
58
|
-
maximumFractionDigits: Math.max(effectivePrecision, 0),
|
|
59
|
-
useGrouping: false
|
|
60
|
-
}),
|
|
61
|
-
[locale, effectivePrecision]
|
|
62
|
-
);
|
|
63
|
-
const formatAtRest = React.useCallback(
|
|
64
|
-
(n) => n == null ? "" : formatter.format(n),
|
|
65
|
-
[formatter]
|
|
66
|
-
);
|
|
67
|
-
const [draft, setDraft] = React.useState(() => formatAtRest(numericValue));
|
|
68
|
-
const [focused, setFocused] = React.useState(false);
|
|
69
|
-
React.useEffect(() => {
|
|
70
|
-
if (focused) return;
|
|
71
|
-
setDraft(formatAtRest(numericValue));
|
|
72
|
-
}, [numericValue, focused, formatAtRest]);
|
|
73
|
-
const commit = React.useCallback(
|
|
74
|
-
(next) => {
|
|
75
|
-
const normalized = next == null || Number.isNaN(next) ? null : roundTo(clamp(next, min, max), effectivePrecision);
|
|
76
|
-
if (!isControlled) setInternal(normalized);
|
|
77
|
-
onValueChange?.(normalized);
|
|
78
|
-
if (!focused) setDraft(formatAtRest(normalized));
|
|
79
|
-
return normalized;
|
|
80
|
-
},
|
|
81
|
-
[effectivePrecision, focused, formatAtRest, isControlled, max, min, onValueChange]
|
|
82
|
-
);
|
|
83
|
-
const stepBy = React.useCallback(
|
|
84
|
-
(direction, multiplier = 1) => {
|
|
85
|
-
const base = numericValue ?? min ?? 0;
|
|
86
|
-
const next = base + direction * step * multiplier;
|
|
87
|
-
const committed = commit(next);
|
|
88
|
-
setDraft(formatAtRest(committed));
|
|
89
|
-
},
|
|
90
|
-
[commit, formatAtRest, min, numericValue, step]
|
|
91
|
-
);
|
|
92
|
-
const atMin = min != null && numericValue != null && numericValue <= min;
|
|
93
|
-
const atMax = max != null && numericValue != null && numericValue >= max;
|
|
94
|
-
const interactive = !disabled && !readOnly;
|
|
95
|
-
const handleChange = (event) => {
|
|
96
|
-
const raw = event.target.value;
|
|
97
|
-
setDraft(raw);
|
|
98
|
-
if (readOnly) return;
|
|
99
|
-
const trimmed = raw.trim();
|
|
100
|
-
if (trimmed === "" || trimmed === "-") {
|
|
101
|
-
if (trimmed === "") commit(null);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const parsed = Number(trimmed);
|
|
105
|
-
if (Number.isNaN(parsed)) return;
|
|
106
|
-
if (!isControlled) setInternal(parsed);
|
|
107
|
-
onValueChange?.(parsed);
|
|
108
|
-
};
|
|
109
|
-
const handleBlur = () => {
|
|
110
|
-
setFocused(false);
|
|
111
|
-
const trimmed = draft.trim();
|
|
112
|
-
if (trimmed === "" || trimmed === "-") {
|
|
113
|
-
commit(null);
|
|
114
|
-
setDraft(formatAtRest(null));
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const parsed = Number(trimmed);
|
|
118
|
-
const committed = commit(Number.isNaN(parsed) ? null : parsed);
|
|
119
|
-
setDraft(formatAtRest(committed));
|
|
120
|
-
};
|
|
121
|
-
const handleKeyDown = (event) => {
|
|
122
|
-
if (!interactive) return;
|
|
123
|
-
if (event.key === "ArrowUp") {
|
|
124
|
-
event.preventDefault();
|
|
125
|
-
stepBy(1, event.shiftKey ? 10 : 1);
|
|
126
|
-
} else if (event.key === "ArrowDown") {
|
|
127
|
-
event.preventDefault();
|
|
128
|
-
stepBy(-1, event.shiftKey ? 10 : 1);
|
|
129
|
-
} else if (event.key === "Enter") {
|
|
130
|
-
const trimmed = draft.trim();
|
|
131
|
-
const parsed = Number(trimmed);
|
|
132
|
-
const committed = commit(trimmed === "" || Number.isNaN(parsed) ? null : parsed);
|
|
133
|
-
setDraft(formatAtRest(committed));
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
return /* @__PURE__ */ jsxs("div", { "data-slot": "number-input", "data-size": size, className: cn("ui-number-input", className), children: [
|
|
137
|
-
prefix != null ? /* @__PURE__ */ jsx(
|
|
138
|
-
"span",
|
|
139
|
-
{
|
|
140
|
-
"data-slot": "number-input-prefix",
|
|
141
|
-
className: "ui-number-input-affix",
|
|
142
|
-
"aria-hidden": "true",
|
|
143
|
-
children: prefix
|
|
144
|
-
}
|
|
145
|
-
) : null,
|
|
146
|
-
/* @__PURE__ */ jsx(
|
|
147
|
-
Input,
|
|
148
|
-
{
|
|
149
|
-
ref,
|
|
150
|
-
id,
|
|
151
|
-
name,
|
|
152
|
-
type: "text",
|
|
153
|
-
inputMode: "decimal",
|
|
154
|
-
autoComplete: "off",
|
|
155
|
-
role: "spinbutton",
|
|
156
|
-
"data-slot": "number-input-field",
|
|
157
|
-
"data-testid": dataTestId,
|
|
158
|
-
className: "ui-number-input-field",
|
|
159
|
-
value: draft,
|
|
160
|
-
placeholder,
|
|
161
|
-
disabled,
|
|
162
|
-
readOnly,
|
|
163
|
-
"aria-label": ariaLabel,
|
|
164
|
-
"aria-labelledby": ariaLabelledby,
|
|
165
|
-
"aria-describedby": ariaDescribedby,
|
|
166
|
-
"aria-valuenow": numericValue ?? void 0,
|
|
167
|
-
"aria-valuemin": min,
|
|
168
|
-
"aria-valuemax": max,
|
|
169
|
-
"aria-valuetext": numericValue != null ? formatAtRest(numericValue) : void 0,
|
|
170
|
-
onChange: handleChange,
|
|
171
|
-
onFocus: () => setFocused(true),
|
|
172
|
-
onBlur: handleBlur,
|
|
173
|
-
onKeyDown: handleKeyDown
|
|
174
|
-
}
|
|
175
|
-
),
|
|
176
|
-
suffix != null ? /* @__PURE__ */ jsx(
|
|
177
|
-
"span",
|
|
178
|
-
{
|
|
179
|
-
"data-slot": "number-input-suffix",
|
|
180
|
-
className: "ui-number-input-affix",
|
|
181
|
-
"aria-hidden": "true",
|
|
182
|
-
children: suffix
|
|
183
|
-
}
|
|
184
|
-
) : null,
|
|
185
|
-
/* @__PURE__ */ jsxs("span", { "data-slot": "number-input-steppers", className: "ui-number-input-steppers", children: [
|
|
186
|
-
/* @__PURE__ */ jsx(
|
|
187
|
-
Button,
|
|
188
|
-
{
|
|
189
|
-
type: "button",
|
|
190
|
-
variant: "outline",
|
|
191
|
-
size: "icon-xs",
|
|
192
|
-
className: "ui-number-input-step ui-number-input-step-up",
|
|
193
|
-
tabIndex: -1,
|
|
194
|
-
disabled: !interactive || atMax,
|
|
195
|
-
"aria-label": t("ui.numberInput.increment"),
|
|
196
|
-
onClick: () => stepBy(1),
|
|
197
|
-
children: /* @__PURE__ */ jsx(ChevronUp, { "aria-hidden": "true" })
|
|
198
|
-
}
|
|
199
|
-
),
|
|
200
|
-
/* @__PURE__ */ jsx(
|
|
201
|
-
Button,
|
|
202
|
-
{
|
|
203
|
-
type: "button",
|
|
204
|
-
variant: "outline",
|
|
205
|
-
size: "icon-xs",
|
|
206
|
-
className: "ui-number-input-step ui-number-input-step-down",
|
|
207
|
-
tabIndex: -1,
|
|
208
|
-
disabled: !interactive || atMin,
|
|
209
|
-
"aria-label": t("ui.numberInput.decrement"),
|
|
210
|
-
onClick: () => stepBy(-1),
|
|
211
|
-
children: /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" })
|
|
212
|
-
}
|
|
213
|
-
)
|
|
214
|
-
] })
|
|
215
|
-
] });
|
|
216
|
-
}
|
|
217
|
-
);
|
|
218
|
-
NumberInput.displayName = "NumberInput";
|
|
219
|
-
var PasswordInput = React.forwardRef(
|
|
220
|
-
({ className, ...props }, ref) => {
|
|
221
|
-
const { t } = useTranslation();
|
|
222
|
-
const [visible, setVisible] = React.useState(false);
|
|
223
|
-
return /* @__PURE__ */ jsxs("div", { className: "ui-password-input", "data-slot": "password-input", children: [
|
|
224
|
-
/* @__PURE__ */ jsx(
|
|
225
|
-
Input,
|
|
226
|
-
{
|
|
227
|
-
ref,
|
|
228
|
-
type: visible ? "text" : "password",
|
|
229
|
-
className: cn("ui-password-input-field", className),
|
|
230
|
-
...props
|
|
231
|
-
}
|
|
232
|
-
),
|
|
233
|
-
/* @__PURE__ */ jsx(
|
|
234
|
-
"button",
|
|
235
|
-
{
|
|
236
|
-
type: "button",
|
|
237
|
-
className: "ui-password-input-toggle",
|
|
238
|
-
onClick: () => setVisible((v) => !v),
|
|
239
|
-
"aria-label": visible ? t("ui.passwordInput.hide") : t("ui.passwordInput.show"),
|
|
240
|
-
"aria-pressed": visible,
|
|
241
|
-
children: visible ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": "true" })
|
|
242
|
-
}
|
|
243
|
-
)
|
|
244
|
-
] });
|
|
245
|
-
}
|
|
246
|
-
);
|
|
247
|
-
PasswordInput.displayName = "PasswordInput";
|
|
248
|
-
var InputOTP = React.forwardRef(({ className, containerClassName, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
249
|
-
OTPInput,
|
|
250
|
-
{
|
|
251
|
-
ref,
|
|
252
|
-
"data-slot": "input-otp",
|
|
253
|
-
containerClassName: cn("ui-otp-container", containerClassName),
|
|
254
|
-
className: cn("ui-otp-input", className),
|
|
255
|
-
...props
|
|
256
|
-
}
|
|
257
|
-
));
|
|
258
|
-
InputOTP.displayName = "InputOTP";
|
|
259
|
-
var InputOTPGroup = React.forwardRef(
|
|
260
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
261
|
-
"div",
|
|
262
|
-
{
|
|
263
|
-
ref,
|
|
264
|
-
"data-slot": "input-otp-group",
|
|
265
|
-
className: cn("ui-otp-group", className),
|
|
266
|
-
...props
|
|
267
|
-
}
|
|
268
|
-
)
|
|
269
|
-
);
|
|
270
|
-
InputOTPGroup.displayName = "InputOTPGroup";
|
|
271
|
-
var InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => {
|
|
272
|
-
const context = React.useContext(OTPInputContext);
|
|
273
|
-
const slot = context.slots[index] ?? { char: null, hasFakeCaret: false, isActive: false };
|
|
274
|
-
return /* @__PURE__ */ jsxs(
|
|
275
|
-
"div",
|
|
276
|
-
{
|
|
277
|
-
ref,
|
|
278
|
-
"data-slot": "input-otp-slot",
|
|
279
|
-
"data-active": slot.isActive || void 0,
|
|
280
|
-
className: cn("ui-otp-slot", className),
|
|
281
|
-
...props,
|
|
282
|
-
children: [
|
|
283
|
-
slot.char,
|
|
284
|
-
slot.hasFakeCaret ? /* @__PURE__ */ jsx("div", { className: "ui-otp-caret-wrapper", "aria-hidden": "true", children: /* @__PURE__ */ jsx("div", { className: "ui-otp-caret" }) }) : null
|
|
285
|
-
]
|
|
286
|
-
}
|
|
287
|
-
);
|
|
288
|
-
});
|
|
289
|
-
InputOTPSlot.displayName = "InputOTPSlot";
|
|
290
|
-
var InputOTPSeparator = React.forwardRef(({ ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, "data-slot": "input-otp-separator", role: "separator", ...props, children: /* @__PURE__ */ jsx(Minus, { className: "ui-otp-separator-icon", "aria-hidden": "true" }) }));
|
|
291
|
-
InputOTPSeparator.displayName = "InputOTPSeparator";
|
|
292
|
-
var Rating = React.forwardRef(
|
|
293
|
-
({
|
|
294
|
-
value,
|
|
295
|
-
defaultValue = 0,
|
|
296
|
-
onValueChange,
|
|
297
|
-
max = 5,
|
|
298
|
-
readOnly,
|
|
299
|
-
disabled,
|
|
300
|
-
name,
|
|
301
|
-
className,
|
|
302
|
-
...rest
|
|
303
|
-
}, ref) => {
|
|
304
|
-
const { t } = useTranslation();
|
|
305
|
-
const [internal, setInternal] = React.useState(defaultValue);
|
|
306
|
-
const current = value ?? internal;
|
|
307
|
-
const [hover, setHover] = React.useState(null);
|
|
308
|
-
const display = hover ?? current;
|
|
309
|
-
const interactive = !readOnly && !disabled;
|
|
310
|
-
const select = (next) => {
|
|
311
|
-
if (!interactive) return;
|
|
312
|
-
if (value === void 0) setInternal(next);
|
|
313
|
-
onValueChange?.(next);
|
|
314
|
-
};
|
|
315
|
-
const focusableStar = current > 0 ? current : 1;
|
|
316
|
-
const onKeyDown = (e, star) => {
|
|
317
|
-
if (!interactive) return;
|
|
318
|
-
let next = null;
|
|
319
|
-
switch (e.key) {
|
|
320
|
-
case "ArrowRight":
|
|
321
|
-
case "ArrowUp":
|
|
322
|
-
next = Math.min(max, star + 1);
|
|
323
|
-
break;
|
|
324
|
-
case "ArrowLeft":
|
|
325
|
-
case "ArrowDown":
|
|
326
|
-
next = Math.max(1, star - 1);
|
|
327
|
-
break;
|
|
328
|
-
case "Home":
|
|
329
|
-
next = 1;
|
|
330
|
-
break;
|
|
331
|
-
case "End":
|
|
332
|
-
next = max;
|
|
333
|
-
break;
|
|
334
|
-
default:
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
e.preventDefault();
|
|
338
|
-
select(next);
|
|
339
|
-
};
|
|
340
|
-
return /* @__PURE__ */ jsxs(
|
|
341
|
-
"div",
|
|
342
|
-
{
|
|
343
|
-
ref,
|
|
344
|
-
role: "radiogroup",
|
|
345
|
-
"data-slot": "rating",
|
|
346
|
-
className: cn("ui-rating", className),
|
|
347
|
-
"aria-label": rest["aria-label"] ?? t("ui.rating.ariaLabel"),
|
|
348
|
-
children: [
|
|
349
|
-
Array.from({ length: max }, (_, i) => i + 1).map((star) => /* @__PURE__ */ jsx(
|
|
350
|
-
"button",
|
|
351
|
-
{
|
|
352
|
-
type: "button",
|
|
353
|
-
role: "radio",
|
|
354
|
-
"aria-checked": current === star,
|
|
355
|
-
"aria-label": t("ui.rating.starLabel", { star, max }),
|
|
356
|
-
disabled: disabled || readOnly,
|
|
357
|
-
tabIndex: interactive && star === focusableStar ? 0 : -1,
|
|
358
|
-
className: cn("ui-rating-star", star <= display && "ui-rating-star-filled"),
|
|
359
|
-
onMouseEnter: () => interactive && setHover(star),
|
|
360
|
-
onMouseLeave: () => setHover(null),
|
|
361
|
-
onClick: () => select(star),
|
|
362
|
-
onKeyDown: (e) => onKeyDown(e, star),
|
|
363
|
-
children: /* @__PURE__ */ jsx(Star, { "aria-hidden": "true" })
|
|
364
|
-
},
|
|
365
|
-
star
|
|
366
|
-
)),
|
|
367
|
-
name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: current }) : null
|
|
368
|
-
]
|
|
369
|
-
}
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
);
|
|
373
|
-
Rating.displayName = "Rating";
|
|
374
|
-
var TagInput = React.forwardRef(
|
|
375
|
-
({
|
|
376
|
-
value,
|
|
377
|
-
defaultValue = [],
|
|
378
|
-
onValueChange,
|
|
379
|
-
placeholder,
|
|
380
|
-
disabled,
|
|
381
|
-
name,
|
|
382
|
-
className,
|
|
383
|
-
id,
|
|
384
|
-
"aria-label": ariaLabel
|
|
385
|
-
}, ref) => {
|
|
386
|
-
const { t } = useTranslation();
|
|
387
|
-
const [internal, setInternal] = React.useState(defaultValue);
|
|
388
|
-
const tags = value ?? internal;
|
|
389
|
-
const [draft, setDraft] = React.useState("");
|
|
390
|
-
const commit = (next) => {
|
|
391
|
-
if (value === void 0) setInternal(next);
|
|
392
|
-
onValueChange?.(next);
|
|
393
|
-
};
|
|
394
|
-
const add = (raw) => {
|
|
395
|
-
const tag = raw.trim();
|
|
396
|
-
if (!tag || tags.includes(tag)) return;
|
|
397
|
-
commit([...tags, tag]);
|
|
398
|
-
};
|
|
399
|
-
const removeAt = (i) => commit(tags.filter((_, idx) => idx !== i));
|
|
400
|
-
const onKeyDown = (e) => {
|
|
401
|
-
if (e.key === "Enter" || e.key === ",") {
|
|
402
|
-
e.preventDefault();
|
|
403
|
-
add(draft);
|
|
404
|
-
setDraft("");
|
|
405
|
-
} else if (e.key === "Backspace" && draft === "" && tags.length > 0) {
|
|
406
|
-
removeAt(tags.length - 1);
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
return /* @__PURE__ */ jsxs(
|
|
410
|
-
"div",
|
|
411
|
-
{
|
|
412
|
-
"data-slot": "tag-input",
|
|
413
|
-
className: cn("ui-tag-input", disabled && "ui-tag-input-disabled", className),
|
|
414
|
-
children: [
|
|
415
|
-
tags.length > 0 ? /* @__PURE__ */ jsx("ul", { role: "list", className: "ui-tag-input-list", "data-slot": "tag-input-list", children: tags.map((tag, i) => /* @__PURE__ */ jsxs(
|
|
416
|
-
"li",
|
|
417
|
-
{
|
|
418
|
-
role: "listitem",
|
|
419
|
-
className: "ui-tag-input-chip",
|
|
420
|
-
"data-slot": "tag-input-chip",
|
|
421
|
-
children: [
|
|
422
|
-
tag,
|
|
423
|
-
!disabled ? /* @__PURE__ */ jsx(
|
|
424
|
-
"button",
|
|
425
|
-
{
|
|
426
|
-
type: "button",
|
|
427
|
-
className: "ui-tag-input-remove",
|
|
428
|
-
"aria-label": t("ui.tagInput.removeTag", { tag }),
|
|
429
|
-
onClick: () => removeAt(i),
|
|
430
|
-
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
431
|
-
}
|
|
432
|
-
) : null
|
|
433
|
-
]
|
|
434
|
-
},
|
|
435
|
-
tag
|
|
436
|
-
)) }) : null,
|
|
437
|
-
/* @__PURE__ */ jsx(
|
|
438
|
-
"input",
|
|
439
|
-
{
|
|
440
|
-
ref,
|
|
441
|
-
id,
|
|
442
|
-
type: "text",
|
|
443
|
-
className: "ui-tag-input-field",
|
|
444
|
-
value: draft,
|
|
445
|
-
placeholder: tags.length === 0 ? placeholder : void 0,
|
|
446
|
-
disabled,
|
|
447
|
-
"aria-label": ariaLabel ?? t("ui.tagInput.inputLabel"),
|
|
448
|
-
onChange: (e) => setDraft(e.target.value),
|
|
449
|
-
onKeyDown,
|
|
450
|
-
onBlur: () => {
|
|
451
|
-
if (draft.trim()) {
|
|
452
|
-
add(draft);
|
|
453
|
-
setDraft("");
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
),
|
|
458
|
-
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", "data-slot": "tag-input-status", children: t("ui.tagInput.tagCount", { count: tags.length }) }),
|
|
459
|
-
name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: tags.join(",") }) : null
|
|
460
|
-
]
|
|
461
|
-
}
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
);
|
|
465
|
-
TagInput.displayName = "TagInput";
|
|
466
|
-
|
|
467
|
-
export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, NumberInput, PasswordInput, Rating, TagInput };
|