@puzzle-ui/ui 0.5.0 → 0.6.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/README.md CHANGED
@@ -1,98 +1,82 @@
1
- # Getting Started
1
+ # @puzzle-ui/ui
2
2
 
3
- Install Puzzle in your React app, build your first interface, and customize the theme.
3
+ Composable, token-driven React components for building React interfaces with Puzzle.
4
4
 
5
- > \[!WARNING\] **Puzzle is not ready for production use.**
6
- >
7
- > This project is under active development. APIs, component props,
8
- > package exports, styling, and internal implementation may change
9
- > without notice. Components may be incomplete, and testing,
10
- > accessibility, documentation, and framework compatibility are not yet
11
- > guaranteed. Use it for experimentation and evaluation only---not for
12
- > production applications.
5
+ **Documentation:** [https://puzzle-ui.com/docs/ui](https://puzzle-ui.com/docs/ui)
13
6
 
14
- Puzzle is a TypeScript and React UI component library built around reusable components and shared design tokens. Its components are composable and router-independent, with styling supplied by `"@puzzle-ui/theme`. The framework is setup to be compatible with `Next.js`, `Tanstack Start` and `react-router`.
7
+ Component API maturity is listed on each component's documentation page.
8
+ Paper, Skeleton, Label, Background, Breadcrumbs, Sidebar, and Backdrop are
9
+ Experimental because their current validation evidence is limited. Review
10
+ documented accessibility and framework details when integrating components.
15
11
 
16
- **Puzzle is under active development and is not ready for production use.** APIs, props, exports, and styling may change without notice. Accessibility and framework compatibility are still being tested. Use the project for experimentation and evaluation.
12
+ `@puzzle-ui/ui` provides composable, router-independent React components:
13
+ actions, data display, editors, forms, layout, navigation, overlays,
14
+ typography, and utilities. Components use semantic HTML and native browser
15
+ behavior first, and all styling comes from the CSS custom properties supplied
16
+ by [`@puzzle-ui/theme`](https://puzzle-ui.com/docs/theme), so one `Theme`
17
+ provider styles your whole application.
17
18
 
18
- ## Prerequisites
19
-
20
- - A package manager: npm, Bun, pnpm, or Yarn.
21
- - An existing React application with a bundler that supports CSS imports, such as Vite.
22
- - Familiarity with React and TypeScript. The UI and theme packages require React and React DOM 19 or later within the supported React 19 range.
23
-
24
- ## Set up a new project
25
-
26
- Simple run our @puzzle-ui/create project template to get started.
27
-
28
- npm:
19
+ ## Install
29
20
 
30
21
  ```bash
31
- npx @puzzle-ui/create
22
+ npm install @puzzle-ui/ui @puzzle-ui/theme
23
+ # or
24
+ bun add @puzzle-ui/ui @puzzle-ui/theme
25
+ # or
26
+ pnpm add @puzzle-ui/ui @puzzle-ui/theme
27
+ # or
28
+ yarn add @puzzle-ui/ui @puzzle-ui/theme
32
29
  ```
33
30
 
34
- bun:
35
-
36
- ```bash
37
- bunx @puzzle-ui/create
38
- ```
39
-
40
- Puzzle can set up a new project for you with the following framework options:
41
-
42
- - Basic React app
43
- - Tanstack start
44
- - Next.js
31
+ React and React DOM 19 are peer dependencies and should already be installed
32
+ in your application.
45
33
 
46
- Furthermore you can choose to install tailwindcss or not.
47
- It directly installs all dependencies and sets up the project for you.
34
+ To start a new project with Puzzle preconfigured, run
35
+ [`npx @puzzle-ui/create`](https://puzzle-ui.com/docs/create).
48
36
 
49
- ## Set up in an existing project:
37
+ ## Usage
50
38
 
51
- Install the UI library and theme package in your application's directory. Choose your package manager below:
52
-
53
- npm:
54
-
55
- ```bash
56
- npm install @puzzle-ui/ui --save
57
- ```
58
-
59
- bun:
60
-
61
- ```bash
62
- bun add @puzzle-ui/create
63
- ```
39
+ Wrap your application in `Theme` and import components from `@puzzle-ui/ui`:
64
40
 
65
- pnpm:
41
+ ```tsx
42
+ import { Theme } from "@puzzle-ui/theme";
43
+ import { Button, Stack, Text } from "@puzzle-ui/ui";
66
44
 
67
- ```bash
68
- pnpm add @puzzle-ui/ui
45
+ export const App = () => (
46
+ <Theme>
47
+ <Stack direction="col" gap="sm">
48
+ <Text>Build your interface with Puzzle.</Text>
49
+ <Button>Get started</Button>
50
+ </Stack>
51
+ </Theme>
52
+ );
69
53
  ```
70
54
 
71
- yarn:
55
+ ## Component categories
72
56
 
73
- ```bash
74
- yarn add @puzzle-ui/ui
75
- ```
57
+ | Category | Components |
58
+ | ------------ | ------------------------------------------------------------------------------------------------------------- |
59
+ | Actions | Button, ButtonGroup, ToggleGroup |
60
+ | Data display | Alert, Avatar, Badge, Card, EmptyState, Image, Paper, Progress, Rating, Skeleton |
61
+ | Editors | TextEditor, TextEditorToolbar, TextRenderer |
62
+ | Forms | Autocomplete, Checkbox, ColorPicker, DatePicker, FileUpload, FormField, inputs, Radio, Select, Slider, Switch |
63
+ | Layout | AppBar, AspectRatio, Container, Grid, GridItem, PageLayout, ResizablePanels, ScrollArea, Section, Separator, Sidebar, Stack |
64
+ | Navigation | Accordion, Breadcrumbs, Carousel, Link, Pagination, Tabs, TreeView |
65
+ | Overlays | Command, ContextMenu, Dialog, Drawer, DropdownMenu, Notification, Popover, Tooltip |
66
+ | Typography | Heading, Text |
67
+ | Utilities | Portal, Preview, ScrollLock, Transition |
76
68
 
77
- These commands install published packages; they do not clone the repository or build its workspaces. Puzzle does not require Bun in your application. React and React DOM are peer dependencies and should already be installed in your app.
69
+ Browse every component with live examples, props, and accessibility guidance
70
+ in the [component documentation](https://puzzle-ui.com/docs/ui).
78
71
 
79
- ## Your first interface
72
+ ## Framework integration
80
73
 
81
- Import components from `"@puzzle-ui/ui` and wrap your application in `Theme` from `"@puzzle-ui/theme`:
74
+ Components do not depend on a router or framework. Use the `components`
75
+ prop of `Theme` to provide your framework's link and image components; see
76
+ [Component Overrides](https://puzzle-ui.com/docs/theme/components).
82
77
 
83
- ```tsx
84
- import { Theme } from "@puzzle-ui/theme";
85
- import { Button } from "@puzzle-ui/ui";
78
+ ## Related packages
86
79
 
87
- export const App = () => (
88
- <Theme>
89
- <main>
90
- <h1>Hello, Puzzle</h1>
91
- <p>Build your interface with reusable components and shared tokens.</p>
92
- <Button onClick={() => window.alert("Welcome to Puzzle!")}>
93
- Get started
94
- </Button>
95
- </main>
96
- </Theme>
97
- );
98
- ```
80
+ - [`@puzzle-ui/theme`](https://puzzle-ui.com/docs/theme) — design tokens and the `Theme` provider.
81
+ - [`@puzzle-ui/icons`](https://puzzle-ui.com/docs/icons) — icon components.
82
+ - [`@puzzle-ui/hooks`](https://puzzle-ui.com/docs/hooks) — reusable React hooks.
@@ -21,7 +21,7 @@ const Badge = ({ content, size = 20, color = "primary", anchorOrigin = {
21
21
  anchorOrigin.horizontal,
22
22
  anchorOverlap
23
23
  ], children == null && "puzzle-badge-standalone", !isHex && `puzzle-badge-${color}`, className);
24
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
24
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(children == null ? "span" : "div", {
25
25
  className: classes,
26
26
  children: [children, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
27
27
  className: (0, _puzzle_ui_core.cn)("puzzle-badge-indicator", isSingleCharacter && "puzzle-badge-indicator--single"),
@@ -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 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"}
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 const Component = children == null ? \"span\" : \"div\";\n\n return (\n <Component 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 </Component>\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;CAIA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAHgB,YAAY,OAAO,SAAS,OAG5C;EAAW,WAAW;EAAtB,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,CACG;;AAEf"}
@@ -21,7 +21,7 @@ const Badge = ({ content, size = 20, color = "primary", anchorOrigin = {
21
21
  anchorOrigin.horizontal,
22
22
  anchorOverlap
23
23
  ], children == null && "puzzle-badge-standalone", !isHex && `puzzle-badge-${color}`, className);
24
- return /* @__PURE__ */ jsxs("div", {
24
+ return /* @__PURE__ */ jsxs(children == null ? "span" : "div", {
25
25
  className: classes,
26
26
  children: [children, /* @__PURE__ */ jsx("span", {
27
27
  className: cn("puzzle-badge-indicator", isSingleCharacter && "puzzle-badge-indicator--single"),
@@ -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 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"}
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 const Component = children == null ? \"span\" : \"div\";\n\n return (\n <Component 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 </Component>\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;CAIA,OACE,qBAHgB,YAAY,OAAO,SAAS,OAG5C;EAAW,WAAW;EAAtB,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,CACG;;AAEf"}
@@ -0,0 +1,63 @@
1
+ .puzzle-grid {
2
+ grid-template-columns: var(--puzzle-grid-columns-mobile);
3
+ grid-template-rows: var(--puzzle-grid-rows-mobile);
4
+ row-gap: var(--puzzle-grid-row-gap-mobile);
5
+ column-gap: var(--puzzle-grid-column-gap-mobile);
6
+ justify-items: var(--puzzle-grid-align-h-mobile);
7
+ align-items: var(--puzzle-grid-align-v-mobile);
8
+ grid-auto-flow: var(--puzzle-grid-auto-flow-mobile);
9
+ min-width: 0;
10
+ display: grid;
11
+ }
12
+
13
+ .puzzle-grid > * {
14
+ min-width: 0;
15
+ }
16
+
17
+ .puzzle-grid-item {
18
+ grid-column: var(--puzzle-grid-item-column-start-mobile) / var(--puzzle-grid-item-column-end-mobile);
19
+ grid-row-end: var(--puzzle-grid-item-row-span-mobile);
20
+ grid-row-start: var(--puzzle-grid-item-row-start-mobile);
21
+ justify-self: var(--puzzle-grid-item-align-h-mobile);
22
+ align-self: var(--puzzle-grid-item-align-v-mobile);
23
+ }
24
+
25
+ @media (width >= 768px) {
26
+ .puzzle-grid {
27
+ grid-template-columns: var(--puzzle-grid-columns-tablet);
28
+ grid-template-rows: var(--puzzle-grid-rows-tablet);
29
+ row-gap: var(--puzzle-grid-row-gap-tablet);
30
+ column-gap: var(--puzzle-grid-column-gap-tablet);
31
+ justify-items: var(--puzzle-grid-align-h-tablet);
32
+ align-items: var(--puzzle-grid-align-v-tablet);
33
+ grid-auto-flow: var(--puzzle-grid-auto-flow-tablet);
34
+ }
35
+
36
+ .puzzle-grid-item {
37
+ grid-column: var(--puzzle-grid-item-column-start-tablet) / var(--puzzle-grid-item-column-end-tablet);
38
+ grid-row-end: var(--puzzle-grid-item-row-span-tablet);
39
+ grid-row-start: var(--puzzle-grid-item-row-start-tablet);
40
+ justify-self: var(--puzzle-grid-item-align-h-tablet);
41
+ align-self: var(--puzzle-grid-item-align-v-tablet);
42
+ }
43
+ }
44
+
45
+ @media (width >= 1024px) {
46
+ .puzzle-grid {
47
+ grid-template-columns: var(--puzzle-grid-columns-desktop);
48
+ grid-template-rows: var(--puzzle-grid-rows-desktop);
49
+ row-gap: var(--puzzle-grid-row-gap-desktop);
50
+ column-gap: var(--puzzle-grid-column-gap-desktop);
51
+ justify-items: var(--puzzle-grid-align-h-desktop);
52
+ align-items: var(--puzzle-grid-align-v-desktop);
53
+ grid-auto-flow: var(--puzzle-grid-auto-flow-desktop);
54
+ }
55
+
56
+ .puzzle-grid-item {
57
+ grid-column: var(--puzzle-grid-item-column-start-desktop) / var(--puzzle-grid-item-column-end-desktop);
58
+ grid-row-end: var(--puzzle-grid-item-row-span-desktop);
59
+ grid-row-start: var(--puzzle-grid-item-row-start-desktop);
60
+ justify-self: var(--puzzle-grid-item-align-h-desktop);
61
+ align-self: var(--puzzle-grid-item-align-v-desktop);
62
+ }
63
+ }
@@ -0,0 +1,65 @@
1
+ ;/* empty css */
2
+ let _puzzle_ui_core = require("@puzzle-ui/core");
3
+ let react = require("react");
4
+ // src/components/layout/grid/index.tsx
5
+ const responsiveStyle = (property, value, format = (value) => value) => {
6
+ const styles = {};
7
+ if (value === void 0) return styles;
8
+ let current = typeof value === "object" ? value.mobile : value;
9
+ for (const breakpoint of _puzzle_ui_core.BREAKPOINTS) {
10
+ if (typeof value === "object") current = value[breakpoint] ?? current;
11
+ styles[`--puzzle-grid-${property}-${breakpoint}`] = format(current);
12
+ }
13
+ return styles;
14
+ };
15
+ const positiveInteger = (value, prop) => {
16
+ if (!Number.isInteger(value) || value < 1) throw new RangeError(`Grid ${prop} must be a positive integer.`);
17
+ return value;
18
+ };
19
+ const tracks = (value) => typeof value === "number" ? `repeat(${positiveInteger(value, "columns/rows")}, minmax(0, 1fr))` : value;
20
+ const span = (value) => `span ${positiveInteger(value, "span")}`;
21
+ const line = (value) => {
22
+ if (typeof value === "number" && (!Number.isInteger(value) || value === 0)) throw new RangeError("Grid start lines must be non-zero integers or auto.");
23
+ return value;
24
+ };
25
+ const gaps = {
26
+ "0": "0",
27
+ xs: "var(--puzzle-space-1, 0.25rem)",
28
+ sm: "var(--puzzle-space-2, 0.5rem)",
29
+ md: "var(--puzzle-space-4, 1rem)",
30
+ lg: "var(--puzzle-space-8, 2rem)",
31
+ xl: "var(--puzzle-space-16, 4rem)"
32
+ };
33
+ const Grid = ({ as, columns = 1, rows = "none", minChildWidth, gap = "md", rowGap = gap, columnGap = gap, alignH = "stretch", alignV = "stretch", autoFlow = "row", children, className, style, ...props }) => (0, react.createElement)(as ?? "div", {
34
+ ...props,
35
+ className: (0, _puzzle_ui_core.cn)("puzzle-grid", className),
36
+ style: {
37
+ ...responsiveStyle("columns", columns, tracks),
38
+ ...responsiveStyle("columns", minChildWidth, (width) => `repeat(auto-fit, minmax(min(100%, ${width}), 1fr))`),
39
+ ...responsiveStyle("rows", rows, tracks),
40
+ ...responsiveStyle("row-gap", rowGap, (value) => gaps[value]),
41
+ ...responsiveStyle("column-gap", columnGap, (value) => gaps[value]),
42
+ ...responsiveStyle("align-h", alignH),
43
+ ...responsiveStyle("align-v", alignV),
44
+ ...responsiveStyle("auto-flow", autoFlow),
45
+ ...style
46
+ }
47
+ }, children);
48
+ const GridItem = ({ as, colSpan = 1, rowSpan = 1, colStart, rowStart = "auto", alignH = "auto", alignV = "auto", children, className, style, ...props }) => (0, react.createElement)(as ?? "div", {
49
+ ...props,
50
+ className: (0, _puzzle_ui_core.cn)("puzzle-grid-item", className),
51
+ style: {
52
+ ...responsiveStyle("item-column-end", colSpan, (value) => value === "full" ? "-1" : span(value)),
53
+ ...responsiveStyle("item-column-start", colSpan, (value) => value === "full" ? "1" : "auto"),
54
+ ...responsiveStyle("item-row-span", rowSpan, span),
55
+ ...responsiveStyle("item-column-start", colStart, line),
56
+ ...responsiveStyle("item-row-start", rowStart, line),
57
+ ...responsiveStyle("item-align-h", alignH),
58
+ ...responsiveStyle("item-align-v", alignV),
59
+ ...style
60
+ }
61
+ }, children);
62
+ exports.Grid = Grid;
63
+ exports.GridItem = GridItem;
64
+
65
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["BREAKPOINTS","createElement","cn"],"sources":["../../../../src/components/layout/grid/index.tsx"],"sourcesContent":["import { BREAKPOINTS, cn, type ResponsiveValue } from \"@puzzle-ui/core\";\nimport {\n createElement,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ElementType,\n type ReactNode,\n} from \"react\";\nimport \"./grid.css\";\n\ntype GridGap = \"0\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\ntype GridAlignment = \"start\" | \"center\" | \"end\" | \"stretch\";\ntype GridTracks = number | string;\ntype GridSpan = number | \"full\";\ntype GridLine = number | \"auto\";\ntype GridAutoFlow = NonNullable<CSSProperties[\"gridAutoFlow\"]>;\n\ntype RootProps<C extends ElementType> = {\n as?: C;\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\ntype GridOwnProps<C extends ElementType> = RootProps<C> & {\n columns?: ResponsiveValue<GridTracks>;\n rows?: ResponsiveValue<GridTracks>;\n minChildWidth?: ResponsiveValue<string>;\n gap?: ResponsiveValue<GridGap>;\n rowGap?: ResponsiveValue<GridGap>;\n columnGap?: ResponsiveValue<GridGap>;\n alignH?: ResponsiveValue<GridAlignment>;\n alignV?: ResponsiveValue<GridAlignment>;\n autoFlow?: ResponsiveValue<GridAutoFlow>;\n};\n\ntype GridProps<C extends ElementType = \"div\"> = GridOwnProps<C> &\n Omit<ComponentPropsWithRef<C>, keyof GridOwnProps<C>>;\n\ntype GridItemOwnProps<C extends ElementType> = RootProps<C> & {\n colSpan?: ResponsiveValue<GridSpan>;\n rowSpan?: ResponsiveValue<number>;\n colStart?: ResponsiveValue<GridLine>;\n rowStart?: ResponsiveValue<GridLine>;\n alignH?: ResponsiveValue<GridAlignment | \"auto\">;\n alignV?: ResponsiveValue<GridAlignment | \"auto\">;\n};\n\ntype GridItemProps<C extends ElementType = \"div\"> = GridItemOwnProps<C> &\n Omit<ComponentPropsWithRef<C>, keyof GridItemOwnProps<C>>;\n\ntype GridStyle = CSSProperties &\n Record<`--puzzle-grid-${string}`, string | number | undefined>;\n\nconst responsiveStyle = <T extends string | number>(\n property: string,\n value: ResponsiveValue<T>,\n format: (value: T) => string | number = (value) => value,\n): GridStyle => {\n const styles: GridStyle = {};\n if (value === undefined) return styles;\n\n let current = typeof value === \"object\" ? value.mobile : value;\n for (const breakpoint of BREAKPOINTS) {\n if (typeof value === \"object\") {\n current = value[breakpoint] ?? current;\n }\n styles[`--puzzle-grid-${property}-${breakpoint}`] = format(current);\n }\n return styles;\n};\n\nconst positiveInteger = (value: number, prop: string) => {\n if (!Number.isInteger(value) || value < 1) {\n throw new RangeError(`Grid ${prop} must be a positive integer.`);\n }\n return value;\n};\n\nconst tracks = (value: GridTracks) =>\n typeof value === \"number\"\n ? `repeat(${positiveInteger(value, \"columns/rows\")}, minmax(0, 1fr))`\n : value;\n\nconst span = (value: number) => `span ${positiveInteger(value, \"span\")}`;\n\nconst line = (value: GridLine) => {\n if (typeof value === \"number\" && (!Number.isInteger(value) || value === 0)) {\n throw new RangeError(\"Grid start lines must be non-zero integers or auto.\");\n }\n return value;\n};\n\nconst gaps: Record<GridGap, string> = {\n \"0\": \"0\",\n xs: \"var(--puzzle-space-1, 0.25rem)\",\n sm: \"var(--puzzle-space-2, 0.5rem)\",\n md: \"var(--puzzle-space-4, 1rem)\",\n lg: \"var(--puzzle-space-8, 2rem)\",\n xl: \"var(--puzzle-space-16, 4rem)\",\n};\n\nconst Grid = <C extends ElementType = \"div\">({\n as,\n columns = 1,\n rows = \"none\",\n minChildWidth,\n gap = \"md\",\n rowGap = gap,\n columnGap = gap,\n alignH = \"stretch\",\n alignV = \"stretch\",\n autoFlow = \"row\",\n children,\n className,\n style,\n ...props\n}: GridProps<C>) =>\n createElement(\n as ?? \"div\",\n {\n ...props,\n className: cn(\"puzzle-grid\", className),\n style: {\n ...responsiveStyle(\"columns\", columns, tracks),\n ...responsiveStyle(\n \"columns\",\n minChildWidth,\n (width) => `repeat(auto-fit, minmax(min(100%, ${width}), 1fr))`,\n ),\n ...responsiveStyle(\"rows\", rows, tracks),\n ...responsiveStyle(\"row-gap\", rowGap, (value) => gaps[value]),\n ...responsiveStyle(\"column-gap\", columnGap, (value) => gaps[value]),\n ...responsiveStyle(\"align-h\", alignH),\n ...responsiveStyle(\"align-v\", alignV),\n ...responsiveStyle(\"auto-flow\", autoFlow),\n ...style,\n },\n },\n children,\n );\n\nconst GridItem = <C extends ElementType = \"div\">({\n as,\n colSpan = 1,\n rowSpan = 1,\n colStart,\n rowStart = \"auto\",\n alignH = \"auto\",\n alignV = \"auto\",\n children,\n className,\n style,\n ...props\n}: GridItemProps<C>) =>\n createElement(\n as ?? \"div\",\n {\n ...props,\n className: cn(\"puzzle-grid-item\", className),\n style: {\n ...responsiveStyle(\"item-column-end\", colSpan, (value) =>\n value === \"full\" ? \"-1\" : span(value),\n ),\n ...responsiveStyle(\"item-column-start\", colSpan, (value) =>\n value === \"full\" ? \"1\" : \"auto\",\n ),\n ...responsiveStyle(\"item-row-span\", rowSpan, span),\n ...responsiveStyle(\"item-column-start\", colStart, line),\n ...responsiveStyle(\"item-row-start\", rowStart, line),\n ...responsiveStyle(\"item-align-h\", alignH),\n ...responsiveStyle(\"item-align-v\", alignV),\n ...style,\n },\n },\n children,\n );\n\nexport {\n Grid,\n GridItem,\n type GridProps,\n type GridItemProps,\n type GridGap,\n type GridAlignment,\n type GridTracks,\n type GridSpan,\n type GridLine,\n type GridAutoFlow,\n};\n"],"mappings":";;;;AAsDA,MAAM,mBACJ,UACA,OACA,UAAyC,UAAU,UACrC;CACd,MAAM,SAAoB,CAAC;CAC3B,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,IAAI,UAAU,OAAO,UAAU,WAAW,MAAM,SAAS;CACzD,KAAK,MAAM,cAAcA,gBAAAA,aAAa;EACpC,IAAI,OAAO,UAAU,UACnB,UAAU,MAAM,eAAe;EAEjC,OAAO,iBAAiB,SAAS,GAAG,gBAAgB,OAAO,OAAO;CACpE;CACA,OAAO;AACT;AAEA,MAAM,mBAAmB,OAAe,SAAiB;CACvD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,WAAW,QAAQ,KAAK,6BAA6B;CAEjE,OAAO;AACT;AAEA,MAAM,UAAU,UACd,OAAO,UAAU,WACb,UAAU,gBAAgB,OAAO,cAAc,EAAE,qBACjD;AAEN,MAAM,QAAQ,UAAkB,QAAQ,gBAAgB,OAAO,MAAM;AAErE,MAAM,QAAQ,UAAoB;CAChC,IAAI,OAAO,UAAU,aAAa,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,IACtE,MAAM,IAAI,WAAW,qDAAqD;CAE5E,OAAO;AACT;AAEA,MAAM,OAAgC;CACpC,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,QAAuC,EAC3C,IACA,UAAU,GACV,OAAO,QACP,eACA,MAAM,MACN,SAAS,KACT,YAAY,KACZ,SAAS,WACT,SAAS,WACT,WAAW,OACX,UACA,WACA,OACA,GAAG,aAAA,GAEHC,MAAAA,cAAAA,CACE,MAAM,OACN;CACE,GAAG;CACH,YAAA,GAAWC,gBAAAA,GAAAA,CAAG,eAAe,SAAS;CACtC,OAAO;EACL,GAAG,gBAAgB,WAAW,SAAS,MAAM;EAC7C,GAAG,gBACD,WACA,gBACC,UAAU,qCAAqC,MAAM,SACxD;EACA,GAAG,gBAAgB,QAAQ,MAAM,MAAM;EACvC,GAAG,gBAAgB,WAAW,SAAS,UAAU,KAAK,MAAM;EAC5D,GAAG,gBAAgB,cAAc,YAAY,UAAU,KAAK,MAAM;EAClE,GAAG,gBAAgB,WAAW,MAAM;EACpC,GAAG,gBAAgB,WAAW,MAAM;EACpC,GAAG,gBAAgB,aAAa,QAAQ;EACxC,GAAG;CACL;AACF,GACA,QACF;AAEF,MAAM,YAA2C,EAC/C,IACA,UAAU,GACV,UAAU,GACV,UACA,WAAW,QACX,SAAS,QACT,SAAS,QACT,UACA,WACA,OACA,GAAG,aAAA,GAEHD,MAAAA,cAAAA,CACE,MAAM,OACN;CACE,GAAG;CACH,YAAA,GAAWC,gBAAAA,GAAAA,CAAG,oBAAoB,SAAS;CAC3C,OAAO;EACL,GAAG,gBAAgB,mBAAmB,UAAU,UAC9C,UAAU,SAAS,OAAO,KAAK,KAAK,CACtC;EACA,GAAG,gBAAgB,qBAAqB,UAAU,UAChD,UAAU,SAAS,MAAM,MAC3B;EACA,GAAG,gBAAgB,iBAAiB,SAAS,IAAI;EACjD,GAAG,gBAAgB,qBAAqB,UAAU,IAAI;EACtD,GAAG,gBAAgB,kBAAkB,UAAU,IAAI;EACnD,GAAG,gBAAgB,gBAAgB,MAAM;EACzC,GAAG,gBAAgB,gBAAgB,MAAM;EACzC,GAAG;CACL;AACF,GACA,QACF"}
@@ -0,0 +1,38 @@
1
+ import { CSSProperties, ComponentPropsWithRef, ElementType, ReactNode } from "react";
2
+ import { ResponsiveValue } from "@puzzle-ui/core";
3
+ type GridGap = "0" | "xs" | "sm" | "md" | "lg" | "xl";
4
+ type GridAlignment = "start" | "center" | "end" | "stretch";
5
+ type GridTracks = number | string;
6
+ type GridSpan = number | "full";
7
+ type GridLine = number | "auto";
8
+ type GridAutoFlow = NonNullable<CSSProperties["gridAutoFlow"]>;
9
+ type RootProps<C extends ElementType> = {
10
+ as?: C;
11
+ children?: ReactNode;
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ };
15
+ type GridOwnProps<C extends ElementType> = RootProps<C> & {
16
+ columns?: ResponsiveValue<GridTracks>;
17
+ rows?: ResponsiveValue<GridTracks>;
18
+ minChildWidth?: ResponsiveValue<string>;
19
+ gap?: ResponsiveValue<GridGap>;
20
+ rowGap?: ResponsiveValue<GridGap>;
21
+ columnGap?: ResponsiveValue<GridGap>;
22
+ alignH?: ResponsiveValue<GridAlignment>;
23
+ alignV?: ResponsiveValue<GridAlignment>;
24
+ autoFlow?: ResponsiveValue<GridAutoFlow>;
25
+ };
26
+ type GridProps<C extends ElementType = "div"> = GridOwnProps<C> & Omit<ComponentPropsWithRef<C>, keyof GridOwnProps<C>>;
27
+ type GridItemOwnProps<C extends ElementType> = RootProps<C> & {
28
+ colSpan?: ResponsiveValue<GridSpan>;
29
+ rowSpan?: ResponsiveValue<number>;
30
+ colStart?: ResponsiveValue<GridLine>;
31
+ rowStart?: ResponsiveValue<GridLine>;
32
+ alignH?: ResponsiveValue<GridAlignment | "auto">;
33
+ alignV?: ResponsiveValue<GridAlignment | "auto">;
34
+ };
35
+ type GridItemProps<C extends ElementType = "div"> = GridItemOwnProps<C> & Omit<ComponentPropsWithRef<C>, keyof GridItemOwnProps<C>>;
36
+ declare const Grid: <C extends ElementType = "div">({ as, columns, rows, minChildWidth, gap, rowGap, columnGap, alignH, alignV, autoFlow, children, className, style, ...props }: GridProps<C>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
37
+ declare const GridItem: <C extends ElementType = "div">({ as, colSpan, rowSpan, colStart, rowStart, alignH, alignV, children, className, style, ...props }: GridItemProps<C>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
38
+ export { Grid, type GridAlignment, type GridAutoFlow, type GridGap, GridItem, type GridItemProps, type GridLine, type GridProps, type GridSpan, type GridTracks };
@@ -0,0 +1,38 @@
1
+ import { ResponsiveValue } from "@puzzle-ui/core";
2
+ import { CSSProperties, ComponentPropsWithRef, ElementType, ReactNode } from "react";
3
+ type GridGap = "0" | "xs" | "sm" | "md" | "lg" | "xl";
4
+ type GridAlignment = "start" | "center" | "end" | "stretch";
5
+ type GridTracks = number | string;
6
+ type GridSpan = number | "full";
7
+ type GridLine = number | "auto";
8
+ type GridAutoFlow = NonNullable<CSSProperties["gridAutoFlow"]>;
9
+ type RootProps<C extends ElementType> = {
10
+ as?: C;
11
+ children?: ReactNode;
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ };
15
+ type GridOwnProps<C extends ElementType> = RootProps<C> & {
16
+ columns?: ResponsiveValue<GridTracks>;
17
+ rows?: ResponsiveValue<GridTracks>;
18
+ minChildWidth?: ResponsiveValue<string>;
19
+ gap?: ResponsiveValue<GridGap>;
20
+ rowGap?: ResponsiveValue<GridGap>;
21
+ columnGap?: ResponsiveValue<GridGap>;
22
+ alignH?: ResponsiveValue<GridAlignment>;
23
+ alignV?: ResponsiveValue<GridAlignment>;
24
+ autoFlow?: ResponsiveValue<GridAutoFlow>;
25
+ };
26
+ type GridProps<C extends ElementType = "div"> = GridOwnProps<C> & Omit<ComponentPropsWithRef<C>, keyof GridOwnProps<C>>;
27
+ type GridItemOwnProps<C extends ElementType> = RootProps<C> & {
28
+ colSpan?: ResponsiveValue<GridSpan>;
29
+ rowSpan?: ResponsiveValue<number>;
30
+ colStart?: ResponsiveValue<GridLine>;
31
+ rowStart?: ResponsiveValue<GridLine>;
32
+ alignH?: ResponsiveValue<GridAlignment | "auto">;
33
+ alignV?: ResponsiveValue<GridAlignment | "auto">;
34
+ };
35
+ type GridItemProps<C extends ElementType = "div"> = GridItemOwnProps<C> & Omit<ComponentPropsWithRef<C>, keyof GridItemOwnProps<C>>;
36
+ declare const Grid: <C extends ElementType = "div">({ as, columns, rows, minChildWidth, gap, rowGap, columnGap, alignH, alignV, autoFlow, children, className, style, ...props }: GridProps<C>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
37
+ declare const GridItem: <C extends ElementType = "div">({ as, colSpan, rowSpan, colStart, rowStart, alignH, alignV, children, className, style, ...props }: GridItemProps<C>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
38
+ export { Grid, type GridAlignment, type GridAutoFlow, type GridGap, GridItem, type GridItemProps, type GridLine, type GridProps, type GridSpan, type GridTracks };
@@ -0,0 +1,64 @@
1
+ import "./grid.css";
2
+ import { BREAKPOINTS, cn } from "@puzzle-ui/core";
3
+ import { createElement } from "react";
4
+ // src/components/layout/grid/index.tsx
5
+ const responsiveStyle = (property, value, format = (value) => value) => {
6
+ const styles = {};
7
+ if (value === void 0) return styles;
8
+ let current = typeof value === "object" ? value.mobile : value;
9
+ for (const breakpoint of BREAKPOINTS) {
10
+ if (typeof value === "object") current = value[breakpoint] ?? current;
11
+ styles[`--puzzle-grid-${property}-${breakpoint}`] = format(current);
12
+ }
13
+ return styles;
14
+ };
15
+ const positiveInteger = (value, prop) => {
16
+ if (!Number.isInteger(value) || value < 1) throw new RangeError(`Grid ${prop} must be a positive integer.`);
17
+ return value;
18
+ };
19
+ const tracks = (value) => typeof value === "number" ? `repeat(${positiveInteger(value, "columns/rows")}, minmax(0, 1fr))` : value;
20
+ const span = (value) => `span ${positiveInteger(value, "span")}`;
21
+ const line = (value) => {
22
+ if (typeof value === "number" && (!Number.isInteger(value) || value === 0)) throw new RangeError("Grid start lines must be non-zero integers or auto.");
23
+ return value;
24
+ };
25
+ const gaps = {
26
+ "0": "0",
27
+ xs: "var(--puzzle-space-1, 0.25rem)",
28
+ sm: "var(--puzzle-space-2, 0.5rem)",
29
+ md: "var(--puzzle-space-4, 1rem)",
30
+ lg: "var(--puzzle-space-8, 2rem)",
31
+ xl: "var(--puzzle-space-16, 4rem)"
32
+ };
33
+ const Grid = ({ as, columns = 1, rows = "none", minChildWidth, gap = "md", rowGap = gap, columnGap = gap, alignH = "stretch", alignV = "stretch", autoFlow = "row", children, className, style, ...props }) => createElement(as ?? "div", {
34
+ ...props,
35
+ className: cn("puzzle-grid", className),
36
+ style: {
37
+ ...responsiveStyle("columns", columns, tracks),
38
+ ...responsiveStyle("columns", minChildWidth, (width) => `repeat(auto-fit, minmax(min(100%, ${width}), 1fr))`),
39
+ ...responsiveStyle("rows", rows, tracks),
40
+ ...responsiveStyle("row-gap", rowGap, (value) => gaps[value]),
41
+ ...responsiveStyle("column-gap", columnGap, (value) => gaps[value]),
42
+ ...responsiveStyle("align-h", alignH),
43
+ ...responsiveStyle("align-v", alignV),
44
+ ...responsiveStyle("auto-flow", autoFlow),
45
+ ...style
46
+ }
47
+ }, children);
48
+ const GridItem = ({ as, colSpan = 1, rowSpan = 1, colStart, rowStart = "auto", alignH = "auto", alignV = "auto", children, className, style, ...props }) => createElement(as ?? "div", {
49
+ ...props,
50
+ className: cn("puzzle-grid-item", className),
51
+ style: {
52
+ ...responsiveStyle("item-column-end", colSpan, (value) => value === "full" ? "-1" : span(value)),
53
+ ...responsiveStyle("item-column-start", colSpan, (value) => value === "full" ? "1" : "auto"),
54
+ ...responsiveStyle("item-row-span", rowSpan, span),
55
+ ...responsiveStyle("item-column-start", colStart, line),
56
+ ...responsiveStyle("item-row-start", rowStart, line),
57
+ ...responsiveStyle("item-align-h", alignH),
58
+ ...responsiveStyle("item-align-v", alignV),
59
+ ...style
60
+ }
61
+ }, children);
62
+ export { Grid, GridItem };
63
+
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/layout/grid/index.tsx"],"sourcesContent":["import { BREAKPOINTS, cn, type ResponsiveValue } from \"@puzzle-ui/core\";\nimport {\n createElement,\n type ComponentPropsWithRef,\n type CSSProperties,\n type ElementType,\n type ReactNode,\n} from \"react\";\nimport \"./grid.css\";\n\ntype GridGap = \"0\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\ntype GridAlignment = \"start\" | \"center\" | \"end\" | \"stretch\";\ntype GridTracks = number | string;\ntype GridSpan = number | \"full\";\ntype GridLine = number | \"auto\";\ntype GridAutoFlow = NonNullable<CSSProperties[\"gridAutoFlow\"]>;\n\ntype RootProps<C extends ElementType> = {\n as?: C;\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\ntype GridOwnProps<C extends ElementType> = RootProps<C> & {\n columns?: ResponsiveValue<GridTracks>;\n rows?: ResponsiveValue<GridTracks>;\n minChildWidth?: ResponsiveValue<string>;\n gap?: ResponsiveValue<GridGap>;\n rowGap?: ResponsiveValue<GridGap>;\n columnGap?: ResponsiveValue<GridGap>;\n alignH?: ResponsiveValue<GridAlignment>;\n alignV?: ResponsiveValue<GridAlignment>;\n autoFlow?: ResponsiveValue<GridAutoFlow>;\n};\n\ntype GridProps<C extends ElementType = \"div\"> = GridOwnProps<C> &\n Omit<ComponentPropsWithRef<C>, keyof GridOwnProps<C>>;\n\ntype GridItemOwnProps<C extends ElementType> = RootProps<C> & {\n colSpan?: ResponsiveValue<GridSpan>;\n rowSpan?: ResponsiveValue<number>;\n colStart?: ResponsiveValue<GridLine>;\n rowStart?: ResponsiveValue<GridLine>;\n alignH?: ResponsiveValue<GridAlignment | \"auto\">;\n alignV?: ResponsiveValue<GridAlignment | \"auto\">;\n};\n\ntype GridItemProps<C extends ElementType = \"div\"> = GridItemOwnProps<C> &\n Omit<ComponentPropsWithRef<C>, keyof GridItemOwnProps<C>>;\n\ntype GridStyle = CSSProperties &\n Record<`--puzzle-grid-${string}`, string | number | undefined>;\n\nconst responsiveStyle = <T extends string | number>(\n property: string,\n value: ResponsiveValue<T>,\n format: (value: T) => string | number = (value) => value,\n): GridStyle => {\n const styles: GridStyle = {};\n if (value === undefined) return styles;\n\n let current = typeof value === \"object\" ? value.mobile : value;\n for (const breakpoint of BREAKPOINTS) {\n if (typeof value === \"object\") {\n current = value[breakpoint] ?? current;\n }\n styles[`--puzzle-grid-${property}-${breakpoint}`] = format(current);\n }\n return styles;\n};\n\nconst positiveInteger = (value: number, prop: string) => {\n if (!Number.isInteger(value) || value < 1) {\n throw new RangeError(`Grid ${prop} must be a positive integer.`);\n }\n return value;\n};\n\nconst tracks = (value: GridTracks) =>\n typeof value === \"number\"\n ? `repeat(${positiveInteger(value, \"columns/rows\")}, minmax(0, 1fr))`\n : value;\n\nconst span = (value: number) => `span ${positiveInteger(value, \"span\")}`;\n\nconst line = (value: GridLine) => {\n if (typeof value === \"number\" && (!Number.isInteger(value) || value === 0)) {\n throw new RangeError(\"Grid start lines must be non-zero integers or auto.\");\n }\n return value;\n};\n\nconst gaps: Record<GridGap, string> = {\n \"0\": \"0\",\n xs: \"var(--puzzle-space-1, 0.25rem)\",\n sm: \"var(--puzzle-space-2, 0.5rem)\",\n md: \"var(--puzzle-space-4, 1rem)\",\n lg: \"var(--puzzle-space-8, 2rem)\",\n xl: \"var(--puzzle-space-16, 4rem)\",\n};\n\nconst Grid = <C extends ElementType = \"div\">({\n as,\n columns = 1,\n rows = \"none\",\n minChildWidth,\n gap = \"md\",\n rowGap = gap,\n columnGap = gap,\n alignH = \"stretch\",\n alignV = \"stretch\",\n autoFlow = \"row\",\n children,\n className,\n style,\n ...props\n}: GridProps<C>) =>\n createElement(\n as ?? \"div\",\n {\n ...props,\n className: cn(\"puzzle-grid\", className),\n style: {\n ...responsiveStyle(\"columns\", columns, tracks),\n ...responsiveStyle(\n \"columns\",\n minChildWidth,\n (width) => `repeat(auto-fit, minmax(min(100%, ${width}), 1fr))`,\n ),\n ...responsiveStyle(\"rows\", rows, tracks),\n ...responsiveStyle(\"row-gap\", rowGap, (value) => gaps[value]),\n ...responsiveStyle(\"column-gap\", columnGap, (value) => gaps[value]),\n ...responsiveStyle(\"align-h\", alignH),\n ...responsiveStyle(\"align-v\", alignV),\n ...responsiveStyle(\"auto-flow\", autoFlow),\n ...style,\n },\n },\n children,\n );\n\nconst GridItem = <C extends ElementType = \"div\">({\n as,\n colSpan = 1,\n rowSpan = 1,\n colStart,\n rowStart = \"auto\",\n alignH = \"auto\",\n alignV = \"auto\",\n children,\n className,\n style,\n ...props\n}: GridItemProps<C>) =>\n createElement(\n as ?? \"div\",\n {\n ...props,\n className: cn(\"puzzle-grid-item\", className),\n style: {\n ...responsiveStyle(\"item-column-end\", colSpan, (value) =>\n value === \"full\" ? \"-1\" : span(value),\n ),\n ...responsiveStyle(\"item-column-start\", colSpan, (value) =>\n value === \"full\" ? \"1\" : \"auto\",\n ),\n ...responsiveStyle(\"item-row-span\", rowSpan, span),\n ...responsiveStyle(\"item-column-start\", colStart, line),\n ...responsiveStyle(\"item-row-start\", rowStart, line),\n ...responsiveStyle(\"item-align-h\", alignH),\n ...responsiveStyle(\"item-align-v\", alignV),\n ...style,\n },\n },\n children,\n );\n\nexport {\n Grid,\n GridItem,\n type GridProps,\n type GridItemProps,\n type GridGap,\n type GridAlignment,\n type GridTracks,\n type GridSpan,\n type GridLine,\n type GridAutoFlow,\n};\n"],"mappings":";;;;AAsDA,MAAM,mBACJ,UACA,OACA,UAAyC,UAAU,UACrC;CACd,MAAM,SAAoB,CAAC;CAC3B,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,IAAI,UAAU,OAAO,UAAU,WAAW,MAAM,SAAS;CACzD,KAAK,MAAM,cAAc,aAAa;EACpC,IAAI,OAAO,UAAU,UACnB,UAAU,MAAM,eAAe;EAEjC,OAAO,iBAAiB,SAAS,GAAG,gBAAgB,OAAO,OAAO;CACpE;CACA,OAAO;AACT;AAEA,MAAM,mBAAmB,OAAe,SAAiB;CACvD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,WAAW,QAAQ,KAAK,6BAA6B;CAEjE,OAAO;AACT;AAEA,MAAM,UAAU,UACd,OAAO,UAAU,WACb,UAAU,gBAAgB,OAAO,cAAc,EAAE,qBACjD;AAEN,MAAM,QAAQ,UAAkB,QAAQ,gBAAgB,OAAO,MAAM;AAErE,MAAM,QAAQ,UAAoB;CAChC,IAAI,OAAO,UAAU,aAAa,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,IACtE,MAAM,IAAI,WAAW,qDAAqD;CAE5E,OAAO;AACT;AAEA,MAAM,OAAgC;CACpC,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,MAAM,QAAuC,EAC3C,IACA,UAAU,GACV,OAAO,QACP,eACA,MAAM,MACN,SAAS,KACT,YAAY,KACZ,SAAS,WACT,SAAS,WACT,WAAW,OACX,UACA,WACA,OACA,GAAG,YAEH,cACE,MAAM,OACN;CACE,GAAG;CACH,WAAW,GAAG,eAAe,SAAS;CACtC,OAAO;EACL,GAAG,gBAAgB,WAAW,SAAS,MAAM;EAC7C,GAAG,gBACD,WACA,gBACC,UAAU,qCAAqC,MAAM,SACxD;EACA,GAAG,gBAAgB,QAAQ,MAAM,MAAM;EACvC,GAAG,gBAAgB,WAAW,SAAS,UAAU,KAAK,MAAM;EAC5D,GAAG,gBAAgB,cAAc,YAAY,UAAU,KAAK,MAAM;EAClE,GAAG,gBAAgB,WAAW,MAAM;EACpC,GAAG,gBAAgB,WAAW,MAAM;EACpC,GAAG,gBAAgB,aAAa,QAAQ;EACxC,GAAG;CACL;AACF,GACA,QACF;AAEF,MAAM,YAA2C,EAC/C,IACA,UAAU,GACV,UAAU,GACV,UACA,WAAW,QACX,SAAS,QACT,SAAS,QACT,UACA,WACA,OACA,GAAG,YAEH,cACE,MAAM,OACN;CACE,GAAG;CACH,WAAW,GAAG,oBAAoB,SAAS;CAC3C,OAAO;EACL,GAAG,gBAAgB,mBAAmB,UAAU,UAC9C,UAAU,SAAS,OAAO,KAAK,KAAK,CACtC;EACA,GAAG,gBAAgB,qBAAqB,UAAU,UAChD,UAAU,SAAS,MAAM,MAC3B;EACA,GAAG,gBAAgB,iBAAiB,SAAS,IAAI;EACjD,GAAG,gBAAgB,qBAAqB,UAAU,IAAI;EACtD,GAAG,gBAAgB,kBAAkB,UAAU,IAAI;EACnD,GAAG,gBAAgB,gBAAgB,MAAM;EACzC,GAAG,gBAAgB,gBAAgB,MAAM;EACzC,GAAG;CACL;AACF,GACA,QACF"}
@@ -12,7 +12,7 @@ const getTextValue = (item) => {
12
12
  return "";
13
13
  };
14
14
  const normalizeSearchText = (value) => value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase();
15
- const TreeView = ({ items, selectionMode = "single", defaultExpandedIds = [], expandedIds, onExpandedChange, defaultSelectedIds = [], selectedIds, onSelectionChange, defaultFocusedId, onFocusedChange, loadChildren, onLoadChildrenError, onItemActivate, getItemActive, renderItem, renderIcon, renderLabel, expandOnItemClick = false, typeahead = true, size = "md", indentation, loadingLabel = "Loading…", loadErrorLabel = "Could not load children. Collapse and expand to retry.", itemClassName, className, style, dir, ...rootProps }) => {
15
+ const TreeView = ({ items, selectionMode = "single", defaultExpandedIds = [], expandedIds, onExpandedChange, defaultSelectedIds = [], selectedIds, onSelectionChange, defaultFocusedId, onFocusedChange, loadChildren, onLoadChildrenError, onItemActivate, getItemActive, renderItem, renderIcon, renderLabel, expandOnItemClick = true, typeahead = true, size = "md", indentation, loadingLabel = "Loading…", loadErrorLabel = "Could not load children. Collapse and expand to retry.", itemClassName, className, style, dir, ...rootProps }) => {
16
16
  const generatedId = (0, react.useId)();
17
17
  const isExpandedControlled = expandedIds !== void 0;
18
18
  const isSelectionControlled = selectedIds !== void 0;