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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tabsir Ahammed
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# premium-ds
|
|
2
|
+
|
|
3
|
+
A premium React design system - modern CSS + a small, closed token vocabulary, applied
|
|
4
|
+
consistently. Restraint, calm motion, no Tailwind, no CSS-in-JS, no UI libraries.
|
|
5
|
+
|
|
6
|
+
**React 19 - TypeScript - ships compiled ESM + types.** Import the whole library or a single
|
|
7
|
+
component; link one stylesheet.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add premium-ds
|
|
13
|
+
# peers (you likely already have them):
|
|
14
|
+
pnpm add react react-dom motion
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Peer | Range | Used for |
|
|
18
|
+
| --------------------- | ----- | -------------------------------------------------------------------- |
|
|
19
|
+
| `react` / `react-dom` | `^19` | components; `createRoot`/`createPortal` for imperative toast/tooltip |
|
|
20
|
+
| `motion` | `^12` | enter/exit + layout animation (`motion/react`) |
|
|
21
|
+
|
|
22
|
+
Icons are **bundled** (a small curated Phosphor set) - there is no icon peer to install.
|
|
23
|
+
|
|
24
|
+
## Use it
|
|
25
|
+
|
|
26
|
+
No bundler config and no `transpilePackages` - the package ships built ESM with the `'use client'`
|
|
27
|
+
directives intact, so Next.js App Router boundaries just work.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { Button, toast } from 'premium-ds';
|
|
31
|
+
import 'premium-ds/styles.css'; // link once, at the app root
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Link `styles.css` exactly once - it's the full token + component manifest
|
|
35
|
+
(fonts - primitives - semantics - components).
|
|
36
|
+
|
|
37
|
+
### Import a single component
|
|
38
|
+
|
|
39
|
+
Every component is also a subpath export, so you can pull just one:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { Button } from 'premium-ds/button';
|
|
43
|
+
import { DateField } from 'premium-ds/date-field';
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The barrel is side-effect-free and tree-shakes, so `import { Button } from 'premium-ds'` is
|
|
47
|
+
equally lean in a bundler - subpaths help in non-bundled or explicit setups.
|
|
48
|
+
|
|
49
|
+
## Components
|
|
50
|
+
|
|
51
|
+
| Group | Components |
|
|
52
|
+
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
53
|
+
| Primitives | Button, Collapse, Badge, StatusBadge, CountBadge |
|
|
54
|
+
| Forms | TextField, NumberField, OtpField, Textarea, Checkbox, Toggle, RadioGroup, Select, MultiSelect |
|
|
55
|
+
| Data | Avatar, AvatarGroup, Tag, ToggleTag, Table, Pagination |
|
|
56
|
+
| Date, time & tabs | DateField, DateTimeField, DateRangeField, TimeField, Tabs |
|
|
57
|
+
| Overlays & feedback | Alert, Toast, Tooltip, Dialog, Overlay, Sheet |
|
|
58
|
+
|
|
59
|
+
Each is a named export from the barrel and a subpath (`premium-ds/<kebab-name>`). Props are
|
|
60
|
+
documented inline in the types; see [`llms.txt`](./llms.txt) for per-component examples.
|
|
61
|
+
|
|
62
|
+
## For AI coding agents
|
|
63
|
+
|
|
64
|
+
Once installed, an agent doesn't need to read the component source - the contract is the shipped
|
|
65
|
+
types:
|
|
66
|
+
|
|
67
|
+
- **`node_modules/premium-ds/dist/*.d.ts`** - every component's props carry inline TSDoc. This is
|
|
68
|
+
the machine-readable source of truth (e.g. `dist/button.d.ts` fully describes `ButtonProps`).
|
|
69
|
+
- **`llms.txt`** (package root) - a compact, per-component index: purpose - import - a minimal
|
|
70
|
+
example. Cheaper to scan than every `.d.ts`.
|
|
71
|
+
- This README.
|
|
72
|
+
|
|
73
|
+
## Copy-paste instead
|
|
74
|
+
|
|
75
|
+
The tarball also ships `src/`, so you can lift a component straight from
|
|
76
|
+
`node_modules/premium-ds/src/components/<name>/` into your project. Components aren't fully
|
|
77
|
+
self-contained - they share `src/tokens/`, the `motion-tokens` bridge, the internal `icon/`, and a
|
|
78
|
+
few `*-core` helpers - so copy those alongside. (A shadcn-style registry/CLI could automate this
|
|
79
|
+
later.)
|
|
80
|
+
|
|
81
|
+
## Icons
|
|
82
|
+
|
|
83
|
+
Components render their own glyphs from a small curated Phosphor set, **bundled in** - no icon peer
|
|
84
|
+
to install. premium-ds does **not** export an `Icon` component, so where a prop takes an icon
|
|
85
|
+
(`iconLeft`, `leadingIcon`, a `Tag`'s `icon`, ...) pass your own node - any `ReactNode` (e.g. an
|
|
86
|
+
`@phosphor-icons/react` element, if you choose to use it).
|
|
87
|
+
|
|
88
|
+
## What's inside
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
src/ source (also shipped, for copy-paste)
|
|
92
|
+
-- index.ts public barrel
|
|
93
|
+
-- styles.css @import manifest (link once)
|
|
94
|
+
-- tokens/ CSS custom properties + motion-tokens.ts (JS and CSS motion bridge)
|
|
95
|
+
-- components/ <domain>/Name.tsx + name.css
|
|
96
|
+
dist/ compiled ESM + .d.ts - what you import
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Notes
|
|
100
|
+
|
|
101
|
+
- **Fonts.** `src/tokens/fonts.css` pulls Geist + Geist Mono from Google Fonts via a remote
|
|
102
|
+
`@import`. Self-host the families to drop the render-blocking network hop.
|
|
103
|
+
- **Styling is token-driven.** Re-skin by overriding the CSS custom properties in your own
|
|
104
|
+
stylesheet loaded after `premium-ds/styles.css` - never fork the source.
|
|
105
|
+
|
|
106
|
+
## Develop
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pnpm install
|
|
110
|
+
pnpm build # tsup - dist/ (ESM + .d.ts)
|
|
111
|
+
pnpm typecheck # tsc --noEmit
|
|
112
|
+
pnpm format # prettier --write
|
|
113
|
+
```
|
package/dist/alert.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type AlertTone = 'info' | 'success' | 'warning' | 'danger';
|
|
4
|
+
interface AlertAction {
|
|
5
|
+
/** Sentence-case label, e.g. "Update billing". */
|
|
6
|
+
label: string;
|
|
7
|
+
onClick?: () => void;
|
|
8
|
+
}
|
|
9
|
+
interface AlertProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
10
|
+
/** Status of the message; info/success are polite, warning/danger assertive. Default 'info'. */
|
|
11
|
+
tone?: AlertTone;
|
|
12
|
+
/** The message - sentence case, ideally one line. */
|
|
13
|
+
title: React.ReactNode;
|
|
14
|
+
/** Optional description; stays neutral - tone marks the message, not the prose. */
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
/** One action max, rendered as the system secondary small button. */
|
|
17
|
+
action?: AlertAction;
|
|
18
|
+
/** Renders the always-visible close button. Uncontrolled unless `open` is given. */
|
|
19
|
+
dismissible?: boolean;
|
|
20
|
+
/** Fires on dismiss. With `open` set, the parent owns hiding the alert. */
|
|
21
|
+
onDismiss?: () => void;
|
|
22
|
+
/** Controlled visibility; omit for uncontrolled. Exit eases shut (height collapse). */
|
|
23
|
+
open?: boolean;
|
|
24
|
+
/** App-level strip: square corners, hairline below only. Paint modifier. */
|
|
25
|
+
banner?: boolean;
|
|
26
|
+
/** Override the tone glyph; pass null to render no glyph. */
|
|
27
|
+
icon?: React.ReactNode | null;
|
|
28
|
+
}
|
|
29
|
+
declare function Alert({ tone, title, children, action, dismissible, onDismiss, open, banner, icon, className, ...rest }: AlertProps): React.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { Alert, type AlertAction, type AlertProps, type AlertTone };
|
package/dist/alert.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"alert.js"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AvatarSize } from './avatar.js';
|
|
3
|
+
|
|
4
|
+
interface AvatarGroupProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/** Max visible avatars before "+N" overflow chip. Default 5. */
|
|
7
|
+
max?: number;
|
|
8
|
+
/** Uniform size applied to all children. Default 'md'. */
|
|
9
|
+
size?: AvatarSize;
|
|
10
|
+
}
|
|
11
|
+
declare function AvatarGroup({ children, max, size, className, ...rest }: AvatarGroupProps): React.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { AvatarGroup, type AvatarGroupProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"avatar-group.js"}
|
package/dist/avatar.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
type AvatarShape = 'circle' | 'square';
|
|
5
|
+
type AvatarStatus = 'online' | 'away' | 'busy' | 'offline';
|
|
6
|
+
type AvatarPaletteIndex = 1 | 2 | 3 | 4 | 5 | 6;
|
|
7
|
+
interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
8
|
+
/** Image URL. Falls back to initials / icon / silhouette if absent or fails. */
|
|
9
|
+
src?: string | null;
|
|
10
|
+
/** Display name - drives initials generation, palette hash, and aria-label. */
|
|
11
|
+
name?: string | null;
|
|
12
|
+
/** Content override - any React node (e.g. <Icon name="globe" />). */
|
|
13
|
+
icon?: React.ReactNode | null;
|
|
14
|
+
/** 'circle' for people; 'square' for channels / brand pages. Default 'circle'. */
|
|
15
|
+
shape?: AvatarShape;
|
|
16
|
+
/** Size step. Default 'md' (32 px). */
|
|
17
|
+
size?: AvatarSize;
|
|
18
|
+
/** Presence indicator dot at bottom-right. Default null (hidden). */
|
|
19
|
+
status?: AvatarStatus | null;
|
|
20
|
+
/** Override identity slot 1-6 (blue - violet - plum - rose - clay - moss); auto from name hash when null, neutral when anonymous. */
|
|
21
|
+
paletteIndex?: AvatarPaletteIndex | null;
|
|
22
|
+
}
|
|
23
|
+
declare function Avatar({ src, name, icon, shape, size, status, paletteIndex, className, style, ...rest }: AvatarProps): React.JSX.Element;
|
|
24
|
+
|
|
25
|
+
export { Avatar, type AvatarPaletteIndex, type AvatarProps, type AvatarShape, type AvatarSize, type AvatarStatus };
|
package/dist/avatar.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"avatar.js"}
|
package/dist/badge.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type BadgeTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
|
|
5
|
+
interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
6
|
+
/** Status hue. @default 'neutral' */
|
|
7
|
+
tone?: BadgeTone;
|
|
8
|
+
/** Surface. @default 'glass' */
|
|
9
|
+
variant?: 'glass' | 'outline';
|
|
10
|
+
/** @default 'md' */
|
|
11
|
+
size?: 'sm' | 'md';
|
|
12
|
+
/** Leading status dot. */
|
|
13
|
+
dot?: boolean;
|
|
14
|
+
/** Dot pulses (implies dot) - for in-progress status. */
|
|
15
|
+
live?: boolean;
|
|
16
|
+
/** Fully-rounded shape. */
|
|
17
|
+
pill?: boolean;
|
|
18
|
+
/** Optional leading <Icon> (overrides dot if both set). */
|
|
19
|
+
icon?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
declare function Badge({ tone, variant, size, dot, live, pill, icon, className, children, ...rest }: BadgeProps): React.JSX.Element;
|
|
22
|
+
|
|
23
|
+
export { Badge, type BadgeProps, type BadgeTone };
|
package/dist/badge.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"badge.js"}
|
package/dist/button.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
/** Visual weight / intent. @default 'primary' */
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'link';
|
|
7
|
+
/** Control height. sm 28px - md 36px (default) - lg 40px. @default 'md' */
|
|
8
|
+
size?: 'sm' | 'md' | 'lg';
|
|
9
|
+
/** Loading - swaps content for a spinner and makes the button inert. */
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
/** Leading icon node (e.g. a 16px <Icon>). Sized & aligned by the component. */
|
|
12
|
+
iconLeft?: ReactNode;
|
|
13
|
+
/** Trailing icon node. */
|
|
14
|
+
iconRight?: ReactNode;
|
|
15
|
+
/** Stretch to fill the container width. */
|
|
16
|
+
fullWidth?: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare function Button({ variant, size, type, disabled, loading, iconLeft, iconRight, fullWidth, className, children, ...rest }: ButtonProps): React.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { Button, type ButtonProps };
|
package/dist/button.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"button.js"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
|
|
4
|
+
/** Controlled checked state. Omit for uncontrolled (use `defaultChecked`). */
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
/** Uncontrolled initial state. */
|
|
7
|
+
defaultChecked?: boolean;
|
|
8
|
+
/** Indeterminate - the "some, not all" select-all state; visually wins over `checked`. @default false */
|
|
9
|
+
indeterminate?: boolean;
|
|
10
|
+
/** Single error state for consent gates ("you must agree"); also sets `aria-invalid`. @default false */
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
/** Disabled - inert and de-emphasized (distinct fill when checked). */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Box size: `md` 18px - `sm` 16px for dense table rows. @default 'md' */
|
|
15
|
+
size?: 'sm' | 'md';
|
|
16
|
+
/** Label text beside the box. */
|
|
17
|
+
label?: React.ReactNode;
|
|
18
|
+
/** Optional secondary line under the label (settings rows). */
|
|
19
|
+
description?: React.ReactNode;
|
|
20
|
+
/** Fires on toggle - read `e.target.checked`. */
|
|
21
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
|
|
22
|
+
}
|
|
23
|
+
declare function Checkbox({ checked, defaultChecked, indeterminate, invalid, disabled, size, label, description, className, onChange, ...rest }: CheckboxProps): React.JSX.Element;
|
|
24
|
+
|
|
25
|
+
export { Checkbox, type CheckboxProps };
|
package/dist/checkbox.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"checkbox.js"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
// src/components/badge/Badge.tsx
|
|
4
|
+
function Badge({
|
|
5
|
+
tone = "neutral",
|
|
6
|
+
variant = "glass",
|
|
7
|
+
size = "md",
|
|
8
|
+
dot = false,
|
|
9
|
+
live = false,
|
|
10
|
+
pill = false,
|
|
11
|
+
icon = null,
|
|
12
|
+
className = "",
|
|
13
|
+
children,
|
|
14
|
+
...rest
|
|
15
|
+
}) {
|
|
16
|
+
const isGlass = variant !== "outline";
|
|
17
|
+
const classes = [
|
|
18
|
+
isGlass ? "glass glass--interactive" : "",
|
|
19
|
+
"badge",
|
|
20
|
+
`badge--${tone}`,
|
|
21
|
+
variant === "outline" ? "badge--outline" : "",
|
|
22
|
+
size !== "md" ? `badge--${size}` : "",
|
|
23
|
+
pill ? "badge--pill" : "",
|
|
24
|
+
className
|
|
25
|
+
].filter(Boolean).join(" ");
|
|
26
|
+
const showDot = (dot || live) && !icon;
|
|
27
|
+
return /* @__PURE__ */ jsxs("span", { className: classes, ...rest, children: [
|
|
28
|
+
showDot ? /* @__PURE__ */ jsx("span", { className: `badge__dot${live ? " badge__dot--live" : ""}`, "aria-hidden": "true" }) : null,
|
|
29
|
+
icon ? /* @__PURE__ */ jsx("span", { className: "badge__icon", "aria-hidden": "true", children: icon }) : null,
|
|
30
|
+
/* @__PURE__ */ jsx("span", { className: "badge__label", children })
|
|
31
|
+
] });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { Badge };
|
|
35
|
+
//# sourceMappingURL=chunk-2OWHZ4JT.js.map
|
|
36
|
+
//# sourceMappingURL=chunk-2OWHZ4JT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/badge/Badge.tsx"],"names":[],"mappings":";;;AAyBO,SAAS,KAAA,CAAM;AAAA,EACpB,IAAA,GAAO,SAAA;AAAA,EACP,OAAA,GAAU,OAAA;AAAA,EACV,IAAA,GAAO,IAAA;AAAA,EACP,GAAA,GAAM,KAAA;AAAA,EACN,IAAA,GAAO,KAAA;AAAA,EACP,IAAA,GAAO,KAAA;AAAA,EACP,IAAA,GAAO,IAAA;AAAA,EACP,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAe;AACb,EAAA,MAAM,UAAU,OAAA,KAAY,SAAA;AAC5B,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,UAAU,0BAAA,GAA6B,EAAA;AAAA,IACvC,OAAA;AAAA,IACA,UAAU,IAAI,CAAA,CAAA;AAAA,IACd,OAAA,KAAY,YAAY,gBAAA,GAAmB,EAAA;AAAA,IAC3C,IAAA,KAAS,IAAA,GAAO,CAAA,OAAA,EAAU,IAAI,CAAA,CAAA,GAAK,EAAA;AAAA,IACnC,OAAO,aAAA,GAAgB,EAAA;AAAA,IACvB;AAAA,GACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,MAAM,OAAA,GAAA,CAAW,GAAA,IAAO,IAAA,KAAS,CAAC,IAAA;AAElC,EAAA,uBACE,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,OAAA,EAAU,GAAG,IAAA,EAC3B,QAAA,EAAA;AAAA,IAAA,OAAA,mBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,CAAA,UAAA,EAAa,IAAA,GAAO,sBAAsB,EAAE,CAAA,CAAA,EAAI,aAAA,EAAY,MAAA,EAAO,CAAA,GAClF,IAAA;AAAA,IACH,IAAA,uBACE,MAAA,EAAA,EAAK,SAAA,EAAU,eAAc,aAAA,EAAY,MAAA,EACvC,gBACH,CAAA,GACE,IAAA;AAAA,oBACJ,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,cAAA,EAAgB,QAAA,EAAS;AAAA,GAAA,EAC3C,CAAA;AAEJ","file":"chunk-2OWHZ4JT.js","sourcesContent":["'use client';\n\n// Base badge chip - glass surface by default; the outline variant is flat (no glass classes).\n\nimport type { HTMLAttributes, ReactNode } from 'react';\n\nexport type BadgeTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Status hue. @default 'neutral' */\n tone?: BadgeTone;\n /** Surface. @default 'glass' */\n variant?: 'glass' | 'outline';\n /** @default 'md' */\n size?: 'sm' | 'md';\n /** Leading status dot. */\n dot?: boolean;\n /** Dot pulses (implies dot) - for in-progress status. */\n live?: boolean;\n /** Fully-rounded shape. */\n pill?: boolean;\n /** Optional leading <Icon> (overrides dot if both set). */\n icon?: ReactNode;\n}\n\nexport function Badge({\n tone = 'neutral',\n variant = 'glass',\n size = 'md',\n dot = false,\n live = false,\n pill = false,\n icon = null,\n className = '',\n children,\n ...rest\n}: BadgeProps) {\n const isGlass = variant !== 'outline';\n const classes = [\n isGlass ? 'glass glass--interactive' : '',\n 'badge',\n `badge--${tone}`,\n variant === 'outline' ? 'badge--outline' : '',\n size !== 'md' ? `badge--${size}` : '',\n pill ? 'badge--pill' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const showDot = (dot || live) && !icon;\n\n return (\n <span className={classes} {...rest}>\n {showDot ? (\n <span className={`badge__dot${live ? ' badge__dot--live' : ''}`} aria-hidden=\"true\" />\n ) : null}\n {icon ? (\n <span className=\"badge__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n ) : null}\n <span className=\"badge__label\">{children}</span>\n </span>\n );\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client';import { TimeSegments } from './chunk-5DDOOT33.js';
|
|
2
|
+
import { useControllable, FieldShell } from './chunk-QNC6O3PG.js';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function TimeField({
|
|
6
|
+
value,
|
|
7
|
+
// controlled: 'HH:mm' | null
|
|
8
|
+
defaultValue = null,
|
|
9
|
+
onChange,
|
|
10
|
+
label,
|
|
11
|
+
format = "24h",
|
|
12
|
+
minuteStep = 5,
|
|
13
|
+
min,
|
|
14
|
+
max,
|
|
15
|
+
required = false,
|
|
16
|
+
invalid = false,
|
|
17
|
+
message,
|
|
18
|
+
disabled = false,
|
|
19
|
+
className = ""
|
|
20
|
+
}) {
|
|
21
|
+
const [val, commit] = useControllable(value, defaultValue, onChange);
|
|
22
|
+
function onBoxPointerDown(e) {
|
|
23
|
+
if (disabled || e.target.closest(".tsg__seg")) return;
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
const seg = e.currentTarget.querySelector(".tsg__seg");
|
|
26
|
+
if (seg) seg.focus();
|
|
27
|
+
}
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
FieldShell,
|
|
30
|
+
{
|
|
31
|
+
variant: "tfd",
|
|
32
|
+
label,
|
|
33
|
+
required,
|
|
34
|
+
invalid,
|
|
35
|
+
message,
|
|
36
|
+
icon: "clock",
|
|
37
|
+
className,
|
|
38
|
+
children: /* @__PURE__ */ jsx(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
className: "fld__input tfd__box" + (disabled ? " is-disabled" : ""),
|
|
42
|
+
onPointerDown: onBoxPointerDown,
|
|
43
|
+
children: /* @__PURE__ */ jsx(
|
|
44
|
+
TimeSegments,
|
|
45
|
+
{
|
|
46
|
+
value: val,
|
|
47
|
+
onCommit: commit,
|
|
48
|
+
format,
|
|
49
|
+
minuteStep,
|
|
50
|
+
min,
|
|
51
|
+
max,
|
|
52
|
+
disabled,
|
|
53
|
+
ariaLabel: label || "Time"
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { TimeField };
|
|
63
|
+
//# sourceMappingURL=chunk-34SIXSYL.js.map
|
|
64
|
+
//# sourceMappingURL=chunk-34SIXSYL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/date-picker/TimeField.tsx"],"names":[],"mappings":";;;;AA+CO,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA;AAAA,EACA,YAAA,GAAe,IAAA;AAAA,EACf,QAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA,GAAS,KAAA;AAAA,EACT,UAAA,GAAa,CAAA;AAAA,EACb,GAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,OAAA,GAAU,KAAA;AAAA,EACV,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,SAAA,GAAY;AACd,CAAA,EAAmB;AACjB,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,IAAI,eAAA,CAAgB,KAAA,EAAO,cAAc,QAAQ,CAAA;AAGnE,EAAA,SAAS,iBAAiB,CAAA,EAAiC;AACzD,IAAA,IAAI,QAAA,IAAa,CAAA,CAAE,MAAA,CAAuB,OAAA,CAAQ,WAAW,CAAA,EAAG;AAChE,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAM,GAAA,GAAM,CAAA,CAAE,aAAA,CAAc,aAAA,CAAc,WAAW,CAAA;AACrD,IAAA,IAAI,GAAA,MAAS,KAAA,EAAM;AAAA,EACrB;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,KAAA;AAAA,MACR,KAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,IAAA,EAAK,OAAA;AAAA,MACL,SAAA;AAAA,MAEA,QAAA,kBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,qBAAA,IAAyB,QAAA,GAAW,cAAA,GAAiB,EAAA,CAAA;AAAA,UAChE,aAAA,EAAe,gBAAA;AAAA,UAEf,QAAA,kBAAA,GAAA;AAAA,YAAC,YAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO,GAAA;AAAA,cACP,QAAA,EAAU,MAAA;AAAA,cACV,MAAA;AAAA,cACA,UAAA;AAAA,cACA,GAAA;AAAA,cACA,GAAA;AAAA,cACA,QAAA;AAAA,cACA,WAAW,KAAA,IAAS;AAAA;AAAA;AACtB;AAAA;AACF;AAAA,GACF;AAEJ","file":"chunk-34SIXSYL.js","sourcesContent":["'use client';\n\n/* TimeField.tsx - standalone time field.\n -------------------------------------------------------------------------\n The segmented HH:MM machine (time-core.tsx) wearing the Input vocabulary -\n usable anywhere a bare time is needed, without the calendar.\n\n <TimeField\n label=\"Send at\"\n value=\"09:30\" // canonical 'HH:mm' (24h) | null\n onChange={(t) => ...} // live - the instant both segments exist\n format=\"12h\" // display only; storage stays 24h\n minuteStep={15} // ↑/↓ granularity (typing is exact)\n min=\"09:00\" max=\"17:30\" // saturation bounds - clamp, never error\n />\n\n Primitives consumed (A8): the .fld Input vocabulary (label/message/error\n chrome), TimeSegments (the machine), Icon. The box is a div wearing\n .fld__input - clicking its empty area seats focus in the hours segment.\n Buildless global was window.TimeField; a bundled app imports it. */\n\nimport type { PointerEvent } from 'react';\nimport { FieldShell, useControllable } from './field-shell';\nimport { TimeSegments } from './time-core';\n\nexport interface TimeFieldProps {\n /** Controlled value, canonical 'HH:mm' (24h). */\n value?: string | null;\n defaultValue?: string | null;\n /** Fires live - the instant both segments exist. */\n onChange?: (value: string) => void;\n label?: string;\n /** Display only; storage stays 24h. Default '24h'. */\n format?: '24h' | '12h';\n /** ↑/↓ step granularity in minutes (typing is exact). Default 5. */\n minuteStep?: number;\n /** Lower bound 'HH:mm' - saturates, never errors. */\n min?: string;\n /** Upper bound 'HH:mm' - saturates, never errors. */\n max?: string;\n required?: boolean;\n invalid?: boolean;\n message?: string;\n disabled?: boolean;\n className?: string;\n}\n\nexport function TimeField({\n value, // controlled: 'HH:mm' | null\n defaultValue = null,\n onChange,\n label,\n format = '24h',\n minuteStep = 5,\n min,\n max,\n required = false,\n invalid = false,\n message,\n disabled = false,\n className = '',\n}: TimeFieldProps) {\n const [val, commit] = useControllable(value, defaultValue, onChange);\n\n /* clicking the box (not a segment) seats focus where typing starts */\n function onBoxPointerDown(e: PointerEvent<HTMLDivElement>) {\n if (disabled || (e.target as HTMLElement).closest('.tsg__seg')) return;\n e.preventDefault();\n const seg = e.currentTarget.querySelector('.tsg__seg') as HTMLElement | null;\n if (seg) seg.focus();\n }\n\n return (\n <FieldShell\n variant=\"tfd\"\n label={label}\n required={required}\n invalid={invalid}\n message={message}\n icon=\"clock\"\n className={className}\n >\n <div\n className={'fld__input tfd__box' + (disabled ? ' is-disabled' : '')}\n onPointerDown={onBoxPointerDown}\n >\n <TimeSegments\n value={val}\n onCommit={commit}\n format={format}\n minuteStep={minuteStep}\n min={min}\n max={max}\n disabled={disabled}\n ariaLabel={label || 'Time'}\n />\n </div>\n </FieldShell>\n );\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/tokens/motion-tokens.ts
|
|
2
|
+
var DEFAULT_DUR = { fast: 0.12, base: 0.18, slow: 0.26 };
|
|
3
|
+
var DEFAULT_EASE = {
|
|
4
|
+
standard: [0.2, 0, 0, 1],
|
|
5
|
+
entrance: [0.16, 1, 0.3, 1],
|
|
6
|
+
exit: [0.4, 0, 1, 1],
|
|
7
|
+
spring: [0.34, 1.4, 0.5, 1],
|
|
8
|
+
glide: [0.55, 0, 0.15, 1]
|
|
9
|
+
};
|
|
10
|
+
function build(dur, ease) {
|
|
11
|
+
const reduced = dur.base <= 5e-3;
|
|
12
|
+
return {
|
|
13
|
+
dur,
|
|
14
|
+
ease,
|
|
15
|
+
reduced,
|
|
16
|
+
t: {
|
|
17
|
+
enter: { duration: dur.base, ease: ease.entrance },
|
|
18
|
+
exit: { duration: dur.fast, ease: ease.exit },
|
|
19
|
+
layout: { duration: dur.slow, ease: ease.entrance },
|
|
20
|
+
settle: reduced ? { duration: 0 } : { type: "spring", visualDuration: dur.base, bounce: 0.22 }
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function readFromDom() {
|
|
25
|
+
const cs = getComputedStyle(document.documentElement);
|
|
26
|
+
const seconds = (name, fallback) => {
|
|
27
|
+
const v = cs.getPropertyValue(name).trim();
|
|
28
|
+
const n = v.slice(-2) === "ms" ? parseFloat(v) / 1e3 : parseFloat(v);
|
|
29
|
+
return isNaN(n) ? fallback : n;
|
|
30
|
+
};
|
|
31
|
+
const bezier = (name, fallback) => {
|
|
32
|
+
const m = cs.getPropertyValue(name).match(/-?[\d.]+/g);
|
|
33
|
+
return m && m.length === 4 ? m.map(Number) : fallback;
|
|
34
|
+
};
|
|
35
|
+
return build(
|
|
36
|
+
{
|
|
37
|
+
fast: seconds("--duration-fast", DEFAULT_DUR.fast),
|
|
38
|
+
base: seconds("--duration-base", DEFAULT_DUR.base),
|
|
39
|
+
slow: seconds("--duration-slow", DEFAULT_DUR.slow)
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
standard: bezier("--ease-standard", DEFAULT_EASE.standard),
|
|
43
|
+
entrance: bezier("--ease-entrance", DEFAULT_EASE.entrance),
|
|
44
|
+
exit: bezier("--ease-exit", DEFAULT_EASE.exit),
|
|
45
|
+
spring: bezier("--ease-spring", DEFAULT_EASE.spring),
|
|
46
|
+
glide: bezier("--ease-glide", DEFAULT_EASE.glide)
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
var UIMotion = typeof document !== "undefined" ? readFromDom() : build(DEFAULT_DUR, DEFAULT_EASE);
|
|
51
|
+
var motion_tokens_default = UIMotion;
|
|
52
|
+
|
|
53
|
+
export { UIMotion, motion_tokens_default };
|
|
54
|
+
//# sourceMappingURL=chunk-37O2ZXD6.js.map
|
|
55
|
+
//# sourceMappingURL=chunk-37O2ZXD6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tokens/motion-tokens.ts"],"names":[],"mappings":"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","file":"chunk-37O2ZXD6.js","sourcesContent":["/* motion-tokens.ts - the JSandCSS motion bridge; Motion code reads these token values, never hardcodes them. */\n\nimport type { Transition } from 'motion/react';\n\nexport type Bezier = [number, number, number, number];\n\nexport interface MotionTokens {\n /** seconds - fast 0.12 - base 0.18 - slow 0.26 */\n dur: { fast: number; base: number; slow: number };\n ease: { standard: Bezier; entrance: Bezier; exit: Bezier; spring: Bezier; glide: Bezier };\n /** ready-made Motion transitions */\n t: { enter: Transition; exit: Transition; layout: Transition; settle: Transition };\n reduced: boolean;\n}\n\nconst DEFAULT_DUR: MotionTokens['dur'] = { fast: 0.12, base: 0.18, slow: 0.26 };\nconst DEFAULT_EASE: MotionTokens['ease'] = {\n standard: [0.2, 0, 0, 1],\n entrance: [0.16, 1, 0.3, 1],\n exit: [0.4, 0, 1, 1],\n spring: [0.34, 1.4, 0.5, 1],\n glide: [0.55, 0, 0.15, 1],\n};\n\nfunction build(dur: MotionTokens['dur'], ease: MotionTokens['ease']): MotionTokens {\n const reduced = dur.base <= 0.005; // reduced motion collapses durations to ~1ms\n return {\n dur,\n ease,\n reduced,\n t: {\n enter: { duration: dur.base, ease: ease.entrance },\n exit: { duration: dur.fast, ease: ease.exit },\n layout: { duration: dur.slow, ease: ease.entrance },\n settle: reduced\n ? { duration: 0 }\n : { type: 'spring', visualDuration: dur.base, bounce: 0.22 },\n },\n };\n}\n\nfunction readFromDom(): MotionTokens {\n const cs = getComputedStyle(document.documentElement);\n const seconds = (name: string, fallback: number): number => {\n const v = cs.getPropertyValue(name).trim();\n const n = v.slice(-2) === 'ms' ? parseFloat(v) / 1000 : parseFloat(v);\n return isNaN(n) ? fallback : n;\n };\n const bezier = (name: string, fallback: Bezier): Bezier => {\n const m = cs.getPropertyValue(name).match(/-?[\\d.]+/g);\n return m && m.length === 4 ? (m.map(Number) as Bezier) : fallback;\n };\n return build(\n {\n fast: seconds('--duration-fast', DEFAULT_DUR.fast),\n base: seconds('--duration-base', DEFAULT_DUR.base),\n slow: seconds('--duration-slow', DEFAULT_DUR.slow),\n },\n {\n standard: bezier('--ease-standard', DEFAULT_EASE.standard),\n entrance: bezier('--ease-entrance', DEFAULT_EASE.entrance),\n exit: bezier('--ease-exit', DEFAULT_EASE.exit),\n spring: bezier('--ease-spring', DEFAULT_EASE.spring),\n glide: bezier('--ease-glide', DEFAULT_EASE.glide),\n },\n );\n}\n\nexport const UIMotion: MotionTokens =\n typeof document !== 'undefined' ? readFromDom() : build(DEFAULT_DUR, DEFAULT_EASE);\n\nexport default UIMotion;\n"]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use client';import { IconSlot } from './chunk-VVPGEAC6.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var TOGGLE_TAG_OWN_PROPS = {
|
|
6
|
+
children: 1,
|
|
7
|
+
selected: 1,
|
|
8
|
+
defaultSelected: 1,
|
|
9
|
+
onChange: 1,
|
|
10
|
+
icon: 1,
|
|
11
|
+
count: 1,
|
|
12
|
+
size: 1,
|
|
13
|
+
disabled: 1,
|
|
14
|
+
className: 1
|
|
15
|
+
};
|
|
16
|
+
function toggleTagRestProps(props, own) {
|
|
17
|
+
const rest = {};
|
|
18
|
+
for (const k in props) {
|
|
19
|
+
if (!own[k]) rest[k] = props[k];
|
|
20
|
+
}
|
|
21
|
+
return rest;
|
|
22
|
+
}
|
|
23
|
+
function ToggleTagTick({ selected }) {
|
|
24
|
+
return /* @__PURE__ */ jsx(
|
|
25
|
+
"span",
|
|
26
|
+
{
|
|
27
|
+
className: "tag__check collapse",
|
|
28
|
+
"data-axis": "width",
|
|
29
|
+
"data-open": selected ? "true" : "false",
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
children: /* @__PURE__ */ jsx("span", { className: "collapse__inner", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
|
|
32
|
+
"path",
|
|
33
|
+
{
|
|
34
|
+
d: "M2.5 6.5 L5 9 L9.5 3.5",
|
|
35
|
+
pathLength: "1",
|
|
36
|
+
strokeWidth: "1.5",
|
|
37
|
+
strokeLinecap: "round",
|
|
38
|
+
strokeLinejoin: "round"
|
|
39
|
+
}
|
|
40
|
+
) }) })
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function ToggleTag(props) {
|
|
45
|
+
const {
|
|
46
|
+
children,
|
|
47
|
+
selected: controlledSelected,
|
|
48
|
+
defaultSelected = false,
|
|
49
|
+
onChange,
|
|
50
|
+
icon = null,
|
|
51
|
+
count = null,
|
|
52
|
+
size = "md",
|
|
53
|
+
disabled = false,
|
|
54
|
+
className = ""
|
|
55
|
+
} = props;
|
|
56
|
+
const rest = toggleTagRestProps(
|
|
57
|
+
props,
|
|
58
|
+
TOGGLE_TAG_OWN_PROPS
|
|
59
|
+
);
|
|
60
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultSelected);
|
|
61
|
+
const isControlled = controlledSelected !== void 0;
|
|
62
|
+
const selected = isControlled ? controlledSelected : uncontrolled;
|
|
63
|
+
function toggle() {
|
|
64
|
+
const next = !selected;
|
|
65
|
+
if (!isControlled) setUncontrolled(next);
|
|
66
|
+
if (onChange) onChange(next);
|
|
67
|
+
}
|
|
68
|
+
const classes = ["tag", "tag--toggle", size === "sm" ? "tag--sm" : "", className].filter(Boolean).join(" ");
|
|
69
|
+
return /* @__PURE__ */ jsxs(
|
|
70
|
+
"button",
|
|
71
|
+
{
|
|
72
|
+
type: "button",
|
|
73
|
+
className: classes,
|
|
74
|
+
"aria-pressed": selected,
|
|
75
|
+
disabled,
|
|
76
|
+
onClick: toggle,
|
|
77
|
+
...rest,
|
|
78
|
+
children: [
|
|
79
|
+
icon ? /* @__PURE__ */ jsx("span", { className: "tag__icon", children: /* @__PURE__ */ jsx(IconSlot, { size: "sm", children: icon }) }) : /* @__PURE__ */ jsx(ToggleTagTick, { selected }),
|
|
80
|
+
/* @__PURE__ */ jsx("span", { className: "tag__label", children }),
|
|
81
|
+
count != null && /* @__PURE__ */ jsx("span", { className: "tag__count", children: count })
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { ToggleTag };
|
|
88
|
+
//# sourceMappingURL=chunk-4AZL76UJ.js.map
|
|
89
|
+
//# sourceMappingURL=chunk-4AZL76UJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/tag/ToggleTag.tsx"],"names":[],"mappings":"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","file":"chunk-4AZL76UJ.js","sourcesContent":["'use client';\n\n/* ToggleTag - on/off filter chip (<button aria-pressed>); owns its selection state. */\n\nimport * as React from 'react';\nimport { IconSlot } from '../icon/IconSlot';\n\n/** ToggleTag - the on/off filter chip (<button aria-pressed>). */\nexport interface ToggleTagProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n 'onChange' | 'children'\n> {\n /** The label. */\n children: React.ReactNode;\n /** Controlled selected value. Omit for uncontrolled. */\n selected?: boolean;\n /** Uncontrolled initial value. */\n defaultSelected?: boolean;\n /** Fires with the next value on every toggle. */\n onChange?: (selected: boolean) => void;\n /** Your own icon node; replaces the tick. Selected state reads from the wash. */\n icon?: React.ReactNode | null;\n /** Optional result count - rendered mono/tabular. */\n count?: React.ReactNode;\n /** 'md' = 28px (default) - 'sm' = 24px for dense rows. */\n size?: 'md' | 'sm';\n disabled?: boolean;\n className?: string;\n}\n\n/* GOTCHA: split props manually instead of object-rest. */\nconst TOGGLE_TAG_OWN_PROPS: Record<string, number> = {\n children: 1,\n selected: 1,\n defaultSelected: 1,\n onChange: 1,\n icon: 1,\n count: 1,\n size: 1,\n disabled: 1,\n className: 1,\n};\nfunction toggleTagRestProps(props: Record<string, unknown>, own: Record<string, number>) {\n const rest: Record<string, unknown> = {};\n for (const k in props) {\n if (!own[k]) rest[k] = props[k];\n }\n return rest;\n}\n\nfunction ToggleTagTick({ selected }: { selected: boolean }) {\n /* collapse.css mechanism on spans - width 0fr and 1fr, content clipped */\n return (\n <span\n className=\"tag__check collapse\"\n data-axis=\"width\"\n data-open={selected ? 'true' : 'false'}\n aria-hidden=\"true\"\n >\n <span className=\"collapse__inner\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\">\n <path\n d=\"M2.5 6.5 L5 9 L9.5 3.5\"\n pathLength=\"1\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </span>\n );\n}\n\nexport function ToggleTag(props: ToggleTagProps) {\n const {\n children,\n selected: controlledSelected,\n defaultSelected = false,\n onChange,\n icon = null,\n count = null,\n size = 'md',\n disabled = false,\n className = '',\n } = props;\n const rest = toggleTagRestProps(\n props as unknown as Record<string, unknown>,\n TOGGLE_TAG_OWN_PROPS,\n );\n const [uncontrolled, setUncontrolled] = React.useState(defaultSelected);\n const isControlled = controlledSelected !== undefined;\n const selected = isControlled ? controlledSelected : uncontrolled;\n\n function toggle() {\n const next = !selected;\n if (!isControlled) setUncontrolled(next);\n if (onChange) onChange(next);\n }\n\n const classes = ['tag', 'tag--toggle', size === 'sm' ? 'tag--sm' : '', className]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button\n type=\"button\"\n className={classes}\n aria-pressed={selected}\n disabled={disabled}\n onClick={toggle}\n {...rest}\n >\n {icon ? (\n <span className=\"tag__icon\">\n <IconSlot size=\"sm\">{icon}</IconSlot>\n </span>\n ) : (\n <ToggleTagTick selected={selected} />\n )}\n <span className=\"tag__label\">{children}</span>\n {count != null && <span className=\"tag__count\">{count}</span>}\n </button>\n );\n}\n"]}
|