@zyncat/ui 0.8.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 +133 -0
- package/dist/alert.css +132 -0
- package/dist/alert.d.ts +46 -0
- package/dist/alert.js +80 -0
- package/dist/alert.js.map +1 -0
- package/dist/avatar-group.d.ts +24 -0
- package/dist/avatar-group.js +23 -0
- package/dist/avatar-group.js.map +1 -0
- package/dist/avatar.css +200 -0
- package/dist/avatar.d.ts +35 -0
- package/dist/avatar.js +67 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.css +182 -0
- package/dist/badge.d.ts +34 -0
- package/dist/badge.js +4 -0
- package/dist/badge.js.map +1 -0
- package/dist/button.css +269 -0
- package/dist/button.d.ts +44 -0
- package/dist/button.js +4 -0
- package/dist/button.js.map +1 -0
- package/dist/checkbox.css +177 -0
- package/dist/checkbox.d.ts +35 -0
- package/dist/checkbox.js +5 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-2ERBBFZS.js +12 -0
- package/dist/chunk-2ERBBFZS.js.map +1 -0
- package/dist/chunk-2HORSLXJ.js +191 -0
- package/dist/chunk-2HORSLXJ.js.map +1 -0
- package/dist/chunk-36WVAQKL.js +40 -0
- package/dist/chunk-36WVAQKL.js.map +1 -0
- package/dist/chunk-3SBCBYB7.js +575 -0
- package/dist/chunk-3SBCBYB7.js.map +1 -0
- package/dist/chunk-4R2GQO43.js +125 -0
- package/dist/chunk-4R2GQO43.js.map +1 -0
- package/dist/chunk-64UU4LGU.js +258 -0
- package/dist/chunk-64UU4LGU.js.map +1 -0
- package/dist/chunk-7SZCJ7WI.js +35 -0
- package/dist/chunk-7SZCJ7WI.js.map +1 -0
- package/dist/chunk-BIDVNLJO.js +38 -0
- package/dist/chunk-BIDVNLJO.js.map +1 -0
- package/dist/chunk-CONSWNIV.js +17 -0
- package/dist/chunk-CONSWNIV.js.map +1 -0
- package/dist/chunk-EQ32F2QJ.js +75 -0
- package/dist/chunk-EQ32F2QJ.js.map +1 -0
- package/dist/chunk-GY7JOPUQ.js +111 -0
- package/dist/chunk-GY7JOPUQ.js.map +1 -0
- package/dist/chunk-I4XQ4PV2.js +30 -0
- package/dist/chunk-I4XQ4PV2.js.map +1 -0
- package/dist/chunk-JSKXZMLH.js +67 -0
- package/dist/chunk-JSKXZMLH.js.map +1 -0
- package/dist/chunk-L3Q3VDIW.js +295 -0
- package/dist/chunk-L3Q3VDIW.js.map +1 -0
- package/dist/chunk-LDC3RIYA.js +62 -0
- package/dist/chunk-LDC3RIYA.js.map +1 -0
- package/dist/chunk-MKIQFK7S.js +43 -0
- package/dist/chunk-MKIQFK7S.js.map +1 -0
- package/dist/chunk-MMRIQNEN.js +20 -0
- package/dist/chunk-MMRIQNEN.js.map +1 -0
- package/dist/chunk-MXOPCFWR.js +59 -0
- package/dist/chunk-MXOPCFWR.js.map +1 -0
- package/dist/chunk-NEF5XAHG.js +17 -0
- package/dist/chunk-NEF5XAHG.js.map +1 -0
- package/dist/chunk-NNXJCLTV.js +22 -0
- package/dist/chunk-NNXJCLTV.js.map +1 -0
- package/dist/chunk-O4N2OBTR.js +94 -0
- package/dist/chunk-O4N2OBTR.js.map +1 -0
- package/dist/chunk-PMECHR3A.js +38 -0
- package/dist/chunk-PMECHR3A.js.map +1 -0
- package/dist/chunk-QDK66S4G.js +44 -0
- package/dist/chunk-QDK66S4G.js.map +1 -0
- package/dist/chunk-QGNC7LH5.js +8 -0
- package/dist/chunk-QGNC7LH5.js.map +1 -0
- package/dist/chunk-QMSJZCK3.js +398 -0
- package/dist/chunk-QMSJZCK3.js.map +1 -0
- package/dist/chunk-S5ZTZANS.js +57 -0
- package/dist/chunk-S5ZTZANS.js.map +1 -0
- package/dist/chunk-S7B34VGN.js +14 -0
- package/dist/chunk-S7B34VGN.js.map +1 -0
- package/dist/chunk-TCUCYFT7.js +25 -0
- package/dist/chunk-TCUCYFT7.js.map +1 -0
- package/dist/chunk-TYHR4VNM.js +193 -0
- package/dist/chunk-TYHR4VNM.js.map +1 -0
- package/dist/chunk-U5QQZC3U.js +56 -0
- package/dist/chunk-U5QQZC3U.js.map +1 -0
- package/dist/chunk-UE63OOVG.js +13 -0
- package/dist/chunk-UE63OOVG.js.map +1 -0
- package/dist/chunk-VTJTGVZZ.js +22 -0
- package/dist/chunk-VTJTGVZZ.js.map +1 -0
- package/dist/chunk-W3SHPKSB.js +49 -0
- package/dist/chunk-W3SHPKSB.js.map +1 -0
- package/dist/chunk-XZAEIQDR.js +188 -0
- package/dist/chunk-XZAEIQDR.js.map +1 -0
- package/dist/chunk-YGGCQNNU.js +92 -0
- package/dist/chunk-YGGCQNNU.js.map +1 -0
- package/dist/collapse.css +88 -0
- package/dist/collapse.d.ts +46 -0
- package/dist/collapse.js +5 -0
- package/dist/collapse.js.map +1 -0
- package/dist/count-badge.d.ts +13 -0
- package/dist/count-badge.js +13 -0
- package/dist/count-badge.js.map +1 -0
- package/dist/date-field.d.ts +25 -0
- package/dist/date-field.js +87 -0
- package/dist/date-field.js.map +1 -0
- package/dist/date-picker.css +595 -0
- package/dist/date-range-field.d.ts +33 -0
- package/dist/date-range-field.js +404 -0
- package/dist/date-range-field.js.map +1 -0
- package/dist/datetime-field.d.ts +29 -0
- package/dist/datetime-field.js +155 -0
- package/dist/datetime-field.js.map +1 -0
- package/dist/dialog.css +180 -0
- package/dist/dialog.d.ts +42 -0
- package/dist/dialog.js +128 -0
- package/dist/dialog.js.map +1 -0
- package/dist/dom-props-C0jrllBw.d.ts +5 -0
- package/dist/field-chrome-CMPOQSLs.d.ts +28 -0
- package/dist/field-shell-Cuda-feL.d.ts +24 -0
- package/dist/glide.d.ts +15 -0
- package/dist/glide.js +5 -0
- package/dist/glide.js.map +1 -0
- package/dist/icon.css +33 -0
- package/dist/input.css +333 -0
- package/dist/mcp.js +359 -0
- package/dist/motion-devtools.css +265 -0
- package/dist/motion-devtools.d.ts +51 -0
- package/dist/motion-devtools.js +354 -0
- package/dist/motion-devtools.js.map +1 -0
- package/dist/motion-scale-Canq4stZ.d.ts +18 -0
- package/dist/motion-tokens.d.ts +28 -0
- package/dist/motion-tokens.js +3 -0
- package/dist/motion-tokens.js.map +1 -0
- package/dist/multi-select.d.ts +44 -0
- package/dist/multi-select.js +109 -0
- package/dist/multi-select.js.map +1 -0
- package/dist/number-field.d.ts +36 -0
- package/dist/number-field.js +112 -0
- package/dist/number-field.js.map +1 -0
- package/dist/odometer.css +62 -0
- package/dist/otp-field.d.ts +31 -0
- package/dist/otp-field.js +98 -0
- package/dist/otp-field.js.map +1 -0
- package/dist/overlay.css +23 -0
- package/dist/pagination.css +43 -0
- package/dist/pagination.d.ts +29 -0
- package/dist/pagination.js +107 -0
- package/dist/pagination.js.map +1 -0
- package/dist/popover.css +69 -0
- package/dist/popover.d.ts +35 -0
- package/dist/popover.js +15 -0
- package/dist/popover.js.map +1 -0
- package/dist/radio-group.css +300 -0
- package/dist/radio-group.d.ts +52 -0
- package/dist/radio-group.js +115 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/select.css +416 -0
- package/dist/select.d.ts +49 -0
- package/dist/select.js +99 -0
- package/dist/select.js.map +1 -0
- package/dist/sheet.css +26 -0
- package/dist/sheet.d.ts +31 -0
- package/dist/sheet.js +14 -0
- package/dist/sheet.js.map +1 -0
- package/dist/status-badge.d.ts +19 -0
- package/dist/status-badge.js +72 -0
- package/dist/status-badge.js.map +1 -0
- package/dist/table.css +348 -0
- package/dist/table.d.ts +75 -0
- package/dist/table.js +262 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.css +208 -0
- package/dist/tabs.d.ts +71 -0
- package/dist/tabs.js +181 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tag.css +248 -0
- package/dist/tag.d.ts +52 -0
- package/dist/tag.js +72 -0
- package/dist/tag.js.map +1 -0
- package/dist/text-field.d.ts +28 -0
- package/dist/text-field.js +69 -0
- package/dist/text-field.js.map +1 -0
- package/dist/textarea.css +219 -0
- package/dist/textarea.d.ts +38 -0
- package/dist/textarea.js +144 -0
- package/dist/textarea.js.map +1 -0
- package/dist/time-field.d.ts +28 -0
- package/dist/time-field.js +66 -0
- package/dist/time-field.js.map +1 -0
- package/dist/timing-7JA_zQHP.d.ts +27 -0
- package/dist/toast-store.d.ts +86 -0
- package/dist/toast-store.js +3 -0
- package/dist/toast-store.js.map +1 -0
- package/dist/toast.css +257 -0
- package/dist/toast.d.ts +12 -0
- package/dist/toast.js +310 -0
- package/dist/toast.js.map +1 -0
- package/dist/toggle-tag.d.ts +34 -0
- package/dist/toggle-tag.js +57 -0
- package/dist/toggle-tag.js.map +1 -0
- package/dist/toggle.css +152 -0
- package/dist/toggle.d.ts +31 -0
- package/dist/toggle.js +75 -0
- package/dist/toggle.js.map +1 -0
- package/dist/tooltip.css +86 -0
- package/dist/tooltip.d.ts +30 -0
- package/dist/tooltip.js +268 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/types-SGMShK7R.d.ts +22 -0
- package/llms.txt +196 -0
- package/next.d.mts +7 -0
- package/next.mjs +59 -0
- package/package.json +257 -0
- package/src/components/composites/alert/Alert.tsx +141 -0
- package/src/components/composites/alert/alert.css +132 -0
- package/src/components/composites/date-picker/DateField.tsx +80 -0
- package/src/components/composites/date-picker/DateRangeField.tsx +110 -0
- package/src/components/composites/date-picker/DateTimeField.tsx +162 -0
- package/src/components/composites/date-picker/TimeField.tsx +78 -0
- package/src/components/composites/date-picker/calendar-panel.tsx +216 -0
- package/src/components/composites/date-picker/date-picker.css +595 -0
- package/src/components/composites/date-picker/date-utils.ts +56 -0
- package/src/components/composites/date-picker/field-shell.tsx +85 -0
- package/src/components/composites/date-picker/range-panel.tsx +363 -0
- package/src/components/composites/date-picker/time-core.tsx +290 -0
- package/src/components/composites/date-picker/use-day-focus.ts +35 -0
- package/src/components/composites/dialog/Dialog.tsx +198 -0
- package/src/components/composites/dialog/dialog.css +180 -0
- package/src/components/composites/pagination/Pagination.tsx +131 -0
- package/src/components/composites/pagination/pagination.css +43 -0
- package/src/components/composites/popover/Popover.tsx +141 -0
- package/src/components/composites/popover/popover.css +69 -0
- package/src/components/composites/select/MultiSelect.tsx +133 -0
- package/src/components/composites/select/Select.tsx +122 -0
- package/src/components/composites/select/core/index.ts +4 -0
- package/src/components/composites/select/core/menu.tsx +100 -0
- package/src/components/composites/select/core/panel.tsx +154 -0
- package/src/components/composites/select/core/trigger.tsx +74 -0
- package/src/components/composites/select/core/types.ts +39 -0
- package/src/components/composites/select/core/use-listbox.ts +182 -0
- package/src/components/composites/select/select.css +416 -0
- package/src/components/composites/sheet/Sheet.tsx +135 -0
- package/src/components/composites/sheet/sheet.css +26 -0
- package/src/components/composites/sheet/use-sheet-drag.ts +126 -0
- package/src/components/composites/table/Table.tsx +377 -0
- package/src/components/composites/table/table.css +348 -0
- package/src/components/composites/tabs/Tabs.tsx +278 -0
- package/src/components/composites/tabs/tabs.css +208 -0
- package/src/components/composites/toast/Toast.tsx +380 -0
- package/src/components/composites/toast/toast-store.ts +295 -0
- package/src/components/composites/toast/toast.css +257 -0
- package/src/components/composites/tooltip/Tooltip.tsx +110 -0
- package/src/components/composites/tooltip/tooltip-host.tsx +184 -0
- package/src/components/composites/tooltip/tooltip-store.ts +81 -0
- package/src/components/composites/tooltip/tooltip.css +86 -0
- package/src/components/dev/MotionDevtools.tsx +200 -0
- package/src/components/dev/motion-devtools.css +265 -0
- package/src/components/dev/slowmo-engine.ts +230 -0
- package/src/components/internal/glass/glass.css +100 -0
- package/src/components/internal/glass/glint.ts +9 -0
- package/src/components/internal/hooks/use-controllable.ts +21 -0
- package/src/components/internal/hooks/use-scroll-edges.ts +46 -0
- package/src/components/internal/icon/Icon.tsx +66 -0
- package/src/components/internal/icon/IconSlot.tsx +10 -0
- package/src/components/internal/icon/icon.css +33 -0
- package/src/components/internal/overlay/focus.ts +68 -0
- package/src/components/internal/overlay/layer.tsx +149 -0
- package/src/components/internal/overlay/modal.tsx +141 -0
- package/src/components/internal/overlay/overlay.css +23 -0
- package/src/components/internal/overlay/position.ts +103 -0
- package/src/components/internal/utils/cx.ts +3 -0
- package/src/components/internal/utils/token-px.ts +8 -0
- package/src/components/primitives/avatar/Avatar.tsx +120 -0
- package/src/components/primitives/avatar/AvatarGroup.tsx +56 -0
- package/src/components/primitives/avatar/avatar.css +200 -0
- package/src/components/primitives/badge/Badge.tsx +75 -0
- package/src/components/primitives/badge/CountBadge.tsx +20 -0
- package/src/components/primitives/badge/StatusBadge.tsx +111 -0
- package/src/components/primitives/badge/badge.css +182 -0
- package/src/components/primitives/badge/odometer.css +62 -0
- package/src/components/primitives/badge/odometer.tsx +36 -0
- package/src/components/primitives/button/Button.tsx +102 -0
- package/src/components/primitives/button/button.css +269 -0
- package/src/components/primitives/checkbox/Checkbox.tsx +76 -0
- package/src/components/primitives/checkbox/check-glyph.tsx +28 -0
- package/src/components/primitives/checkbox/checkbox.css +177 -0
- package/src/components/primitives/collapse/Collapse.tsx +86 -0
- package/src/components/primitives/collapse/collapse.css +88 -0
- package/src/components/primitives/collapse/collapse.typecheck.tsx +29 -0
- package/src/components/primitives/input/NumberField.tsx +139 -0
- package/src/components/primitives/input/OtpField.tsx +134 -0
- package/src/components/primitives/input/TextField.tsx +110 -0
- package/src/components/primitives/input/field-chrome.tsx +83 -0
- package/src/components/primitives/input/input.css +333 -0
- package/src/components/primitives/radio-group/RadioGroup.tsx +183 -0
- package/src/components/primitives/radio-group/radio-group.css +300 -0
- package/src/components/primitives/tag/Tag.tsx +143 -0
- package/src/components/primitives/tag/ToggleTag.tsx +97 -0
- package/src/components/primitives/tag/tag.css +248 -0
- package/src/components/primitives/textarea/Textarea.tsx +190 -0
- package/src/components/primitives/textarea/textarea.css +219 -0
- package/src/components/primitives/toggle/Toggle.tsx +105 -0
- package/src/components/primitives/toggle/toggle.css +152 -0
- package/src/css.d.ts +1 -0
- package/src/dom-props.ts +1 -0
- package/src/engine/animate.ts +141 -0
- package/src/engine/drag.ts +53 -0
- package/src/engine/ease.ts +155 -0
- package/src/engine/flip.ts +59 -0
- package/src/engine/index.ts +13 -0
- package/src/mcp/server.ts +420 -0
- package/src/motion/element.tsx +53 -0
- package/src/motion/flip.tsx +87 -0
- package/src/motion/glide.tsx +47 -0
- package/src/motion/motion-timing.ts +33 -0
- package/src/motion/presence-context.ts +18 -0
- package/src/motion/presence.tsx +91 -0
- package/src/motion/timing.ts +49 -0
- package/src/motion/use-motion.ts +64 -0
- package/src/styles.css +26 -0
- package/src/tokens/avatar.css +20 -0
- package/src/tokens/color.css +58 -0
- package/src/tokens/elevation.css +22 -0
- package/src/tokens/fonts.css +3 -0
- package/src/tokens/glass.css +20 -0
- package/src/tokens/icons.css +7 -0
- package/src/tokens/layers.css +6 -0
- package/src/tokens/motion-scale.ts +17 -0
- package/src/tokens/motion-tokens.ts +92 -0
- package/src/tokens/motion.css +49 -0
- package/src/tokens/radius.css +11 -0
- package/src/tokens/semantic.css +65 -0
- package/src/tokens/spacing.css +26 -0
- package/src/tokens/typography.css +52 -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,133 @@
|
|
|
1
|
+
# Zyncat UI
|
|
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 base stylesheet - each component loads its own CSS automatically.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @zyncat/ui
|
|
13
|
+
# peers (you likely already have them):
|
|
14
|
+
pnpm add react react-dom
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
| Peer | Range | Used for |
|
|
18
|
+
| --------------------- | ----- | -------------------------------------------------------------------- |
|
|
19
|
+
| `react` / `react-dom` | `^19` | components; `createRoot`/`createPortal` for imperative toast/tooltip |
|
|
20
|
+
|
|
21
|
+
Enter/exit, layout and gesture animation are built in (a small WAAPI engine) - no animation library to install.
|
|
22
|
+
|
|
23
|
+
Icons are **bundled** (a small curated Phosphor set) - there is no icon peer to install.
|
|
24
|
+
|
|
25
|
+
## Use it
|
|
26
|
+
|
|
27
|
+
No bundler config and no `transpilePackages` - the package ships built ESM with the `'use client'`
|
|
28
|
+
directives intact, so Next.js App Router boundaries just work.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { Button, toast } from '@zyncat/ui';
|
|
32
|
+
import '@zyncat/ui/styles.css'; // base layer - link once, at the app root
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`styles.css` is the **base layer only** - fonts, design tokens (the `:root` custom
|
|
36
|
+
properties) and the shared `glass` utility. Link it exactly once at the app root.
|
|
37
|
+
|
|
38
|
+
You never import per-component CSS: every component imports its own stylesheet, so your
|
|
39
|
+
bundler code-splits and lazy-loads it with the component. Import `@zyncat/ui/dialog` and
|
|
40
|
+
only `dialog.css` ships (plus the `overlay`/`icon` styles it reuses, deduped) - not the
|
|
41
|
+
other 30 components' CSS.
|
|
42
|
+
|
|
43
|
+
### Import a single component
|
|
44
|
+
|
|
45
|
+
Every component is also a subpath export, so you can pull just one:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { Button } from '@zyncat/ui/button';
|
|
49
|
+
import { DateField } from '@zyncat/ui/date-field';
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The barrel is side-effect-free and tree-shakes, so `import { Button } from '@zyncat/ui'` is
|
|
53
|
+
equally lean in a bundler - subpaths help in non-bundled or explicit setups. CSS follows the
|
|
54
|
+
same module graph: components you don't use drop their stylesheets too.
|
|
55
|
+
|
|
56
|
+
## Components
|
|
57
|
+
|
|
58
|
+
| Group | Components |
|
|
59
|
+
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
60
|
+
| Primitives | Button, Collapse, Badge, StatusBadge, CountBadge |
|
|
61
|
+
| Forms | TextField, NumberField, OtpField, Textarea, Checkbox, Toggle, RadioGroup, Select, MultiSelect |
|
|
62
|
+
| Data | Avatar, AvatarGroup, Tag, ToggleTag, Table, Pagination |
|
|
63
|
+
| Date, time & tabs | DateField, DateTimeField, DateRangeField, TimeField, Tabs |
|
|
64
|
+
| Overlays & feedback | Alert, Toast, Tooltip, Dialog, Popover, Sheet |
|
|
65
|
+
|
|
66
|
+
Each is a named export from the barrel and a subpath (`@zyncat/ui/<kebab-name>`). Props are
|
|
67
|
+
documented inline in the types; see [`llms.txt`](./llms.txt) for per-component examples.
|
|
68
|
+
|
|
69
|
+
## For AI coding agents
|
|
70
|
+
|
|
71
|
+
**MCP server (preferred).** The package bundles a zero-dependency MCP server (stdio) so agents
|
|
72
|
+
query the API surface instead of grepping `node_modules`: `list_components` (index + conventions),
|
|
73
|
+
`get_component` (usage docs + complete prop types, shared type chunks inlined), `search_api`
|
|
74
|
+
(which component owns a prop/type/token), `get_tokens` (the token vocabulary with real values).
|
|
75
|
+
Register it in the consuming project - for Claude Code, `.mcp.json` at the project root:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{ "mcpServers": { "zyncat-ui": { "command": "node", "args": ["./node_modules/@zyncat/ui/dist/mcp.js"] } } }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Any MCP client works (also exposed as the `zyncat-ui-mcp` bin). The server reads the installed
|
|
82
|
+
package's `llms.txt`, `dist/*.d.ts` and `src/tokens/*.css` at call time, so answers always match
|
|
83
|
+
the installed version.
|
|
84
|
+
|
|
85
|
+
Without MCP, the same contract is readable directly:
|
|
86
|
+
|
|
87
|
+
- **`node_modules/@zyncat/ui/dist/*.d.ts`** - every component's props carry inline TSDoc. This is
|
|
88
|
+
the machine-readable source of truth (e.g. `dist/button.d.ts` fully describes `ButtonProps`).
|
|
89
|
+
- **`llms.txt`** (package root) - a compact, per-component index: purpose - import - a minimal
|
|
90
|
+
example. Cheaper to scan than every `.d.ts`.
|
|
91
|
+
- This README.
|
|
92
|
+
|
|
93
|
+
## Copy-paste instead
|
|
94
|
+
|
|
95
|
+
The tarball also ships `src/`, so you can lift a component straight from
|
|
96
|
+
`node_modules/@zyncat/ui/src/components/<name>/` into your project. Components aren't fully
|
|
97
|
+
self-contained - they share `src/tokens/`, the `motion-tokens` bridge, the internal `icon/`, and a
|
|
98
|
+
few `*-core` helpers - so copy those alongside. (A shadcn-style registry/CLI could automate this
|
|
99
|
+
later.)
|
|
100
|
+
|
|
101
|
+
## Icons
|
|
102
|
+
|
|
103
|
+
Components render their own glyphs from a small curated Phosphor set, **bundled in** - no icon peer
|
|
104
|
+
to install. Zyncat UI does **not** export an `Icon` component, so where a prop takes an icon
|
|
105
|
+
(`iconLeft`, `leadingIcon`, a `Tag`'s `icon`, ...) pass your own node - any `ReactNode` (e.g. an
|
|
106
|
+
`@phosphor-icons/react` element, if you choose to use it).
|
|
107
|
+
|
|
108
|
+
## What's inside
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
src/ source (also shipped, for copy-paste)
|
|
112
|
+
-- index.ts public barrel
|
|
113
|
+
-- styles.css base layer: fonts + tokens + glass (link once)
|
|
114
|
+
-- tokens/ CSS custom properties + motion-tokens.ts (JS and CSS motion bridge)
|
|
115
|
+
-- components/ <domain>/Name.tsx + name.css (each Tsx imports its own CSS -> lazy-loaded)
|
|
116
|
+
dist/ compiled ESM + .d.ts - what you import
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Notes
|
|
120
|
+
|
|
121
|
+
- **Fonts.** `src/tokens/fonts.css` pulls Geist + Geist Mono from Google Fonts via a remote
|
|
122
|
+
`@import`. Self-host the families to drop the render-blocking network hop.
|
|
123
|
+
- **Styling is token-driven.** Re-skin by overriding the CSS custom properties in your own
|
|
124
|
+
stylesheet loaded after `@zyncat/ui/styles.css` - never fork the source.
|
|
125
|
+
|
|
126
|
+
## Develop
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm install
|
|
130
|
+
pnpm build # tsup - dist/ (ESM + .d.ts)
|
|
131
|
+
pnpm typecheck # tsc --noEmit
|
|
132
|
+
pnpm format # prettier --write
|
|
133
|
+
```
|
package/dist/alert.css
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* alert.css - the persistent in-flow status message: a lit tinted pane per tone. */
|
|
2
|
+
|
|
3
|
+
.alert-shell {
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.alert {
|
|
8
|
+
/* tone hooks - repointed by [data-tone] below; info is the default */
|
|
9
|
+
--alert-hue: var(--info);
|
|
10
|
+
--alert-fg: var(--info-text);
|
|
11
|
+
--alert-bg: var(--info-subtle);
|
|
12
|
+
--alert-wash: var(--accent-wash); /* info's wash = accent (teal) */
|
|
13
|
+
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: var(--space-3);
|
|
18
|
+
padding: var(--space-3) var(--space-4);
|
|
19
|
+
/* the lit pane: top-light gradient over the tint + 1px inner highlight (Button's lighting model) */
|
|
20
|
+
background: linear-gradient(180deg, color-mix(in oklab, var(--bg-surface) 45%, var(--alert-bg)), var(--alert-bg));
|
|
21
|
+
border: var(--border-hairline) solid color-mix(in oklab, var(--alert-hue) 30%, transparent);
|
|
22
|
+
border-radius: var(--radius-lg);
|
|
23
|
+
box-shadow: inset 0 1px 0 0 rgb(255 255 255 / 0.55);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.alert[data-tone='success'] {
|
|
27
|
+
--alert-hue: var(--success);
|
|
28
|
+
--alert-fg: var(--success-text);
|
|
29
|
+
--alert-bg: var(--success-subtle);
|
|
30
|
+
--alert-wash: var(--success-wash);
|
|
31
|
+
}
|
|
32
|
+
.alert[data-tone='warning'] {
|
|
33
|
+
--alert-hue: var(--warning);
|
|
34
|
+
--alert-fg: var(--warning-text);
|
|
35
|
+
--alert-bg: var(--warning-subtle);
|
|
36
|
+
--alert-wash: var(--warning-wash);
|
|
37
|
+
}
|
|
38
|
+
.alert[data-tone='danger'] {
|
|
39
|
+
--alert-hue: var(--danger);
|
|
40
|
+
--alert-fg: var(--danger-text);
|
|
41
|
+
--alert-bg: var(--danger-subtle);
|
|
42
|
+
--alert-wash: var(--danger-wash);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* with a description: glyph rides the title line, controls stay centered */
|
|
46
|
+
.alert:has(.alert__desc) {
|
|
47
|
+
align-items: flex-start;
|
|
48
|
+
}
|
|
49
|
+
.alert:has(.alert__desc) .alert__action,
|
|
50
|
+
.alert:has(.alert__desc) .alert__close {
|
|
51
|
+
align-self: center;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.alert--banner {
|
|
55
|
+
border-radius: 0;
|
|
56
|
+
border-block-start: 0;
|
|
57
|
+
border-inline: 0;
|
|
58
|
+
padding-inline: var(--space-6);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Glyph - one --leading-body tall so it centers on the title line. */
|
|
62
|
+
.alert__icon {
|
|
63
|
+
flex: none;
|
|
64
|
+
display: grid;
|
|
65
|
+
place-items: center;
|
|
66
|
+
height: var(--leading-body);
|
|
67
|
+
color: var(--alert-hue);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.alert__body {
|
|
71
|
+
flex: 1 1 auto;
|
|
72
|
+
min-width: 0;
|
|
73
|
+
}
|
|
74
|
+
.alert__title {
|
|
75
|
+
margin: 0;
|
|
76
|
+
font: var(--type-label);
|
|
77
|
+
color: var(--alert-fg);
|
|
78
|
+
text-wrap: pretty;
|
|
79
|
+
}
|
|
80
|
+
.alert__desc {
|
|
81
|
+
margin: var(--space-1) 0 0;
|
|
82
|
+
font: var(--type-caption);
|
|
83
|
+
color: color-mix(in oklab, var(--alert-fg) 56%, var(--text-body));
|
|
84
|
+
text-wrap: pretty;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Action - the system .btn .btn--sm re-skinned to the pane's tone (alert-local chrome, not a global Button variant). */
|
|
88
|
+
.alert__action {
|
|
89
|
+
flex: none;
|
|
90
|
+
color: var(--alert-fg);
|
|
91
|
+
background: transparent;
|
|
92
|
+
}
|
|
93
|
+
.alert__action:hover:not(:disabled) {
|
|
94
|
+
color: var(--alert-fg);
|
|
95
|
+
background: var(--alert-wash);
|
|
96
|
+
}
|
|
97
|
+
.alert__action:active:not(:disabled) {
|
|
98
|
+
background: color-mix(in oklab, var(--alert-hue) 16%, transparent);
|
|
99
|
+
transform: translateY(var(--space-px));
|
|
100
|
+
}
|
|
101
|
+
.alert[data-tone='danger'] .alert__action {
|
|
102
|
+
--btn-ring: var(--ring-danger);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Dismiss - always visible (alerts persist; no hover-reveal like toast). */
|
|
106
|
+
.alert__close {
|
|
107
|
+
flex: none;
|
|
108
|
+
appearance: none;
|
|
109
|
+
display: grid;
|
|
110
|
+
place-items: center;
|
|
111
|
+
width: var(--space-6);
|
|
112
|
+
height: var(--space-6);
|
|
113
|
+
margin: 0;
|
|
114
|
+
padding: 0;
|
|
115
|
+
border: none;
|
|
116
|
+
border-radius: var(--radius-sm);
|
|
117
|
+
background: transparent;
|
|
118
|
+
color: color-mix(in oklab, var(--alert-fg) 64%, transparent);
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
transition: var(--transition-control);
|
|
121
|
+
}
|
|
122
|
+
.alert__close:hover {
|
|
123
|
+
background: color-mix(in oklab, var(--alert-fg) 9%, transparent);
|
|
124
|
+
color: var(--alert-fg);
|
|
125
|
+
}
|
|
126
|
+
.alert__close:active {
|
|
127
|
+
background: color-mix(in oklab, var(--alert-fg) 14%, transparent);
|
|
128
|
+
}
|
|
129
|
+
.alert__close:focus-visible {
|
|
130
|
+
outline: none;
|
|
131
|
+
box-shadow: var(--focus-ring);
|
|
132
|
+
}
|
package/dist/alert.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, CSSProperties, HTMLAttributes } from 'react';
|
|
3
|
+
import { D as DisableableAnimation } from './timing-7JA_zQHP.js';
|
|
4
|
+
import { D as DataAttributes } from './dom-props-C0jrllBw.js';
|
|
5
|
+
import './motion-scale-Canq4stZ.js';
|
|
6
|
+
|
|
7
|
+
type AlertTone = 'info' | 'success' | 'warning' | 'danger';
|
|
8
|
+
interface AlertAction {
|
|
9
|
+
/** Sentence-case label, e.g. "Update billing". */
|
|
10
|
+
label: string;
|
|
11
|
+
onClick?: () => void;
|
|
12
|
+
}
|
|
13
|
+
interface AlertOwnProps {
|
|
14
|
+
/** Status of the message; info/success are polite, warning/danger assertive. Default 'info'. */
|
|
15
|
+
tone?: AlertTone;
|
|
16
|
+
/** The message - sentence case, ideally one line. */
|
|
17
|
+
title: ReactNode;
|
|
18
|
+
/** Optional description; stays neutral - tone marks the message, not the prose. */
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
/** One action max, rendered as the system secondary small button. */
|
|
21
|
+
action?: AlertAction;
|
|
22
|
+
/** Renders the always-visible close button. Uncontrolled unless `open` is given. */
|
|
23
|
+
dismissible?: boolean;
|
|
24
|
+
/** Fires on dismiss. With `open` set, the parent owns hiding the alert. */
|
|
25
|
+
onDismiss?: () => void;
|
|
26
|
+
/** Controlled visibility; omit for uncontrolled. Exit eases shut (height collapse). */
|
|
27
|
+
open?: boolean;
|
|
28
|
+
/** App-level strip: square corners, hairline below only. Paint modifier. */
|
|
29
|
+
banner?: boolean;
|
|
30
|
+
/** Override the tone glyph; pass null to render no glyph. */
|
|
31
|
+
icon?: ReactNode | null;
|
|
32
|
+
/** Extra class(es) merged onto the alert. */
|
|
33
|
+
className?: string;
|
|
34
|
+
/** Inline styles merged onto the alert. */
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
/** Enter/exit timing - motion tokens only, or `null` to disable (the height collapse snaps).
|
|
37
|
+
* @default height 'slow'/'entrance'; opacity in 'base'/'entrance', out 'fast'/'exit' */
|
|
38
|
+
animation?: DisableableAnimation;
|
|
39
|
+
}
|
|
40
|
+
interface AlertProps extends AlertOwnProps {
|
|
41
|
+
/** Standard <div> attributes (aria-*, data-*, ...) forwarded to the alert. */
|
|
42
|
+
htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof AlertOwnProps> & DataAttributes;
|
|
43
|
+
}
|
|
44
|
+
declare function Alert({ tone, title, children, action, dismissible, onDismiss, open, banner, icon, className, style, htmlProps, animation, }: AlertProps): react.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { Alert, type AlertAction, type AlertProps, type AlertTone };
|
package/dist/alert.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use client';import { Motion } from './chunk-36WVAQKL.js';
|
|
2
|
+
import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
|
|
3
|
+
import { Presence } from './chunk-MXOPCFWR.js';
|
|
4
|
+
import './chunk-W3SHPKSB.js';
|
|
5
|
+
import './chunk-JSKXZMLH.js';
|
|
6
|
+
import './chunk-L3Q3VDIW.js';
|
|
7
|
+
import { IconSlot } from './chunk-2ERBBFZS.js';
|
|
8
|
+
import { Icon } from './chunk-3SBCBYB7.js';
|
|
9
|
+
import { useControllable } from './chunk-MMRIQNEN.js';
|
|
10
|
+
import './chunk-S5ZTZANS.js';
|
|
11
|
+
import { Button } from './chunk-U5QQZC3U.js';
|
|
12
|
+
import './chunk-VTJTGVZZ.js';
|
|
13
|
+
import { cx } from './chunk-QGNC7LH5.js';
|
|
14
|
+
import './alert.css';
|
|
15
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
16
|
+
|
|
17
|
+
var ALERT_HEIGHT_TIMING = {
|
|
18
|
+
open: { duration: "slow", ease: "entrance" },
|
|
19
|
+
close: { duration: "slow", ease: "entrance" }
|
|
20
|
+
};
|
|
21
|
+
var ALERT_OPACITY_TIMING = {
|
|
22
|
+
open: { duration: "base", ease: "entrance" },
|
|
23
|
+
close: { duration: "fast", ease: "exit" }
|
|
24
|
+
};
|
|
25
|
+
var TONE_GLYPH = {
|
|
26
|
+
info: "info",
|
|
27
|
+
success: "check-circle",
|
|
28
|
+
warning: "warning",
|
|
29
|
+
danger: "warning-circle"
|
|
30
|
+
};
|
|
31
|
+
var TONE_ROLE = { info: "status", success: "status", warning: "alert", danger: "alert" };
|
|
32
|
+
function Alert({
|
|
33
|
+
tone = "info",
|
|
34
|
+
title,
|
|
35
|
+
children = null,
|
|
36
|
+
action = null,
|
|
37
|
+
dismissible = false,
|
|
38
|
+
onDismiss,
|
|
39
|
+
open,
|
|
40
|
+
banner = false,
|
|
41
|
+
icon,
|
|
42
|
+
className = "",
|
|
43
|
+
style,
|
|
44
|
+
htmlProps,
|
|
45
|
+
animation
|
|
46
|
+
}) {
|
|
47
|
+
const [isOpen, setOpen] = useControllable(open, true, onDismiss);
|
|
48
|
+
const dismiss = () => setOpen(false);
|
|
49
|
+
const h = resolveMotionTiming(animation, ALERT_HEIGHT_TIMING);
|
|
50
|
+
const o = resolveMotionTiming(animation, ALERT_OPACITY_TIMING);
|
|
51
|
+
const cls = cx("alert", banner && "alert--banner", className);
|
|
52
|
+
return /* @__PURE__ */ jsx(Presence, { initial: false, children: isOpen && /* @__PURE__ */ jsx(
|
|
53
|
+
Motion,
|
|
54
|
+
{
|
|
55
|
+
className: "alert-shell",
|
|
56
|
+
animate: [
|
|
57
|
+
{ height: [0, "auto"], timing: h.open },
|
|
58
|
+
{ opacity: [0, 1], timing: o.open }
|
|
59
|
+
],
|
|
60
|
+
exit: [
|
|
61
|
+
{ height: ["auto", 0], timing: h.close },
|
|
62
|
+
{ opacity: [1, 0], timing: o.close }
|
|
63
|
+
],
|
|
64
|
+
children: /* @__PURE__ */ jsxs("div", { className: cls, style, "data-tone": tone, role: TONE_ROLE[tone] || "status", ...htmlProps, children: [
|
|
65
|
+
icon === null ? null : /* @__PURE__ */ jsx("span", { className: "alert__icon", "aria-hidden": "true", children: icon !== void 0 ? /* @__PURE__ */ jsx(IconSlot, { size: "md", children: icon }) : /* @__PURE__ */ jsx(Icon, { name: TONE_GLYPH[tone] || "info", size: "md" }) }),
|
|
66
|
+
/* @__PURE__ */ jsxs("div", { className: "alert__body", children: [
|
|
67
|
+
/* @__PURE__ */ jsx("p", { className: "alert__title", children: title }),
|
|
68
|
+
children != null && /* @__PURE__ */ jsx("p", { className: "alert__desc", children })
|
|
69
|
+
] }),
|
|
70
|
+
action && /* @__PURE__ */ jsx(Button, { variant: "unstyled", size: "sm", className: "alert__action", onClick: action.onClick, children: action.label }),
|
|
71
|
+
dismissible && /* @__PURE__ */ jsx("button", { type: "button", className: "alert__close", "aria-label": "Dismiss", onClick: dismiss, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: "sm" }) })
|
|
72
|
+
] })
|
|
73
|
+
},
|
|
74
|
+
"alert-shell"
|
|
75
|
+
) });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { Alert };
|
|
79
|
+
//# sourceMappingURL=alert.js.map
|
|
80
|
+
//# sourceMappingURL=alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/composites/alert/Alert.tsx"],"names":[],"mappings":"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","file":"alert.js","sourcesContent":["'use client';\n\nimport './alert.css';\nimport type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { Presence } from '../../../motion/presence';\nimport { Motion } from '../../../motion/element';\nimport { resolveMotionTiming } from '../../../motion/motion-timing';\nimport type { DisableableAnimation } from '../../../motion/timing';\nimport { Icon, type IconName } from '../../internal/icon/Icon';\nimport { Button } from '../../primitives/button/Button';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport { useControllable } from '../../internal/hooks/use-controllable';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nexport type AlertTone = 'info' | 'success' | 'warning' | 'danger';\n\nexport interface AlertAction {\n /** Sentence-case label, e.g. \"Update billing\". */\n label: string;\n onClick?: () => void;\n}\n\ninterface AlertOwnProps {\n /** Status of the message; info/success are polite, warning/danger assertive. Default 'info'. */\n tone?: AlertTone;\n /** The message - sentence case, ideally one line. */\n title: ReactNode;\n /** Optional description; stays neutral - tone marks the message, not the prose. */\n children?: ReactNode;\n /** One action max, rendered as the system secondary small button. */\n action?: AlertAction;\n /** Renders the always-visible close button. Uncontrolled unless `open` is given. */\n dismissible?: boolean;\n /** Fires on dismiss. With `open` set, the parent owns hiding the alert. */\n onDismiss?: () => void;\n /** Controlled visibility; omit for uncontrolled. Exit eases shut (height collapse). */\n open?: boolean;\n /** App-level strip: square corners, hairline below only. Paint modifier. */\n banner?: boolean;\n /** Override the tone glyph; pass null to render no glyph. */\n icon?: ReactNode | null;\n /** Extra class(es) merged onto the alert. */\n className?: string;\n /** Inline styles merged onto the alert. */\n style?: CSSProperties;\n /** Enter/exit timing - motion tokens only, or `null` to disable (the height collapse snaps).\n * @default height 'slow'/'entrance'; opacity in 'base'/'entrance', out 'fast'/'exit' */\n animation?: DisableableAnimation;\n}\n\nexport interface AlertProps extends AlertOwnProps {\n /** Standard <div> attributes (aria-*, data-*, ...) forwarded to the alert. */\n htmlProps?: Omit<HTMLAttributes<HTMLDivElement>, keyof AlertOwnProps> & DataAttributes;\n}\n\nconst ALERT_HEIGHT_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'slow', ease: 'entrance' },\n} as const;\nconst ALERT_OPACITY_TIMING = {\n open: { duration: 'base', ease: 'entrance' },\n close: { duration: 'fast', ease: 'exit' },\n} as const;\n\nconst TONE_GLYPH: Record<AlertTone, IconName> = {\n info: 'info',\n success: 'check-circle',\n warning: 'warning',\n danger: 'warning-circle',\n};\nconst TONE_ROLE: Record<AlertTone, string> = { info: 'status', success: 'status', warning: 'alert', danger: 'alert' };\n\nexport function Alert({\n tone = 'info',\n title,\n children = null,\n action = null,\n dismissible = false,\n onDismiss,\n open,\n banner = false,\n icon,\n className = '',\n style,\n htmlProps,\n animation,\n}: AlertProps) {\n const [isOpen, setOpen] = useControllable(open, true, onDismiss);\n const dismiss = () => setOpen(false);\n\n const h = resolveMotionTiming(animation, ALERT_HEIGHT_TIMING);\n const o = resolveMotionTiming(animation, ALERT_OPACITY_TIMING);\n\n const cls = cx('alert', banner && 'alert--banner', className);\n\n return (\n <Presence initial={false}>\n {isOpen && (\n <Motion\n key=\"alert-shell\"\n className=\"alert-shell\"\n animate={[\n { height: [0, 'auto'], timing: h.open },\n { opacity: [0, 1], timing: o.open },\n ]}\n exit={[\n { height: ['auto', 0], timing: h.close },\n { opacity: [1, 0], timing: o.close },\n ]}\n >\n <div className={cls} style={style} data-tone={tone} role={TONE_ROLE[tone] || 'status'} {...htmlProps}>\n {icon === null ? null : (\n <span className=\"alert__icon\" aria-hidden=\"true\">\n {icon !== undefined ? (\n <IconSlot size=\"md\">{icon}</IconSlot>\n ) : (\n <Icon name={TONE_GLYPH[tone] || 'info'} size=\"md\" />\n )}\n </span>\n )}\n <div className=\"alert__body\">\n <p className=\"alert__title\">{title}</p>\n {children != null && <p className=\"alert__desc\">{children}</p>}\n </div>\n {action && (\n <Button variant=\"unstyled\" size=\"sm\" className=\"alert__action\" onClick={action.onClick}>\n {action.label}\n </Button>\n )}\n {dismissible && (\n <button type=\"button\" className=\"alert__close\" aria-label=\"Dismiss\" onClick={dismiss}>\n <Icon name=\"close\" size=\"sm\" />\n </button>\n )}\n </div>\n </Motion>\n )}\n </Presence>\n );\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, CSSProperties, HTMLAttributes } from 'react';
|
|
3
|
+
import { AvatarSize } from './avatar.js';
|
|
4
|
+
import { D as DataAttributes } from './dom-props-C0jrllBw.js';
|
|
5
|
+
|
|
6
|
+
interface AvatarGroupOwnProps {
|
|
7
|
+
/** The `Avatar` elements to stack; each is cloned to force `size`, then sliced to `max`. */
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
/** Max visible avatars before "+N" overflow chip. Default 5. */
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Uniform size applied to all children. Default 'md'. */
|
|
12
|
+
size?: AvatarSize;
|
|
13
|
+
/** Extra class(es) merged onto the group wrapper. */
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Inline styles merged onto the group wrapper. */
|
|
16
|
+
style?: CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
interface AvatarGroupProps extends AvatarGroupOwnProps {
|
|
19
|
+
/** Standard <span> attributes forwarded to the group wrapper. */
|
|
20
|
+
htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof AvatarGroupOwnProps> & DataAttributes;
|
|
21
|
+
}
|
|
22
|
+
declare function AvatarGroup({ children, max, size, className, style, htmlProps }: AvatarGroupProps): react.JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { AvatarGroup, type AvatarGroupProps };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';import { cx } from './chunk-QGNC7LH5.js';
|
|
2
|
+
import './avatar.css';
|
|
3
|
+
import { Children, isValidElement, cloneElement } from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function AvatarGroup({ children, max = 5, size = "md", className = "", style, htmlProps }) {
|
|
7
|
+
const items = Children.toArray(children);
|
|
8
|
+
const visible = max > 0 ? items.slice(0, max) : items;
|
|
9
|
+
const overflow = items.length - visible.length;
|
|
10
|
+
return /* @__PURE__ */ jsxs("span", { className: cx("avatar-group", className), style, ...htmlProps, children: [
|
|
11
|
+
visible.map(
|
|
12
|
+
(child, i) => isValidElement(child) ? cloneElement(child, { size, key: child.key ?? i }) : child
|
|
13
|
+
),
|
|
14
|
+
overflow > 0 && /* @__PURE__ */ jsx("span", { className: `avatar avatar--${size} avatar--overflow`, role: "img", "aria-label": `${overflow} more`, children: /* @__PURE__ */ jsx("span", { className: "avatar__face", children: /* @__PURE__ */ jsxs("span", { className: "avatar__initials", children: [
|
|
15
|
+
"+",
|
|
16
|
+
overflow
|
|
17
|
+
] }) }) })
|
|
18
|
+
] });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { AvatarGroup };
|
|
22
|
+
//# sourceMappingURL=avatar-group.js.map
|
|
23
|
+
//# sourceMappingURL=avatar-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/primitives/avatar/AvatarGroup.tsx"],"names":[],"mappings":";;;;;AAkCO,SAAS,WAAA,CAAY,EAAE,QAAA,EAAU,GAAA,GAAM,CAAA,EAAG,IAAA,GAAO,IAAA,EAAM,SAAA,GAAY,EAAA,EAAI,KAAA,EAAO,SAAA,EAAU,EAAqB;AAClH,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA;AACvC,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,UAAK,SAAA,EAAW,EAAA,CAAG,gBAAgB,SAAS,CAAA,EAAG,KAAA,EAAe,GAAG,SAAA,EAC/D,QAAA,EAAA;AAAA,IAAA,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,KAAA,EAAO,CAAA,KACnB,cAAA,CAAe,KAAK,CAAA,GAChB,YAAA,CAAa,KAAA,EAA8C,EAAE,MAAM,GAAA,EAAK,KAAA,CAAM,GAAA,IAAO,CAAA,EAAG,CAAA,GACxF;AAAA,KACN;AAAA,IACC,QAAA,GAAW,qBACV,GAAA,CAAC,MAAA,EAAA,EAAK,WAAW,CAAA,eAAA,EAAkB,IAAI,qBAAqB,IAAA,EAAK,KAAA,EAAM,cAAY,CAAA,EAAG,QAAQ,SAC5F,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,cAAA,EACd,QAAA,kBAAA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kBAAA,EAAmB,QAAA,EAAA;AAAA,MAAA,GAAA;AAAA,MAAE;AAAA,KAAA,EAAS,GAChD,CAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"avatar-group.js","sourcesContent":["'use client';\n\nimport './avatar.css';\nimport {\n Children,\n cloneElement,\n isValidElement,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport type { AvatarSize } from './Avatar';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\ninterface AvatarGroupOwnProps {\n /** The `Avatar` elements to stack; each is cloned to force `size`, then sliced to `max`. */\n children: 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 /** Extra class(es) merged onto the group wrapper. */\n className?: string;\n /** Inline styles merged onto the group wrapper. */\n style?: CSSProperties;\n}\n\nexport interface AvatarGroupProps extends AvatarGroupOwnProps {\n /** Standard <span> attributes forwarded to the group wrapper. */\n htmlProps?: Omit<HTMLAttributes<HTMLSpanElement>, keyof AvatarGroupOwnProps> & DataAttributes;\n}\n\nexport function AvatarGroup({ children, max = 5, size = 'md', className = '', style, htmlProps }: AvatarGroupProps) {\n const items = 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={cx('avatar-group', className)} style={style} {...htmlProps}>\n {visible.map((child, i) =>\n isValidElement(child)\n ? cloneElement(child as ReactElement<{ size?: AvatarSize }>, { size, key: child.key ?? i })\n : child,\n )}\n {overflow > 0 && (\n <span className={`avatar avatar--${size} avatar--overflow`} role=\"img\" aria-label={`${overflow} more`}>\n <span className=\"avatar__face\">\n <span className=\"avatar__initials\">+{overflow}</span>\n </span>\n </span>\n )}\n </span>\n );\n}\n"]}
|