@puzzle-ui/ui 0.4.0 → 0.5.1
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/README.md +61 -77
- package/dist/components/actions/button/button.css +5 -2
- package/dist/components/actions/button-group/button-group.css +16 -17
- package/dist/components/data-display/badge/badge.css +15 -2
- package/dist/components/data-display/badge/index.cjs +13 -2
- package/dist/components/data-display/badge/index.cjs.map +1 -1
- package/dist/components/data-display/badge/index.d.cts +7 -2
- package/dist/components/data-display/badge/index.d.ts +7 -2
- package/dist/components/data-display/badge/index.js +13 -2
- package/dist/components/data-display/badge/index.js.map +1 -1
- package/dist/components/data-display/rating/index.cjs +84 -0
- package/dist/components/data-display/rating/index.cjs.map +1 -0
- package/dist/components/data-display/rating/index.d.cts +3 -0
- package/dist/components/data-display/rating/index.d.ts +3 -0
- package/dist/components/data-display/rating/index.js +84 -0
- package/dist/components/data-display/rating/index.js.map +1 -0
- package/dist/components/data-display/rating/rating.css +72 -0
- package/dist/components/data-display/rating/rating.types.d.cts +15 -0
- package/dist/components/data-display/rating/rating.types.d.ts +15 -0
- package/dist/components/data-display/rating/rating.utils.cjs +27 -0
- package/dist/components/data-display/rating/rating.utils.cjs.map +1 -0
- package/dist/components/data-display/rating/rating.utils.js +25 -0
- package/dist/components/data-display/rating/rating.utils.js.map +1 -0
- package/dist/components/forms/checkbox/checkbox.css +2 -10
- package/dist/components/forms/input-group/input-group.d.cts +4 -2
- package/dist/components/forms/input-group/input-group.d.ts +4 -2
- package/dist/components/forms/radio-group/index.d.cts +2 -1
- package/dist/components/forms/radio-group/index.d.ts +2 -1
- package/dist/components/forms/stepper/index.d.cts +4 -2
- package/dist/components/forms/stepper/index.d.ts +4 -2
- package/dist/components/forms/time-picker/index.cjs +108 -0
- package/dist/components/forms/time-picker/index.cjs.map +1 -0
- package/dist/components/forms/time-picker/index.d.cts +3 -0
- package/dist/components/forms/time-picker/index.d.ts +3 -0
- package/dist/components/forms/time-picker/index.js +108 -0
- package/dist/components/forms/time-picker/index.js.map +1 -0
- package/dist/components/forms/time-picker/time-picker.css +166 -0
- package/dist/components/forms/time-picker/time-picker.types.d.cts +34 -0
- package/dist/components/forms/time-picker/time-picker.types.d.ts +34 -0
- package/dist/components/forms/time-picker/time-picker.utils.cjs +25 -0
- package/dist/components/forms/time-picker/time-picker.utils.cjs.map +1 -0
- package/dist/components/forms/time-picker/time-picker.utils.js +24 -0
- package/dist/components/forms/time-picker/time-picker.utils.js.map +1 -0
- package/dist/components/forms/token-input/index.cjs +189 -0
- package/dist/components/forms/token-input/index.cjs.map +1 -0
- package/dist/components/forms/token-input/index.d.cts +3 -0
- package/dist/components/forms/token-input/index.d.ts +3 -0
- package/dist/components/forms/token-input/index.js +189 -0
- package/dist/components/forms/token-input/index.js.map +1 -0
- package/dist/components/forms/token-input/token-input.css +145 -0
- package/dist/components/forms/token-input/token-input.types.d.cts +48 -0
- package/dist/components/forms/token-input/token-input.types.d.ts +48 -0
- package/dist/components/forms/token-input/token-input.utils.cjs +30 -0
- package/dist/components/forms/token-input/token-input.utils.cjs.map +1 -0
- package/dist/components/forms/token-input/token-input.utils.js +24 -0
- package/dist/components/forms/token-input/token-input.utils.js.map +1 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio.css +14 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs +11 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs.map +1 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js +11 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js.map +1 -0
- package/dist/components/layout/aspect-ratio/index.cjs +16 -0
- package/dist/components/layout/aspect-ratio/index.cjs.map +1 -0
- package/dist/components/layout/aspect-ratio/index.d.cts +11 -0
- package/dist/components/layout/aspect-ratio/index.d.ts +11 -0
- package/dist/components/layout/aspect-ratio/index.js +16 -0
- package/dist/components/layout/aspect-ratio/index.js.map +1 -0
- package/dist/components/layout/container/container.css +1 -0
- package/dist/components/layout/page-layout/page-layout.css +1 -0
- package/dist/components/layout/scroll-area/index.cjs +27 -0
- package/dist/components/layout/scroll-area/index.cjs.map +1 -0
- package/dist/components/layout/scroll-area/index.d.cts +15 -0
- package/dist/components/layout/scroll-area/index.d.ts +15 -0
- package/dist/components/layout/scroll-area/index.js +27 -0
- package/dist/components/layout/scroll-area/index.js.map +1 -0
- package/dist/components/layout/scroll-area/scroll-area.css +25 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.cjs +8 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.cjs.map +1 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.d.cts +2 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.d.ts +2 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.js +8 -0
- package/dist/components/layout/scroll-area/scroll-area.utils.js.map +1 -0
- package/dist/components/layout/section/index.cjs +10 -4
- package/dist/components/layout/section/index.cjs.map +1 -1
- package/dist/components/layout/section/index.d.cts +1 -1
- package/dist/components/layout/section/index.d.ts +1 -1
- package/dist/components/layout/section/index.js +11 -5
- package/dist/components/layout/section/index.js.map +1 -1
- package/dist/components/layout/section/section.css +9 -3
- package/dist/components/layout/section/types.d.cts +5 -5
- package/dist/components/layout/section/types.d.ts +5 -5
- package/dist/components/layout/separator/index.cjs +18 -0
- package/dist/components/layout/separator/index.cjs.map +1 -0
- package/dist/components/layout/separator/index.d.cts +17 -0
- package/dist/components/layout/separator/index.d.ts +17 -0
- package/dist/components/layout/separator/index.js +18 -0
- package/dist/components/layout/separator/index.js.map +1 -0
- package/dist/components/layout/separator/separator.css +15 -0
- package/dist/components/layout/separator/separator.utils.cjs +11 -0
- package/dist/components/layout/separator/separator.utils.cjs.map +1 -0
- package/dist/components/layout/separator/separator.utils.d.cts +2 -0
- package/dist/components/layout/separator/separator.utils.d.ts +2 -0
- package/dist/components/layout/separator/separator.utils.js +11 -0
- package/dist/components/layout/separator/separator.utils.js.map +1 -0
- package/dist/components/layout/stack/index.cjs +18 -2
- package/dist/components/layout/stack/index.cjs.map +1 -1
- package/dist/components/layout/stack/index.d.cts +8 -6
- package/dist/components/layout/stack/index.d.ts +8 -6
- package/dist/components/layout/stack/index.js +18 -2
- package/dist/components/layout/stack/index.js.map +1 -1
- package/dist/components/layout/stack/stack.css +118 -138
- package/dist/components/navigation/carousel/index.cjs +4 -1
- package/dist/components/navigation/carousel/index.cjs.map +1 -1
- package/dist/components/navigation/carousel/index.js +4 -1
- package/dist/components/navigation/carousel/index.js.map +1 -1
- package/dist/components/navigation/tabs/index.d.cts +3 -2
- package/dist/components/navigation/tabs/index.d.ts +3 -2
- package/dist/components/navigation/tree-view/index.cjs +1 -1
- package/dist/components/navigation/tree-view/index.cjs.map +1 -1
- package/dist/components/navigation/tree-view/index.d.cts +5 -1
- package/dist/components/navigation/tree-view/index.d.ts +5 -1
- package/dist/components/navigation/tree-view/index.js +1 -1
- package/dist/components/navigation/tree-view/index.js.map +1 -1
- package/dist/components/navigation/tree-view/tree-view.css +5 -3
- package/dist/components/overlays/context-menu/context-menu.css +151 -0
- package/dist/components/overlays/context-menu/context-menu.types.d.cts +69 -0
- package/dist/components/overlays/context-menu/context-menu.types.d.ts +69 -0
- package/dist/components/overlays/context-menu/context-menu.utils.cjs +46 -0
- package/dist/components/overlays/context-menu/context-menu.utils.cjs.map +1 -0
- package/dist/components/overlays/context-menu/context-menu.utils.js +40 -0
- package/dist/components/overlays/context-menu/context-menu.utils.js.map +1 -0
- package/dist/components/overlays/context-menu/index.cjs +830 -0
- package/dist/components/overlays/context-menu/index.cjs.map +1 -0
- package/dist/components/overlays/context-menu/index.d.cts +42 -0
- package/dist/components/overlays/context-menu/index.d.ts +42 -0
- package/dist/components/overlays/context-menu/index.js +818 -0
- package/dist/components/overlays/context-menu/index.js.map +1 -0
- package/dist/components/typography/heading.cjs +6 -2
- package/dist/components/typography/heading.cjs.map +1 -1
- package/dist/components/typography/heading.d.cts +3 -2
- package/dist/components/typography/heading.d.ts +3 -2
- package/dist/components/typography/heading.js +6 -2
- package/dist/components/typography/heading.js.map +1 -1
- package/dist/components/typography/text.cjs +6 -2
- package/dist/components/typography/text.cjs.map +1 -1
- package/dist/components/typography/text.d.cts +3 -2
- package/dist/components/typography/text.d.ts +3 -2
- package/dist/components/typography/text.js +6 -2
- package/dist/components/typography/text.js.map +1 -1
- package/dist/components/utilities/preview/index.cjs +88 -20
- package/dist/components/utilities/preview/index.cjs.map +1 -1
- package/dist/components/utilities/preview/index.d.cts +6 -2
- package/dist/components/utilities/preview/index.d.ts +6 -2
- package/dist/components/utilities/preview/index.js +88 -20
- package/dist/components/utilities/preview/index.js.map +1 -1
- package/dist/components/utilities/preview/preview.css +26 -11
- package/dist/components/utilities/transition/index.d.cts +1 -1
- package/dist/components/utilities/transition/index.d.ts +1 -1
- package/dist/index.cjs +123 -97
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +8 -1
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -1,99 +1,83 @@
|
|
|
1
|
-
|
|
2
|
-
title: Getting Started
|
|
3
|
-
description: Install Puzzle in your React app, build your first interface, and customize the theme.
|
|
4
|
-
---
|
|
1
|
+
# @puzzle-ui/ui
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
>
|
|
8
|
-
> This project is under active development. APIs, component props,
|
|
9
|
-
> package exports, styling, and internal implementation may change
|
|
10
|
-
> without notice. Components may be incomplete, and testing,
|
|
11
|
-
> accessibility, documentation, and framework compatibility are not yet
|
|
12
|
-
> guaranteed. Use it for experimentation and evaluation only---not for
|
|
13
|
-
> production applications.
|
|
3
|
+
Accessible, token-driven React components for building Puzzle interfaces.
|
|
14
4
|
|
|
15
|
-
|
|
5
|
+
**Documentation:** [https://puzzle-ui.com/docs/ui](https://puzzle-ui.com/docs/ui)
|
|
16
6
|
|
|
17
|
-
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> **Puzzle is not ready for production use.** APIs, component props, package
|
|
9
|
+
> exports, and styling may change without notice. Accessibility and framework
|
|
10
|
+
> compatibility are still being tested. Use it for experimentation and
|
|
11
|
+
> evaluation.
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
`@puzzle-ui/ui` provides composable, router-independent React components:
|
|
14
|
+
actions, data display, editors, forms, layout, navigation, overlays,
|
|
15
|
+
typography, and utilities. Components use semantic HTML and native browser
|
|
16
|
+
behavior first, and all styling comes from the CSS custom properties supplied
|
|
17
|
+
by [`@puzzle-ui/theme`](https://puzzle-ui.com/docs/theme), so one `Theme`
|
|
18
|
+
provider styles your whole application.
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
- An existing React application with a bundler that supports CSS imports, such as Vite.
|
|
23
|
-
- Familiarity with React and TypeScript. The UI and theme packages require React and React DOM 19 or later within the supported React 19 range.
|
|
24
|
-
|
|
25
|
-
## Set up a new project
|
|
26
|
-
|
|
27
|
-
Simple run our @puzzle-ui/create project template to get started.
|
|
28
|
-
|
|
29
|
-
npm:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx @puzzle-ui/create
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
bun:
|
|
20
|
+
## Install
|
|
36
21
|
|
|
37
22
|
```bash
|
|
38
|
-
|
|
23
|
+
npm install @puzzle-ui/ui @puzzle-ui/theme
|
|
24
|
+
# or
|
|
25
|
+
bun add @puzzle-ui/ui @puzzle-ui/theme
|
|
26
|
+
# or
|
|
27
|
+
pnpm add @puzzle-ui/ui @puzzle-ui/theme
|
|
28
|
+
# or
|
|
29
|
+
yarn add @puzzle-ui/ui @puzzle-ui/theme
|
|
39
30
|
```
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- Basic React app
|
|
44
|
-
- Tanstack start
|
|
45
|
-
- Next.js
|
|
32
|
+
React and React DOM 19 are peer dependencies and should already be installed
|
|
33
|
+
in your application.
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
To start a new project with Puzzle preconfigured, run
|
|
36
|
+
[`npx @puzzle-ui/create`](https://puzzle-ui.com/docs/create).
|
|
49
37
|
|
|
50
|
-
##
|
|
38
|
+
## Usage
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
npm:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
npm install @puzzle-ui/ui --save
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
bun:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
bun add @puzzle-ui/create
|
|
64
|
-
```
|
|
40
|
+
Wrap your application in `Theme` and import components from `@puzzle-ui/ui`:
|
|
65
41
|
|
|
66
|
-
|
|
42
|
+
```tsx
|
|
43
|
+
import { Theme } from "@puzzle-ui/theme";
|
|
44
|
+
import { Button, Stack, Text } from "@puzzle-ui/ui";
|
|
67
45
|
|
|
68
|
-
|
|
69
|
-
|
|
46
|
+
export const App = () => (
|
|
47
|
+
<Theme>
|
|
48
|
+
<Stack direction="col" gap="sm">
|
|
49
|
+
<Text>Build your interface with Puzzle.</Text>
|
|
50
|
+
<Button>Get started</Button>
|
|
51
|
+
</Stack>
|
|
52
|
+
</Theme>
|
|
53
|
+
);
|
|
70
54
|
```
|
|
71
55
|
|
|
72
|
-
|
|
56
|
+
## Component categories
|
|
73
57
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
| Category | Components |
|
|
59
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| Actions | Button, ButtonGroup, ToggleGroup |
|
|
61
|
+
| Data display | Alert, Avatar, Badge, Card, EmptyState, Image, Paper, Progress, Rating, Skeleton |
|
|
62
|
+
| Editors | TextEditor, TextEditorToolbar, TextRenderer |
|
|
63
|
+
| Forms | Autocomplete, Checkbox, ColorPicker, DatePicker, FileUpload, FormField, inputs, Radio, Select, Slider, Switch |
|
|
64
|
+
| Layout | AppBar, AspectRatio, Container, PageLayout, ResizablePanels, ScrollArea, Section, Separator, Sidebar, Stack |
|
|
65
|
+
| Navigation | Accordion, Breadcrumbs, Carousel, Link, Pagination, Tabs, TreeView |
|
|
66
|
+
| Overlays | Command, ContextMenu, Dialog, Drawer, DropdownMenu, Notification, Popover, Tooltip |
|
|
67
|
+
| Typography | Heading, Text |
|
|
68
|
+
| Utilities | Portal, Preview, ScrollLock, Transition |
|
|
77
69
|
|
|
78
|
-
|
|
70
|
+
Browse every component with live examples, props, and accessibility guidance
|
|
71
|
+
in the [component documentation](https://puzzle-ui.com/docs/ui).
|
|
79
72
|
|
|
80
|
-
##
|
|
73
|
+
## Framework integration
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
Components do not depend on a router or framework. Use the `components`
|
|
76
|
+
prop of `Theme` to provide your framework's link and image components; see
|
|
77
|
+
[Component Overrides](https://puzzle-ui.com/docs/theme/components).
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
import { Theme } from "@puzzle-ui/theme";
|
|
86
|
-
import { Button } from "@puzzle-ui/ui";
|
|
79
|
+
## Related packages
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<h1>Hello, Puzzle</h1>
|
|
92
|
-
<p>Build your interface with reusable components and shared tokens.</p>
|
|
93
|
-
<Button onClick={() => window.alert("Welcome to Puzzle!")}>
|
|
94
|
-
Get started
|
|
95
|
-
</Button>
|
|
96
|
-
</main>
|
|
97
|
-
</Theme>
|
|
98
|
-
);
|
|
99
|
-
```
|
|
81
|
+
- [`@puzzle-ui/theme`](https://puzzle-ui.com/docs/theme) — design tokens and the `Theme` provider.
|
|
82
|
+
- [`@puzzle-ui/icons`](https://puzzle-ui.com/docs/icons) — icon components.
|
|
83
|
+
- [`@puzzle-ui/hooks`](https://puzzle-ui.com/docs/hooks) — reusable React hooks.
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.puzzle-button--primary:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
47
|
-
|
|
47
|
+
background: color-mix(in srgb, var(--puzzle-color-primary) 88%, var(--puzzle-color-text));
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.puzzle-button--secondary {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
.puzzle-button--secondary:hover:not(:disabled):not([aria-disabled="true"]) {
|
|
56
|
-
|
|
56
|
+
background: color-mix(in srgb, var(--puzzle-color-surface-sunken) 85%, var(--puzzle-color-text));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
.puzzle-button--outline {
|
|
@@ -160,7 +160,10 @@
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
.puzzle-button__content {
|
|
163
|
+
gap: var(--puzzle-button-gap, var(--puzzle-space-2, .5rem));
|
|
164
|
+
flex-direction: row;
|
|
163
165
|
flex: 0 auto;
|
|
166
|
+
display: inline-flex;
|
|
164
167
|
}
|
|
165
168
|
|
|
166
169
|
.puzzle-button__leading, .puzzle-button__trailing, .puzzle-button__spinner {
|
|
@@ -24,41 +24,40 @@
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.puzzle-button-group--attached {
|
|
27
|
+
--puzzle-button-group-divider-color: var(--puzzle-color-border);
|
|
28
|
+
isolation: isolate;
|
|
27
29
|
gap: 0;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
.puzzle-button-group--attached > :
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.puzzle-button-group--horizontal .puzzle-button-group--attached {
|
|
35
|
-
border-radius: inherit;
|
|
32
|
+
.puzzle-button-group--attached > :is(:hover, :focus-visible) {
|
|
33
|
+
z-index: 1;
|
|
34
|
+
position: relative;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
.puzzle-button-group--attached > :not(:first-child)
|
|
39
|
-
border-
|
|
37
|
+
.puzzle-button-group--horizontal.puzzle-button-group--attached > :not(:first-child) {
|
|
38
|
+
border-inline-start: 1px solid var(--puzzle-button-group-divider-color);
|
|
39
|
+
border-start-start-radius: 0;
|
|
40
|
+
border-end-start-radius: 0;
|
|
41
|
+
margin-inline-start: -1px;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
.puzzle-button-group--horizontal
|
|
44
|
+
.puzzle-button-group--horizontal.puzzle-button-group--attached > :not(:last-child) {
|
|
43
45
|
border-start-end-radius: 0;
|
|
44
46
|
border-end-end-radius: 0;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
.puzzle-button-group--
|
|
49
|
+
.puzzle-button-group--vertical.puzzle-button-group--attached > :not(:first-child) {
|
|
50
|
+
border-block-start: 1px solid var(--puzzle-button-group-divider-color);
|
|
48
51
|
border-start-start-radius: 0;
|
|
49
|
-
border-end-
|
|
52
|
+
border-start-end-radius: 0;
|
|
53
|
+
margin-block-start: -1px;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
.puzzle-button-group--vertical
|
|
56
|
+
.puzzle-button-group--vertical.puzzle-button-group--attached > :not(:last-child) {
|
|
53
57
|
border-end-end-radius: 0;
|
|
54
58
|
border-end-start-radius: 0;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
.puzzle-button-group--vertical .puzzle-button-group--attached > :last-child {
|
|
58
|
-
border-start-start-radius: 0;
|
|
59
|
-
border-start-end-radius: 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
61
|
.puzzle-button-group--disabled {
|
|
63
62
|
cursor: not-allowed;
|
|
64
63
|
}
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
.puzzle-badge {
|
|
2
|
+
justify-content: center;
|
|
3
|
+
align-items: center;
|
|
2
4
|
display: inline-flex;
|
|
3
5
|
position: relative;
|
|
4
6
|
}
|
|
5
7
|
|
|
6
8
|
.puzzle-badge > .puzzle-badge-indicator {
|
|
7
|
-
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
padding: var(--puzzle-space-1) var(--puzzle-space-2);
|
|
8
11
|
border-radius: var(--puzzle-radius-full, 50%);
|
|
9
12
|
font-weight: var(--puzzle-font-weight-normal, 400);
|
|
10
13
|
line-height: var(--puzzle-font-line-height-none, 1);
|
|
11
14
|
text-align: center;
|
|
15
|
+
white-space: nowrap;
|
|
12
16
|
vertical-align: middle;
|
|
13
17
|
justify-content: center;
|
|
14
18
|
align-items: center;
|
|
15
|
-
padding: .25em;
|
|
16
19
|
display: inline-flex;
|
|
17
20
|
position: absolute;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
.puzzle-badge > .puzzle-badge-indicator--single {
|
|
24
|
+
padding-inline: var(--puzzle-space-1);
|
|
25
|
+
aspect-ratio: 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
.puzzle-badge-primary > .puzzle-badge-indicator {
|
|
21
29
|
background-color: var(--puzzle-color-primary);
|
|
22
30
|
color: var(--puzzle-color-primary-foreground);
|
|
@@ -89,3 +97,8 @@
|
|
|
89
97
|
left: 85.3553%;
|
|
90
98
|
transform: translate(-50%, -50%);
|
|
91
99
|
}
|
|
100
|
+
|
|
101
|
+
.puzzle-badge.puzzle-badge-standalone > .puzzle-badge-indicator {
|
|
102
|
+
position: static;
|
|
103
|
+
transform: none;
|
|
104
|
+
}
|
|
@@ -6,19 +6,30 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
6
6
|
const Badge = ({ content, size = 20, color = "primary", anchorOrigin = {
|
|
7
7
|
vertical: "top",
|
|
8
8
|
horizontal: "right"
|
|
9
|
+
}, anchorOffset = {
|
|
10
|
+
vertical: 0,
|
|
11
|
+
horizontal: 0
|
|
9
12
|
}, anchorOverlap = "rectangular", className, children }) => {
|
|
13
|
+
if (!Number.isFinite(anchorOffset.vertical) || !Number.isFinite(anchorOffset.horizontal)) throw new TypeError("Badge anchorOffset values must be finite numbers.");
|
|
10
14
|
const resolvedSize = Math.max(size, 16);
|
|
11
15
|
const isHex = (0, _puzzle_ui_core.isHexColor)(color);
|
|
12
16
|
const isDark = isHex ? (0, _puzzle_ui_core.isDarkColor)(color) : false;
|
|
13
|
-
const
|
|
17
|
+
const textContent = typeof content === "string" || typeof content === "number" ? String(content).trim() : null;
|
|
18
|
+
const isSingleCharacter = textContent != null && Array.from(textContent).length === 1;
|
|
19
|
+
const classes = (0, _puzzle_ui_core.cn)("puzzle-badge", children != null && [
|
|
20
|
+
anchorOrigin.vertical,
|
|
21
|
+
anchorOrigin.horizontal,
|
|
22
|
+
anchorOverlap
|
|
23
|
+
], children == null && "puzzle-badge-standalone", !isHex && `puzzle-badge-${color}`, className);
|
|
14
24
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
15
25
|
className: classes,
|
|
16
26
|
children: [children, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
17
|
-
className: "puzzle-badge-indicator",
|
|
27
|
+
className: (0, _puzzle_ui_core.cn)("puzzle-badge-indicator", isSingleCharacter && "puzzle-badge-indicator--single"),
|
|
18
28
|
style: {
|
|
19
29
|
fontSize: `clamp(0.7rem, calc(${resolvedSize}px - 1em), 4rem)`,
|
|
20
30
|
minHeight: `${resolvedSize}px`,
|
|
21
31
|
minWidth: `${resolvedSize}px`,
|
|
32
|
+
translate: children != null ? `${anchorOffset.horizontal * (anchorOrigin.horizontal === "left" ? 1 : -1)}px ${anchorOffset.vertical * (anchorOrigin.vertical === "top" ? 1 : -1)}px` : void 0,
|
|
22
33
|
backgroundColor: isHex ? color : void 0,
|
|
23
34
|
color: isHex ? isDark ? "var(--puzzle-color-light-foreground)" : "var(--puzzle-color-dark-foreground)" : void 0
|
|
24
35
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["isHexColor","isDarkColor","cn"],"sources":["../../../../src/components/data-display/badge/index.tsx"],"sourcesContent":["import { cn, isDarkColor, isHexColor } from \"@puzzle-ui/core\";\nimport { type ReactNode } from \"react\";\nimport \"./badge.css\";\n\ntype AnchorOrigin = {\n vertical: \"top\" | \"bottom\";\n horizontal: \"left\" | \"right\";\n};\n\ntype AnchorOverlap = \"rectangular\" | \"circular\";\ntype BadgeColor =\n | \"primary\"\n | \"secondary\"\n | \"accent\"\n | \"danger\"\n | \"info\"\n | `#${string}`;\n\ntype BadgeProps = {\n content: ReactNode;\n size?: number;\n color?: BadgeColor;\n anchorOrigin?: AnchorOrigin;\n anchorOverlap?: AnchorOverlap;\n className?: string;\n children?: ReactNode;\n};\n\nconst Badge = ({\n content,\n size = 20,\n color = \"primary\",\n anchorOrigin = { vertical: \"top\", horizontal: \"right\" },\n anchorOverlap = \"rectangular\",\n className,\n children,\n}: BadgeProps) => {\n const resolvedSize = Math.max(size, 16);\n const isHex = isHexColor(color);\n const isDark = isHex ? isDarkColor(color) : false;\n\n const classes = cn(\n \"puzzle-badge\",\n anchorOrigin.vertical,\n
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["isHexColor","isDarkColor","cn"],"sources":["../../../../src/components/data-display/badge/index.tsx"],"sourcesContent":["import { cn, isDarkColor, isHexColor } from \"@puzzle-ui/core\";\nimport { type ReactNode } from \"react\";\nimport \"./badge.css\";\n\ntype AnchorOrigin = {\n vertical: \"top\" | \"bottom\";\n horizontal: \"left\" | \"right\";\n};\n\ntype AnchorOffset = {\n vertical: number;\n horizontal: number;\n};\n\ntype AnchorOverlap = \"rectangular\" | \"circular\";\ntype BadgeColor =\n | \"primary\"\n | \"secondary\"\n | \"accent\"\n | \"danger\"\n | \"info\"\n | `#${string}`;\n\ntype BadgeProps = {\n content: ReactNode;\n size?: number;\n color?: BadgeColor;\n anchorOrigin?: AnchorOrigin;\n anchorOffset?: AnchorOffset;\n anchorOverlap?: AnchorOverlap;\n className?: string;\n children?: ReactNode;\n};\n\nconst Badge = ({\n content,\n size = 20,\n color = \"primary\",\n anchorOrigin = { vertical: \"top\", horizontal: \"right\" },\n anchorOffset = { vertical: 0, horizontal: 0 },\n anchorOverlap = \"rectangular\",\n className,\n children,\n}: BadgeProps) => {\n if (!Number.isFinite(anchorOffset.vertical) || !Number.isFinite(anchorOffset.horizontal)) {\n throw new TypeError(\"Badge anchorOffset values must be finite numbers.\");\n }\n\n const resolvedSize = Math.max(size, 16);\n const isHex = isHexColor(color);\n const isDark = isHex ? isDarkColor(color) : false;\n\n const textContent =\n typeof content === \"string\" || typeof content === \"number\"\n ? String(content).trim()\n : null;\n const isSingleCharacter =\n textContent != null && Array.from(textContent).length === 1;\n\n const classes = cn(\n \"puzzle-badge\",\n children != null && [\n anchorOrigin.vertical,\n anchorOrigin.horizontal,\n anchorOverlap,\n ],\n children == null && \"puzzle-badge-standalone\",\n !isHex && `puzzle-badge-${color}`,\n className,\n );\n\n return (\n <div className={classes}>\n {children}\n <span\n className={cn(\n \"puzzle-badge-indicator\",\n isSingleCharacter && \"puzzle-badge-indicator--single\",\n )}\n style={{\n fontSize: `clamp(0.7rem, calc(${resolvedSize}px - 1em), 4rem)`,\n minHeight: `${resolvedSize}px`,\n minWidth: `${resolvedSize}px`,\n translate: children != null\n ? `${anchorOffset.horizontal * (anchorOrigin.horizontal === \"left\" ? 1 : -1)}px ${anchorOffset.vertical * (anchorOrigin.vertical === \"top\" ? 1 : -1)}px`\n : undefined,\n backgroundColor: isHex ? color : undefined,\n color: isHex\n ? isDark\n ? \"var(--puzzle-color-light-foreground)\"\n : \"var(--puzzle-color-dark-foreground)\"\n : undefined,\n }}\n >\n {content}\n </span>\n </div>\n );\n};\n\nexport {\n Badge,\n type BadgeProps,\n type BadgeColor,\n type AnchorOrigin,\n type AnchorOffset,\n type AnchorOverlap,\n};\n"],"mappings":";;;;;AAkCA,MAAM,SAAS,EACb,SACA,OAAO,IACP,QAAQ,WACR,eAAe;CAAE,UAAU;CAAO,YAAY;AAAQ,GACtD,eAAe;CAAE,UAAU;CAAG,YAAY;AAAE,GAC5C,gBAAgB,eAChB,WACA,eACgB;CAChB,IAAI,CAAC,OAAO,SAAS,aAAa,QAAQ,KAAK,CAAC,OAAO,SAAS,aAAa,UAAU,GACrF,MAAM,IAAI,UAAU,mDAAmD;CAGzE,MAAM,eAAe,KAAK,IAAI,MAAM,EAAE;CACtC,MAAM,SAAA,GAAQA,gBAAAA,WAAAA,CAAW,KAAK;CAC9B,MAAM,SAAS,SAAA,GAAQC,gBAAAA,YAAAA,CAAY,KAAK,IAAI;CAE5C,MAAM,cACJ,OAAO,YAAY,YAAY,OAAO,YAAY,WAC9C,OAAO,OAAO,CAAC,CAAC,KAAK,IACrB;CACN,MAAM,oBACJ,eAAe,QAAQ,MAAM,KAAK,WAAW,CAAC,CAAC,WAAW;CAE5D,MAAM,WAAA,GAAUC,gBAAAA,GAAAA,CACd,gBACA,YAAY,QAAQ;EAClB,aAAa;EACb,aAAa;EACb;CACF,GACA,YAAY,QAAQ,2BACpB,CAAC,SAAS,gBAAgB,SAC1B,SACF;CAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAW;EAAhB,UAAA,CACG,UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;GACE,YAAA,GAAWA,gBAAAA,GAAAA,CACT,0BACA,qBAAqB,gCACvB;GACA,OAAO;IACL,UAAU,sBAAsB,aAAa;IAC7C,WAAW,GAAG,aAAa;IAC3B,UAAU,GAAG,aAAa;IAC1B,WAAW,YAAY,OACnB,GAAG,aAAa,cAAc,aAAa,eAAe,SAAS,IAAI,IAAI,KAAK,aAAa,YAAY,aAAa,aAAa,QAAQ,IAAI,IAAI,MACnJ,KAAA;IACJ,iBAAiB,QAAQ,QAAQ,KAAA;IACjC,OAAO,QACH,SACE,yCACA,wCACF,KAAA;GACN;GAEC,UAAA;EACG,CAAA,CACH;;AAET"}
|
|
@@ -3,6 +3,10 @@ type AnchorOrigin = {
|
|
|
3
3
|
vertical: "top" | "bottom";
|
|
4
4
|
horizontal: "left" | "right";
|
|
5
5
|
};
|
|
6
|
+
type AnchorOffset = {
|
|
7
|
+
vertical: number;
|
|
8
|
+
horizontal: number;
|
|
9
|
+
};
|
|
6
10
|
type AnchorOverlap = "rectangular" | "circular";
|
|
7
11
|
type BadgeColor = "primary" | "secondary" | "accent" | "danger" | "info" | `#${string}`;
|
|
8
12
|
type BadgeProps = {
|
|
@@ -10,9 +14,10 @@ type BadgeProps = {
|
|
|
10
14
|
size?: number;
|
|
11
15
|
color?: BadgeColor;
|
|
12
16
|
anchorOrigin?: AnchorOrigin;
|
|
17
|
+
anchorOffset?: AnchorOffset;
|
|
13
18
|
anchorOverlap?: AnchorOverlap;
|
|
14
19
|
className?: string;
|
|
15
20
|
children?: ReactNode;
|
|
16
21
|
};
|
|
17
|
-
declare const Badge: ({ content, size, color, anchorOrigin, anchorOverlap, className, children }: BadgeProps) => import("react").JSX.Element;
|
|
18
|
-
export { type AnchorOrigin, type AnchorOverlap, Badge, type BadgeColor, type BadgeProps };
|
|
22
|
+
declare const Badge: ({ content, size, color, anchorOrigin, anchorOffset, anchorOverlap, className, children }: BadgeProps) => import("react").JSX.Element;
|
|
23
|
+
export { type AnchorOffset, type AnchorOrigin, type AnchorOverlap, Badge, type BadgeColor, type BadgeProps };
|
|
@@ -3,6 +3,10 @@ type AnchorOrigin = {
|
|
|
3
3
|
vertical: "top" | "bottom";
|
|
4
4
|
horizontal: "left" | "right";
|
|
5
5
|
};
|
|
6
|
+
type AnchorOffset = {
|
|
7
|
+
vertical: number;
|
|
8
|
+
horizontal: number;
|
|
9
|
+
};
|
|
6
10
|
type AnchorOverlap = "rectangular" | "circular";
|
|
7
11
|
type BadgeColor = "primary" | "secondary" | "accent" | "danger" | "info" | `#${string}`;
|
|
8
12
|
type BadgeProps = {
|
|
@@ -10,9 +14,10 @@ type BadgeProps = {
|
|
|
10
14
|
size?: number;
|
|
11
15
|
color?: BadgeColor;
|
|
12
16
|
anchorOrigin?: AnchorOrigin;
|
|
17
|
+
anchorOffset?: AnchorOffset;
|
|
13
18
|
anchorOverlap?: AnchorOverlap;
|
|
14
19
|
className?: string;
|
|
15
20
|
children?: ReactNode;
|
|
16
21
|
};
|
|
17
|
-
declare const Badge: ({ content, size, color, anchorOrigin, anchorOverlap, className, children }: BadgeProps) => import("react").JSX.Element;
|
|
18
|
-
export { type AnchorOrigin, type AnchorOverlap, Badge, type BadgeColor, type BadgeProps };
|
|
22
|
+
declare const Badge: ({ content, size, color, anchorOrigin, anchorOffset, anchorOverlap, className, children }: BadgeProps) => import("react").JSX.Element;
|
|
23
|
+
export { type AnchorOffset, type AnchorOrigin, type AnchorOverlap, Badge, type BadgeColor, type BadgeProps };
|
|
@@ -6,19 +6,30 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
const Badge = ({ content, size = 20, color = "primary", anchorOrigin = {
|
|
7
7
|
vertical: "top",
|
|
8
8
|
horizontal: "right"
|
|
9
|
+
}, anchorOffset = {
|
|
10
|
+
vertical: 0,
|
|
11
|
+
horizontal: 0
|
|
9
12
|
}, anchorOverlap = "rectangular", className, children }) => {
|
|
13
|
+
if (!Number.isFinite(anchorOffset.vertical) || !Number.isFinite(anchorOffset.horizontal)) throw new TypeError("Badge anchorOffset values must be finite numbers.");
|
|
10
14
|
const resolvedSize = Math.max(size, 16);
|
|
11
15
|
const isHex = isHexColor(color);
|
|
12
16
|
const isDark = isHex ? isDarkColor(color) : false;
|
|
13
|
-
const
|
|
17
|
+
const textContent = typeof content === "string" || typeof content === "number" ? String(content).trim() : null;
|
|
18
|
+
const isSingleCharacter = textContent != null && Array.from(textContent).length === 1;
|
|
19
|
+
const classes = cn("puzzle-badge", children != null && [
|
|
20
|
+
anchorOrigin.vertical,
|
|
21
|
+
anchorOrigin.horizontal,
|
|
22
|
+
anchorOverlap
|
|
23
|
+
], children == null && "puzzle-badge-standalone", !isHex && `puzzle-badge-${color}`, className);
|
|
14
24
|
return /* @__PURE__ */ jsxs("div", {
|
|
15
25
|
className: classes,
|
|
16
26
|
children: [children, /* @__PURE__ */ jsx("span", {
|
|
17
|
-
className: "puzzle-badge-indicator",
|
|
27
|
+
className: cn("puzzle-badge-indicator", isSingleCharacter && "puzzle-badge-indicator--single"),
|
|
18
28
|
style: {
|
|
19
29
|
fontSize: `clamp(0.7rem, calc(${resolvedSize}px - 1em), 4rem)`,
|
|
20
30
|
minHeight: `${resolvedSize}px`,
|
|
21
31
|
minWidth: `${resolvedSize}px`,
|
|
32
|
+
translate: children != null ? `${anchorOffset.horizontal * (anchorOrigin.horizontal === "left" ? 1 : -1)}px ${anchorOffset.vertical * (anchorOrigin.vertical === "top" ? 1 : -1)}px` : void 0,
|
|
22
33
|
backgroundColor: isHex ? color : void 0,
|
|
23
34
|
color: isHex ? isDark ? "var(--puzzle-color-light-foreground)" : "var(--puzzle-color-dark-foreground)" : void 0
|
|
24
35
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/data-display/badge/index.tsx"],"sourcesContent":["import { cn, isDarkColor, isHexColor } from \"@puzzle-ui/core\";\nimport { type ReactNode } from \"react\";\nimport \"./badge.css\";\n\ntype AnchorOrigin = {\n vertical: \"top\" | \"bottom\";\n horizontal: \"left\" | \"right\";\n};\n\ntype AnchorOverlap = \"rectangular\" | \"circular\";\ntype BadgeColor =\n | \"primary\"\n | \"secondary\"\n | \"accent\"\n | \"danger\"\n | \"info\"\n | `#${string}`;\n\ntype BadgeProps = {\n content: ReactNode;\n size?: number;\n color?: BadgeColor;\n anchorOrigin?: AnchorOrigin;\n anchorOverlap?: AnchorOverlap;\n className?: string;\n children?: ReactNode;\n};\n\nconst Badge = ({\n content,\n size = 20,\n color = \"primary\",\n anchorOrigin = { vertical: \"top\", horizontal: \"right\" },\n anchorOverlap = \"rectangular\",\n className,\n children,\n}: BadgeProps) => {\n const resolvedSize = Math.max(size, 16);\n const isHex = isHexColor(color);\n const isDark = isHex ? isDarkColor(color) : false;\n\n const classes = cn(\n \"puzzle-badge\",\n anchorOrigin.vertical,\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/data-display/badge/index.tsx"],"sourcesContent":["import { cn, isDarkColor, isHexColor } from \"@puzzle-ui/core\";\nimport { type ReactNode } from \"react\";\nimport \"./badge.css\";\n\ntype AnchorOrigin = {\n vertical: \"top\" | \"bottom\";\n horizontal: \"left\" | \"right\";\n};\n\ntype AnchorOffset = {\n vertical: number;\n horizontal: number;\n};\n\ntype AnchorOverlap = \"rectangular\" | \"circular\";\ntype BadgeColor =\n | \"primary\"\n | \"secondary\"\n | \"accent\"\n | \"danger\"\n | \"info\"\n | `#${string}`;\n\ntype BadgeProps = {\n content: ReactNode;\n size?: number;\n color?: BadgeColor;\n anchorOrigin?: AnchorOrigin;\n anchorOffset?: AnchorOffset;\n anchorOverlap?: AnchorOverlap;\n className?: string;\n children?: ReactNode;\n};\n\nconst Badge = ({\n content,\n size = 20,\n color = \"primary\",\n anchorOrigin = { vertical: \"top\", horizontal: \"right\" },\n anchorOffset = { vertical: 0, horizontal: 0 },\n anchorOverlap = \"rectangular\",\n className,\n children,\n}: BadgeProps) => {\n if (!Number.isFinite(anchorOffset.vertical) || !Number.isFinite(anchorOffset.horizontal)) {\n throw new TypeError(\"Badge anchorOffset values must be finite numbers.\");\n }\n\n const resolvedSize = Math.max(size, 16);\n const isHex = isHexColor(color);\n const isDark = isHex ? isDarkColor(color) : false;\n\n const textContent =\n typeof content === \"string\" || typeof content === \"number\"\n ? String(content).trim()\n : null;\n const isSingleCharacter =\n textContent != null && Array.from(textContent).length === 1;\n\n const classes = cn(\n \"puzzle-badge\",\n children != null && [\n anchorOrigin.vertical,\n anchorOrigin.horizontal,\n anchorOverlap,\n ],\n children == null && \"puzzle-badge-standalone\",\n !isHex && `puzzle-badge-${color}`,\n className,\n );\n\n return (\n <div className={classes}>\n {children}\n <span\n className={cn(\n \"puzzle-badge-indicator\",\n isSingleCharacter && \"puzzle-badge-indicator--single\",\n )}\n style={{\n fontSize: `clamp(0.7rem, calc(${resolvedSize}px - 1em), 4rem)`,\n minHeight: `${resolvedSize}px`,\n minWidth: `${resolvedSize}px`,\n translate: children != null\n ? `${anchorOffset.horizontal * (anchorOrigin.horizontal === \"left\" ? 1 : -1)}px ${anchorOffset.vertical * (anchorOrigin.vertical === \"top\" ? 1 : -1)}px`\n : undefined,\n backgroundColor: isHex ? color : undefined,\n color: isHex\n ? isDark\n ? \"var(--puzzle-color-light-foreground)\"\n : \"var(--puzzle-color-dark-foreground)\"\n : undefined,\n }}\n >\n {content}\n </span>\n </div>\n );\n};\n\nexport {\n Badge,\n type BadgeProps,\n type BadgeColor,\n type AnchorOrigin,\n type AnchorOffset,\n type AnchorOverlap,\n};\n"],"mappings":";;;;;AAkCA,MAAM,SAAS,EACb,SACA,OAAO,IACP,QAAQ,WACR,eAAe;CAAE,UAAU;CAAO,YAAY;AAAQ,GACtD,eAAe;CAAE,UAAU;CAAG,YAAY;AAAE,GAC5C,gBAAgB,eAChB,WACA,eACgB;CAChB,IAAI,CAAC,OAAO,SAAS,aAAa,QAAQ,KAAK,CAAC,OAAO,SAAS,aAAa,UAAU,GACrF,MAAM,IAAI,UAAU,mDAAmD;CAGzE,MAAM,eAAe,KAAK,IAAI,MAAM,EAAE;CACtC,MAAM,QAAQ,WAAW,KAAK;CAC9B,MAAM,SAAS,QAAQ,YAAY,KAAK,IAAI;CAE5C,MAAM,cACJ,OAAO,YAAY,YAAY,OAAO,YAAY,WAC9C,OAAO,OAAO,CAAC,CAAC,KAAK,IACrB;CACN,MAAM,oBACJ,eAAe,QAAQ,MAAM,KAAK,WAAW,CAAC,CAAC,WAAW;CAE5D,MAAM,UAAU,GACd,gBACA,YAAY,QAAQ;EAClB,aAAa;EACb,aAAa;EACb;CACF,GACA,YAAY,QAAQ,2BACpB,CAAC,SAAS,gBAAgB,SAC1B,SACF;CAEA,OACE,qBAAC,OAAD;EAAK,WAAW;EAAhB,UAAA,CACG,UACD,oBAAC,QAAD;GACE,WAAW,GACT,0BACA,qBAAqB,gCACvB;GACA,OAAO;IACL,UAAU,sBAAsB,aAAa;IAC7C,WAAW,GAAG,aAAa;IAC3B,UAAU,GAAG,aAAa;IAC1B,WAAW,YAAY,OACnB,GAAG,aAAa,cAAc,aAAa,eAAe,SAAS,IAAI,IAAI,KAAK,aAAa,YAAY,aAAa,aAAa,QAAQ,IAAI,IAAI,MACnJ,KAAA;IACJ,iBAAiB,QAAQ,QAAQ,KAAA;IACjC,OAAO,QACH,SACE,yCACA,wCACF,KAAA;GACN;GAEC,UAAA;EACG,CAAA,CACH;;AAET"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const require_rating_utils = require("./rating.utils.cjs");
|
|
3
|
+
;/* empty css */
|
|
4
|
+
let _puzzle_ui_core = require("@puzzle-ui/core");
|
|
5
|
+
let react = require("react");
|
|
6
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
let _puzzle_ui_icons = require("@puzzle-ui/icons");
|
|
8
|
+
// src/components/data-display/rating/index.tsx
|
|
9
|
+
const ICONS = {
|
|
10
|
+
full: "ph:star-fill",
|
|
11
|
+
half: "ph:star-half-fill",
|
|
12
|
+
empty: "ph:star"
|
|
13
|
+
};
|
|
14
|
+
const SIZE_MAP = {
|
|
15
|
+
sm: 16,
|
|
16
|
+
md: 20,
|
|
17
|
+
lg: 24
|
|
18
|
+
};
|
|
19
|
+
const Rating = ({ value, defaultValue = 0, onValueChange, max = 5, precision = .5, size = "md", readOnly = false, disabled = false, color = "var(--puzzle-color-warning, #FABC0A)", emptyColor = "var(--puzzle-color-border)", className, style, "aria-label": ariaLabel = "Rating", onKeyDown, ...props }) => {
|
|
20
|
+
if (!Number.isInteger(max) || max < 1 || max > 10) throw new Error("Rating max must be an integer between 1 and 10.");
|
|
21
|
+
const isControlled = value !== void 0;
|
|
22
|
+
const [internalValue, setInternalValue] = (0, react.useState)(() => require_rating_utils.normalizeRating(defaultValue, max, precision));
|
|
23
|
+
const currentValue = require_rating_utils.normalizeRating(isControlled ? value : internalValue, max, precision);
|
|
24
|
+
const commitValue = (nextValue) => {
|
|
25
|
+
if (disabled || readOnly) return;
|
|
26
|
+
const next = require_rating_utils.normalizeRating(nextValue, max, precision);
|
|
27
|
+
if (next === currentValue) return;
|
|
28
|
+
if (!isControlled) setInternalValue(next);
|
|
29
|
+
onValueChange?.(next);
|
|
30
|
+
};
|
|
31
|
+
const handleKeyDown = (event) => {
|
|
32
|
+
onKeyDown?.(event);
|
|
33
|
+
if (event.defaultPrevented || disabled || readOnly) return;
|
|
34
|
+
const nextValue = require_rating_utils.getNextRating(currentValue, event.key, max, precision);
|
|
35
|
+
if (nextValue === void 0) return;
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
commitValue(nextValue);
|
|
38
|
+
};
|
|
39
|
+
const classes = (0, _puzzle_ui_core.cn)("puzzle-rating", disabled && "puzzle-rating-disabled", readOnly && "puzzle-rating-readonly", className);
|
|
40
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41
|
+
...props,
|
|
42
|
+
className: classes,
|
|
43
|
+
style: {
|
|
44
|
+
...style,
|
|
45
|
+
"--puzzle-rating-color": color,
|
|
46
|
+
"--puzzle-rating-empty-color": emptyColor
|
|
47
|
+
},
|
|
48
|
+
role: readOnly ? "img" : "slider",
|
|
49
|
+
tabIndex: disabled || readOnly ? void 0 : 0,
|
|
50
|
+
"aria-label": readOnly ? `${ariaLabel}: ${currentValue} out of ${max} stars` : ariaLabel,
|
|
51
|
+
"aria-valuemin": readOnly ? void 0 : 0,
|
|
52
|
+
"aria-valuemax": readOnly ? void 0 : max,
|
|
53
|
+
"aria-valuenow": readOnly ? void 0 : currentValue,
|
|
54
|
+
"aria-valuetext": readOnly ? void 0 : `${currentValue} out of ${max} stars`,
|
|
55
|
+
"aria-disabled": disabled || void 0,
|
|
56
|
+
"aria-readonly": readOnly || void 0,
|
|
57
|
+
onKeyDown: handleKeyDown,
|
|
58
|
+
"data-size": size,
|
|
59
|
+
"data-disabled": disabled || void 0,
|
|
60
|
+
"data-readonly": readOnly || void 0,
|
|
61
|
+
children: Array.from({ length: max }, (_, index) => {
|
|
62
|
+
const state = require_rating_utils.getRatingStarState(currentValue, index);
|
|
63
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
64
|
+
className: "puzzle-rating__star",
|
|
65
|
+
"data-state": state,
|
|
66
|
+
"aria-hidden": "true",
|
|
67
|
+
onClick: (event) => {
|
|
68
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
69
|
+
const isHalf = precision === .5 && event.clientX < rect.left + rect.width / 2;
|
|
70
|
+
commitValue(index + (isHalf ? .5 : 1));
|
|
71
|
+
},
|
|
72
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_puzzle_ui_icons.Icon, {
|
|
73
|
+
name: ICONS[state],
|
|
74
|
+
size: SIZE_MAP[size],
|
|
75
|
+
"aria-hidden": "true",
|
|
76
|
+
focusable: "false"
|
|
77
|
+
})
|
|
78
|
+
}, index);
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
exports.Rating = Rating;
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["useState","normalizeRating","getNextRating","cn","getRatingStarState","Icon"],"sources":["../../../../src/components/data-display/rating/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, type CSSProperties, type KeyboardEvent } from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\nimport { Icon } from \"@puzzle-ui/icons\";\n\nimport type { RatingProps, RatingSize } from \"./rating.types\";\n\nimport {\n getNextRating,\n getRatingStarState,\n normalizeRating,\n} from \"./rating.utils\";\n\nimport \"./rating.css\";\n\nconst ICONS = {\n full: \"ph:star-fill\",\n half: \"ph:star-half-fill\",\n empty: \"ph:star\",\n} as const;\n\nconst SIZE_MAP = {\n sm: 16,\n md: 20,\n lg: 24,\n} as const;\n\nconst Rating = ({\n value,\n defaultValue = 0,\n onValueChange,\n max = 5,\n precision = 0.5,\n size = \"md\",\n readOnly = false,\n disabled = false,\n color = \"var(--puzzle-color-warning, #FABC0A)\",\n emptyColor = \"var(--puzzle-color-border)\",\n className,\n style,\n \"aria-label\": ariaLabel = \"Rating\",\n onKeyDown,\n ...props\n}: RatingProps) => {\n if (!Number.isInteger(max) || max < 1 || max > 10) {\n throw new Error(\"Rating max must be an integer between 1 and 10.\");\n }\n\n const isControlled = value !== undefined;\n\n const [internalValue, setInternalValue] = useState(() =>\n normalizeRating(defaultValue, max, precision),\n );\n\n const currentValue = normalizeRating(\n isControlled ? value : internalValue,\n max,\n precision,\n );\n\n const commitValue = (nextValue: number) => {\n if (disabled || readOnly) {\n return;\n }\n\n const next = normalizeRating(nextValue, max, precision);\n\n if (next === currentValue) {\n return;\n }\n\n if (!isControlled) {\n setInternalValue(next);\n }\n\n onValueChange?.(next);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented || disabled || readOnly) {\n return;\n }\n\n const nextValue = getNextRating(currentValue, event.key, max, precision);\n\n if (nextValue === undefined) {\n return;\n }\n\n event.preventDefault();\n commitValue(nextValue);\n };\n\n const classes = cn(\n \"puzzle-rating\",\n disabled && \"puzzle-rating-disabled\",\n readOnly && \"puzzle-rating-readonly\",\n className,\n );\n\n return (\n <div\n {...props}\n className={classes}\n style={\n {\n ...style,\n \"--puzzle-rating-color\": color,\n \"--puzzle-rating-empty-color\": emptyColor,\n } as CSSProperties\n }\n role={readOnly ? \"img\" : \"slider\"}\n tabIndex={disabled || readOnly ? undefined : 0}\n aria-label={\n readOnly\n ? `${ariaLabel}: ${currentValue} out of ${max} stars`\n : ariaLabel\n }\n aria-valuemin={readOnly ? undefined : 0}\n aria-valuemax={readOnly ? undefined : max}\n aria-valuenow={readOnly ? undefined : currentValue}\n aria-valuetext={\n readOnly ? undefined : `${currentValue} out of ${max} stars`\n }\n aria-disabled={disabled || undefined}\n aria-readonly={readOnly || undefined}\n onKeyDown={handleKeyDown}\n data-size={size}\n data-disabled={disabled || undefined}\n data-readonly={readOnly || undefined}\n >\n {Array.from({ length: max }, (_, index) => {\n const state = getRatingStarState(currentValue, index);\n\n return (\n <span\n key={index}\n className=\"puzzle-rating__star\"\n data-state={state}\n aria-hidden=\"true\"\n onClick={(event) => {\n const rect = event.currentTarget.getBoundingClientRect();\n\n const isHalf =\n precision === 0.5 && event.clientX < rect.left + rect.width / 2;\n\n commitValue(index + (isHalf ? 0.5 : 1));\n }}\n >\n <Icon\n name={ICONS[state]}\n size={SIZE_MAP[size]}\n aria-hidden=\"true\"\n focusable=\"false\"\n />\n </span>\n );\n })}\n </div>\n );\n};\n\nexport { Rating, type RatingProps, type RatingSize };\n"],"mappings":";;;;;;;;AAiBA,MAAM,QAAQ;CACZ,MAAM;CACN,MAAM;CACN,OAAO;AACT;AAEA,MAAM,WAAW;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,UAAU,EACd,OACA,eAAe,GACf,eACA,MAAM,GACN,YAAY,IACZ,OAAO,MACP,WAAW,OACX,WAAW,OACX,QAAQ,wCACR,aAAa,8BACb,WACA,OACA,cAAc,YAAY,UAC1B,WACA,GAAG,YACc;CACjB,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAM,IAC7C,MAAM,IAAI,MAAM,iDAAiD;CAGnE,MAAM,eAAe,UAAU,KAAA;CAE/B,MAAM,CAAC,eAAe,qBAAA,GAAoBA,MAAAA,SAAAA,OACxCC,qBAAAA,gBAAgB,cAAc,KAAK,SAAS,CAC9C;CAEA,MAAM,eAAeA,qBAAAA,gBACnB,eAAe,QAAQ,eACvB,KACA,SACF;CAEA,MAAM,eAAe,cAAsB;EACzC,IAAI,YAAY,UACd;EAGF,MAAM,OAAOA,qBAAAA,gBAAgB,WAAW,KAAK,SAAS;EAEtD,IAAI,SAAS,cACX;EAGF,IAAI,CAAC,cACH,iBAAiB,IAAI;EAGvB,gBAAgB,IAAI;CACtB;CAEA,MAAM,iBAAiB,UAAyC;EAC9D,YAAY,KAAK;EAEjB,IAAI,MAAM,oBAAoB,YAAY,UACxC;EAGF,MAAM,YAAYC,qBAAAA,cAAc,cAAc,MAAM,KAAK,KAAK,SAAS;EAEvE,IAAI,cAAc,KAAA,GAChB;EAGF,MAAM,eAAe;EACrB,YAAY,SAAS;CACvB;CAEA,MAAM,WAAA,GAAUC,gBAAAA,GAAAA,CACd,iBACA,YAAY,0BACZ,YAAY,0BACZ,SACF;CAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EACE,GAAI;EACJ,WAAW;EACX,OACE;GACE,GAAG;GACH,yBAAyB;GACzB,+BAA+B;EACjC;EAEF,MAAM,WAAW,QAAQ;EACzB,UAAU,YAAY,WAAW,KAAA,IAAY;EAC7C,cACE,WACI,GAAG,UAAU,IAAI,aAAa,UAAU,IAAI,UAC5C;EAEN,iBAAe,WAAW,KAAA,IAAY;EACtC,iBAAe,WAAW,KAAA,IAAY;EACtC,iBAAe,WAAW,KAAA,IAAY;EACtC,kBACE,WAAW,KAAA,IAAY,GAAG,aAAa,UAAU,IAAI;EAEvD,iBAAe,YAAY,KAAA;EAC3B,iBAAe,YAAY,KAAA;EAC3B,WAAW;EACX,aAAW;EACX,iBAAe,YAAY,KAAA;EAC3B,iBAAe,YAAY,KAAA;EAE1B,UAAA,MAAM,KAAK,EAAE,QAAQ,IAAI,IAAI,GAAG,UAAU;GACzC,MAAM,QAAQC,qBAAAA,mBAAmB,cAAc,KAAK;GAEpD,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;IAEE,WAAU;IACV,cAAY;IACZ,eAAY;IACZ,UAAU,UAAU;KAClB,MAAM,OAAO,MAAM,cAAc,sBAAsB;KAEvD,MAAM,SACJ,cAAc,MAAO,MAAM,UAAU,KAAK,OAAO,KAAK,QAAQ;KAEhE,YAAY,SAAS,SAAS,KAAM,EAAE;IACxC;IAEA,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,iBAAAA,MAAD;KACE,MAAM,MAAM;KACZ,MAAM,SAAS;KACf,eAAY;KACZ,WAAU;IACX,CAAA;GACG,GAnBC,KAmBD;EAEV,CAAC;CACE,CAAA;AAET"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { RatingProps, RatingSize } from "./rating.types.cjs";
|
|
2
|
+
declare const Rating: ({ value, defaultValue, onValueChange, max, precision, size, readOnly, disabled, color, emptyColor, className, style, "aria-label": ariaLabel, onKeyDown, ...props }: RatingProps) => import("react").JSX.Element;
|
|
3
|
+
export { Rating, type RatingProps, type RatingSize };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { RatingProps, RatingSize } from "./rating.types.js";
|
|
2
|
+
declare const Rating: ({ value, defaultValue, onValueChange, max, precision, size, readOnly, disabled, color, emptyColor, className, style, "aria-label": ariaLabel, onKeyDown, ...props }: RatingProps) => import("react").JSX.Element;
|
|
3
|
+
export { Rating, type RatingProps, type RatingSize };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getNextRating, getRatingStarState, normalizeRating } from "./rating.utils.js";
|
|
3
|
+
import "./rating.css";
|
|
4
|
+
import { cn } from "@puzzle-ui/core";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { Icon } from "@puzzle-ui/icons";
|
|
8
|
+
// src/components/data-display/rating/index.tsx
|
|
9
|
+
const ICONS = {
|
|
10
|
+
full: "ph:star-fill",
|
|
11
|
+
half: "ph:star-half-fill",
|
|
12
|
+
empty: "ph:star"
|
|
13
|
+
};
|
|
14
|
+
const SIZE_MAP = {
|
|
15
|
+
sm: 16,
|
|
16
|
+
md: 20,
|
|
17
|
+
lg: 24
|
|
18
|
+
};
|
|
19
|
+
const Rating = ({ value, defaultValue = 0, onValueChange, max = 5, precision = .5, size = "md", readOnly = false, disabled = false, color = "var(--puzzle-color-warning, #FABC0A)", emptyColor = "var(--puzzle-color-border)", className, style, "aria-label": ariaLabel = "Rating", onKeyDown, ...props }) => {
|
|
20
|
+
if (!Number.isInteger(max) || max < 1 || max > 10) throw new Error("Rating max must be an integer between 1 and 10.");
|
|
21
|
+
const isControlled = value !== void 0;
|
|
22
|
+
const [internalValue, setInternalValue] = useState(() => normalizeRating(defaultValue, max, precision));
|
|
23
|
+
const currentValue = normalizeRating(isControlled ? value : internalValue, max, precision);
|
|
24
|
+
const commitValue = (nextValue) => {
|
|
25
|
+
if (disabled || readOnly) return;
|
|
26
|
+
const next = normalizeRating(nextValue, max, precision);
|
|
27
|
+
if (next === currentValue) return;
|
|
28
|
+
if (!isControlled) setInternalValue(next);
|
|
29
|
+
onValueChange?.(next);
|
|
30
|
+
};
|
|
31
|
+
const handleKeyDown = (event) => {
|
|
32
|
+
onKeyDown?.(event);
|
|
33
|
+
if (event.defaultPrevented || disabled || readOnly) return;
|
|
34
|
+
const nextValue = getNextRating(currentValue, event.key, max, precision);
|
|
35
|
+
if (nextValue === void 0) return;
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
commitValue(nextValue);
|
|
38
|
+
};
|
|
39
|
+
const classes = cn("puzzle-rating", disabled && "puzzle-rating-disabled", readOnly && "puzzle-rating-readonly", className);
|
|
40
|
+
return /* @__PURE__ */ jsx("div", {
|
|
41
|
+
...props,
|
|
42
|
+
className: classes,
|
|
43
|
+
style: {
|
|
44
|
+
...style,
|
|
45
|
+
"--puzzle-rating-color": color,
|
|
46
|
+
"--puzzle-rating-empty-color": emptyColor
|
|
47
|
+
},
|
|
48
|
+
role: readOnly ? "img" : "slider",
|
|
49
|
+
tabIndex: disabled || readOnly ? void 0 : 0,
|
|
50
|
+
"aria-label": readOnly ? `${ariaLabel}: ${currentValue} out of ${max} stars` : ariaLabel,
|
|
51
|
+
"aria-valuemin": readOnly ? void 0 : 0,
|
|
52
|
+
"aria-valuemax": readOnly ? void 0 : max,
|
|
53
|
+
"aria-valuenow": readOnly ? void 0 : currentValue,
|
|
54
|
+
"aria-valuetext": readOnly ? void 0 : `${currentValue} out of ${max} stars`,
|
|
55
|
+
"aria-disabled": disabled || void 0,
|
|
56
|
+
"aria-readonly": readOnly || void 0,
|
|
57
|
+
onKeyDown: handleKeyDown,
|
|
58
|
+
"data-size": size,
|
|
59
|
+
"data-disabled": disabled || void 0,
|
|
60
|
+
"data-readonly": readOnly || void 0,
|
|
61
|
+
children: Array.from({ length: max }, (_, index) => {
|
|
62
|
+
const state = getRatingStarState(currentValue, index);
|
|
63
|
+
return /* @__PURE__ */ jsx("span", {
|
|
64
|
+
className: "puzzle-rating__star",
|
|
65
|
+
"data-state": state,
|
|
66
|
+
"aria-hidden": "true",
|
|
67
|
+
onClick: (event) => {
|
|
68
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
69
|
+
const isHalf = precision === .5 && event.clientX < rect.left + rect.width / 2;
|
|
70
|
+
commitValue(index + (isHalf ? .5 : 1));
|
|
71
|
+
},
|
|
72
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
73
|
+
name: ICONS[state],
|
|
74
|
+
size: SIZE_MAP[size],
|
|
75
|
+
"aria-hidden": "true",
|
|
76
|
+
focusable: "false"
|
|
77
|
+
})
|
|
78
|
+
}, index);
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
export { Rating };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=index.js.map
|