shru-design-system 0.1.6 → 0.1.8
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 +96 -166
- package/dist/index.d.mts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +144 -29
- package/dist/index.mjs +136 -30
- package/package.json +7 -1
- package/scripts/apply-theme-sync.js +31 -9
- package/scripts/applyThemeSync.js +285 -0
- package/scripts/init.js +192 -367
- package/scripts/themeConfig.js +214 -0
- package/scripts/themeUtils.js +452 -0
- package/scripts/tokens/base.json +46 -0
- package/scripts/tokens/palettes.json +47 -0
- package/scripts/tokens/themes/animation/brisk.json +10 -0
- package/scripts/tokens/themes/animation/gentle.json +10 -0
- package/scripts/tokens/themes/color/dark.json +25 -0
- package/scripts/tokens/themes/color/white.json +25 -0
- package/scripts/tokens/themes/custom/brand.json +14 -0
- package/scripts/tokens/themes/custom/minimal.json +17 -0
- package/scripts/tokens/themes/density/comfortable.json +12 -0
- package/scripts/tokens/themes/density/compact.json +12 -0
- package/scripts/tokens/themes/shape/sharp.json +8 -0
- package/scripts/tokens/themes/shape/smooth.json +8 -0
- package/scripts/tokens/themes/typography/sans.json +7 -0
- package/scripts/tokens/themes/typography/serif.json +7 -0
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,184 +1,114 @@
|
|
|
1
1
|
# shru-design-system
|
|
2
2
|
|
|
3
|
-
A React component library with atoms and molecules built on Radix UI and Tailwind CSS.
|
|
3
|
+
A React component library with atoms and molecules built on Radix UI and Tailwind CSS, featuring a dynamic theme system.
|
|
4
|
+
|
|
5
|
+
## Project Structure
|
|
6
|
+
|
|
7
|
+
### Root Files
|
|
8
|
+
|
|
9
|
+
- **`package.json`** - Package configuration, dependencies, and scripts
|
|
10
|
+
- **`tsconfig.json`** - TypeScript configuration
|
|
11
|
+
- **`tsup.config.ts`** - Build configuration for bundling (ESM/CJS)
|
|
12
|
+
- **`tailwind.config.js`** - Tailwind CSS configuration (for library development)
|
|
13
|
+
- **`postcss.config.js`** - PostCSS configuration (for library development)
|
|
14
|
+
- **`.gitignore`** - Git ignore rules
|
|
15
|
+
|
|
16
|
+
### Source Code (`src/`)
|
|
17
|
+
|
|
18
|
+
- **`src/index.ts`** - Main entry point, exports all components and utilities
|
|
19
|
+
- **`src/utils.ts`** - Utility functions (cn helper for class merging)
|
|
20
|
+
|
|
21
|
+
#### Atoms (`src/atoms/`)
|
|
22
|
+
Basic UI building blocks:
|
|
23
|
+
- **`Button.tsx`** - Button component with variants and sizes
|
|
24
|
+
- **`Badge.tsx`** - Badge component for labels and tags
|
|
25
|
+
- **`TextInput.tsx`** - Text input field component
|
|
26
|
+
- **`Label.tsx`** - Form label component
|
|
27
|
+
- **`Textarea.tsx`** - Multi-line text input component
|
|
28
|
+
- **`Separator.tsx`** - Horizontal/vertical divider component
|
|
29
|
+
- **`Checkbox.tsx`** - Checkbox input component
|
|
30
|
+
|
|
31
|
+
#### Molecules (`src/molecules/`)
|
|
32
|
+
Composite components:
|
|
33
|
+
- **`Modal.tsx`** - Modal dialog component
|
|
34
|
+
- **`Select.tsx`** - Dropdown select component
|
|
35
|
+
- **`Tooltip.tsx`** - Tooltip component
|
|
36
|
+
|
|
37
|
+
#### Theme System (`src/themes/`)
|
|
38
|
+
- **`themeConfig.ts`** - Theme configuration and category definitions
|
|
39
|
+
- **`themeUtils.ts`** - Theme utility functions (loading, merging, flattening)
|
|
40
|
+
- **`applyThemeSync.ts`** - Synchronous theme application (prevents FOUC)
|
|
41
|
+
- **`useTheme.tsx`** - React hook for theme management
|
|
42
|
+
- **`ui/ThemeToggle/`** - Theme toggle UI component and related files
|
|
43
|
+
- **`ThemeToggle.tsx`** - Main theme toggle component
|
|
44
|
+
- **`useThemeToggle.ts`** - Hook for theme toggle UI state
|
|
45
|
+
- **`themeToggleConfig.ts`** - Theme toggle configuration
|
|
46
|
+
- **`themeToggleUtils.ts`** - Theme toggle utility functions
|
|
47
|
+
- **`index.ts`** - Theme toggle exports
|
|
48
|
+
|
|
49
|
+
### Build Output (`dist/`)
|
|
50
|
+
|
|
51
|
+
- **`index.js`** - CommonJS bundle
|
|
52
|
+
- **`index.mjs`** - ESM bundle
|
|
53
|
+
- **`index.d.ts`** - TypeScript declarations (CJS)
|
|
54
|
+
- **`index.d.mts`** - TypeScript declarations (ESM)
|
|
55
|
+
|
|
56
|
+
### Scripts (`scripts/`)
|
|
57
|
+
|
|
58
|
+
Setup and runtime scripts:
|
|
59
|
+
- **`init.js`** - Postinstall script that sets up Tailwind, PostCSS, and token files in consuming apps
|
|
60
|
+
- **`apply-theme-sync.js`** - Standalone synchronous theme script (injected into HTML)
|
|
61
|
+
- **`applyThemeSync.js`** - Synchronous theme application module
|
|
62
|
+
- **`themeConfig.js`** - Theme configuration (JavaScript version)
|
|
63
|
+
- **`themeUtils.js`** - Theme utilities (JavaScript version)
|
|
64
|
+
- **`tokens/`** - Default token files (copied to consuming apps)
|
|
65
|
+
- **`base.json`** - Base design tokens
|
|
66
|
+
- **`palettes.json`** - Color palette definitions
|
|
67
|
+
- **`themes/`** - Theme category files
|
|
68
|
+
- **`color/`** - Color theme variants (white, dark)
|
|
69
|
+
- **`typography/`** - Typography themes (sans, serif)
|
|
70
|
+
- **`shape/`** - Shape themes (smooth, sharp)
|
|
71
|
+
- **`density/`** - Density themes (comfortable, compact)
|
|
72
|
+
- **`animation/`** - Animation themes (gentle, brisk)
|
|
73
|
+
- **`custom/`** - Custom theme examples (brand, minimal)
|
|
74
|
+
|
|
75
|
+
### Test Application (`test/`)
|
|
76
|
+
|
|
77
|
+
Local test environment for developing and testing the library:
|
|
78
|
+
- **`package.json`** - Test app dependencies
|
|
79
|
+
- **`vite.config.ts`** - Vite configuration for test app
|
|
80
|
+
- **`index.html`** - Test app HTML entry point
|
|
81
|
+
- **`src/App.tsx`** - Test app component showcasing all library components
|
|
82
|
+
- **`src/main.tsx`** - Test app entry point
|
|
83
|
+
- **`src/index.css`** - Test app global styles
|
|
84
|
+
- **`tailwind.config.js`** - Tailwind config for test app
|
|
85
|
+
- **`postcss.config.js`** - PostCSS config for test app
|
|
86
|
+
- **`public/tokens/`** - Token files for testing (generated by init script)
|
|
87
|
+
- **`dist/`** - Vite build output (ignored in git)
|
|
4
88
|
|
|
5
|
-
##
|
|
89
|
+
## Usage
|
|
6
90
|
|
|
91
|
+
Install the package:
|
|
7
92
|
```bash
|
|
8
93
|
npm install shru-design-system
|
|
9
94
|
```
|
|
10
95
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
After installation, run the setup script to configure Tailwind CSS:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npx shru-design-system-init
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Or it will run automatically after `npm install` (you can skip this step if it already ran).
|
|
20
|
-
|
|
21
|
-
## Manual Setup
|
|
22
|
-
|
|
23
|
-
If you prefer to set up manually or the automatic setup didn't work:
|
|
24
|
-
|
|
25
|
-
### 1. Install Tailwind CSS
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm install -D tailwindcss postcss autoprefixer
|
|
29
|
-
npx tailwindcss init -p
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### 2. Configure Tailwind
|
|
33
|
-
|
|
34
|
-
Update `tailwind.config.js`:
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
export default {
|
|
38
|
-
content: [
|
|
39
|
-
"./index.html",
|
|
40
|
-
"./src/**/*.{js,ts,jsx,tsx}",
|
|
41
|
-
"./node_modules/shru-design-system/dist/**/*.{js,mjs}",
|
|
42
|
-
],
|
|
43
|
-
theme: {
|
|
44
|
-
extend: {
|
|
45
|
-
colors: {
|
|
46
|
-
background: "hsl(var(--background))",
|
|
47
|
-
foreground: "hsl(var(--foreground))",
|
|
48
|
-
primary: {
|
|
49
|
-
DEFAULT: "hsl(var(--primary))",
|
|
50
|
-
foreground: "hsl(var(--primary-foreground))",
|
|
51
|
-
},
|
|
52
|
-
secondary: {
|
|
53
|
-
DEFAULT: "hsl(var(--secondary))",
|
|
54
|
-
foreground: "hsl(var(--secondary-foreground))",
|
|
55
|
-
},
|
|
56
|
-
destructive: {
|
|
57
|
-
DEFAULT: "hsl(var(--destructive))",
|
|
58
|
-
foreground: "hsl(var(--destructive-foreground))",
|
|
59
|
-
},
|
|
60
|
-
muted: {
|
|
61
|
-
DEFAULT: "hsl(var(--muted))",
|
|
62
|
-
foreground: "hsl(var(--muted-foreground))",
|
|
63
|
-
},
|
|
64
|
-
accent: {
|
|
65
|
-
DEFAULT: "hsl(var(--accent))",
|
|
66
|
-
foreground: "hsl(var(--accent-foreground))",
|
|
67
|
-
},
|
|
68
|
-
popover: {
|
|
69
|
-
DEFAULT: "hsl(var(--popover))",
|
|
70
|
-
foreground: "hsl(var(--popover-foreground))",
|
|
71
|
-
},
|
|
72
|
-
border: "hsl(var(--border))",
|
|
73
|
-
input: "hsl(var(--input))",
|
|
74
|
-
ring: "hsl(var(--ring))",
|
|
75
|
-
},
|
|
76
|
-
borderRadius: {
|
|
77
|
-
lg: "var(--radius)",
|
|
78
|
-
md: "calc(var(--radius) - 2px)",
|
|
79
|
-
sm: "calc(var(--radius) - 4px)",
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
plugins: [],
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 3. Add CSS Variables
|
|
88
|
-
|
|
89
|
-
Create or update `src/index.css`:
|
|
90
|
-
|
|
91
|
-
```css
|
|
92
|
-
@tailwind base;
|
|
93
|
-
@tailwind components;
|
|
94
|
-
@tailwind utilities;
|
|
95
|
-
|
|
96
|
-
@layer base {
|
|
97
|
-
:root {
|
|
98
|
-
--background: 0 0% 100%;
|
|
99
|
-
--foreground: 222.2 84% 4.9%;
|
|
100
|
-
--primary: 222.2 47.4% 11.2%;
|
|
101
|
-
--primary-foreground: 210 40% 98%;
|
|
102
|
-
--secondary: 210 40% 96.1%;
|
|
103
|
-
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
104
|
-
--destructive: 0 84.2% 60.2%;
|
|
105
|
-
--destructive-foreground: 210 40% 98%;
|
|
106
|
-
--muted: 210 40% 96.1%;
|
|
107
|
-
--muted-foreground: 215.4 16.3% 46.9%;
|
|
108
|
-
--accent: 210 40% 96.1%;
|
|
109
|
-
--accent-foreground: 222.2 47.4% 11.2%;
|
|
110
|
-
--popover: 0 0% 100%;
|
|
111
|
-
--popover-foreground: 222.2 84% 4.9%;
|
|
112
|
-
--border: 214.3 31.8% 91.4%;
|
|
113
|
-
--input: 214.3 31.8% 91.4%;
|
|
114
|
-
--ring: 222.2 84% 4.9%;
|
|
115
|
-
--radius: 0.5rem;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
* {
|
|
119
|
-
border-color: hsl(var(--border));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
body {
|
|
123
|
-
background-color: hsl(var(--background));
|
|
124
|
-
color: hsl(var(--foreground));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### 4. Import CSS
|
|
130
|
-
|
|
131
|
-
Import the CSS file in your entry point (e.g., `src/main.tsx`):
|
|
96
|
+
The `postinstall` script automatically sets up Tailwind CSS, PostCSS, and token files in your project.
|
|
132
97
|
|
|
98
|
+
Import components:
|
|
133
99
|
```tsx
|
|
134
|
-
import '
|
|
100
|
+
import { Button, Modal, ThemeToggle } from 'shru-design-system'
|
|
135
101
|
```
|
|
136
102
|
|
|
137
|
-
##
|
|
103
|
+
## Development
|
|
138
104
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
function App() {
|
|
143
|
-
return (
|
|
144
|
-
<div>
|
|
145
|
-
<Button variant="default">Click me</Button>
|
|
146
|
-
<Badge>New</Badge>
|
|
147
|
-
|
|
148
|
-
<Modal>
|
|
149
|
-
<ModalTrigger asChild>
|
|
150
|
-
<Button>Open Modal</Button>
|
|
151
|
-
</ModalTrigger>
|
|
152
|
-
<ModalContent>
|
|
153
|
-
<ModalHeader>
|
|
154
|
-
<ModalTitle>Hello</ModalTitle>
|
|
155
|
-
<ModalDescription>This is a modal</ModalDescription>
|
|
156
|
-
</ModalHeader>
|
|
157
|
-
</ModalContent>
|
|
158
|
-
</Modal>
|
|
159
|
-
</div>
|
|
160
|
-
)
|
|
161
|
-
}
|
|
105
|
+
Build the library:
|
|
106
|
+
```bash
|
|
107
|
+
npm run build
|
|
162
108
|
```
|
|
163
109
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
### Atoms
|
|
167
|
-
- **Button** - Versatile button with multiple variants and sizes
|
|
168
|
-
- **Badge** - Small status indicators
|
|
169
|
-
|
|
170
|
-
### Molecules
|
|
171
|
-
- **Modal** - Dialog component with overlay
|
|
172
|
-
- **Select** - Dropdown select component
|
|
173
|
-
|
|
174
|
-
## Peer Dependencies
|
|
175
|
-
|
|
176
|
-
Make sure to install these peer dependencies:
|
|
177
|
-
|
|
110
|
+
Test locally:
|
|
178
111
|
```bash
|
|
179
|
-
|
|
112
|
+
cd test && npm run dev
|
|
180
113
|
```
|
|
181
114
|
|
|
182
|
-
## License
|
|
183
|
-
|
|
184
|
-
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
5
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
6
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
4
7
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
8
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
6
9
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
@@ -26,6 +29,30 @@ declare const Badge: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<
|
|
|
26
29
|
asChild?: boolean;
|
|
27
30
|
}, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
28
31
|
|
|
32
|
+
declare const textInputTypes: readonly ["text", "email", "password", "number", "tel", "url", "search"];
|
|
33
|
+
interface TextInputProps extends React.ComponentProps<"input"> {
|
|
34
|
+
type?: typeof textInputTypes[number];
|
|
35
|
+
}
|
|
36
|
+
declare const TextInput: React.ForwardRefExoticComponent<Omit<TextInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
37
|
+
|
|
38
|
+
interface LabelProps extends React.ComponentProps<typeof LabelPrimitive.Root> {
|
|
39
|
+
}
|
|
40
|
+
declare const Label: React.ForwardRefExoticComponent<Omit<LabelProps, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
41
|
+
|
|
42
|
+
interface TextareaProps extends React.ComponentProps<"textarea"> {
|
|
43
|
+
}
|
|
44
|
+
declare const Textarea: React.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
45
|
+
|
|
46
|
+
declare const separatorOrientations: readonly ["horizontal", "vertical"];
|
|
47
|
+
interface SeparatorProps extends React.ComponentProps<typeof SeparatorPrimitive.Root> {
|
|
48
|
+
orientation?: typeof separatorOrientations[number];
|
|
49
|
+
}
|
|
50
|
+
declare const Separator: React.ForwardRefExoticComponent<Omit<SeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
+
|
|
52
|
+
interface CheckboxProps extends React.ComponentProps<typeof CheckboxPrimitive.Root> {
|
|
53
|
+
}
|
|
54
|
+
declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
55
|
+
|
|
29
56
|
declare function Modal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>): react_jsx_runtime.JSX.Element;
|
|
30
57
|
declare function ModalTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>): react_jsx_runtime.JSX.Element;
|
|
31
58
|
declare function ModalPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>): react_jsx_runtime.JSX.Element;
|
|
@@ -130,6 +157,16 @@ type ThemeCategory = {
|
|
|
130
157
|
order: number;
|
|
131
158
|
themes: Record<string, ThemeMetadata>;
|
|
132
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* Centralized theme category order
|
|
162
|
+
* Used everywhere to ensure consistency
|
|
163
|
+
* Custom category is included but handled specially (optional, user-created files)
|
|
164
|
+
*
|
|
165
|
+
* ⚠️ IF YOU UPDATE THIS, ALSO UPDATE:
|
|
166
|
+
* 1. scripts/themeConfig.js - THEME_CATEGORY_ORDER (JavaScript version)
|
|
167
|
+
* 2. scripts/apply-theme-sync.js - THEME_CATEGORY_ORDER constant (standalone script, can't import)
|
|
168
|
+
*/
|
|
169
|
+
declare const THEME_CATEGORY_ORDER: readonly ["color", "typography", "shape", "density", "animation", "custom"];
|
|
133
170
|
/**
|
|
134
171
|
* Register a custom theme dynamically
|
|
135
172
|
* Allows users to add themes without modifying the base config
|
|
@@ -178,4 +215,4 @@ declare function getCurrentCSSVariables(): Record<string, string>;
|
|
|
178
215
|
*/
|
|
179
216
|
declare function applyThemeSync(): void;
|
|
180
217
|
|
|
181
|
-
export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
|
218
|
+
export { Badge, Button, Checkbox, Label, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, THEME_CATEGORY_ORDER, TextInput, Textarea, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
5
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
6
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
4
7
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
8
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
6
9
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
@@ -26,6 +29,30 @@ declare const Badge: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<
|
|
|
26
29
|
asChild?: boolean;
|
|
27
30
|
}, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
28
31
|
|
|
32
|
+
declare const textInputTypes: readonly ["text", "email", "password", "number", "tel", "url", "search"];
|
|
33
|
+
interface TextInputProps extends React.ComponentProps<"input"> {
|
|
34
|
+
type?: typeof textInputTypes[number];
|
|
35
|
+
}
|
|
36
|
+
declare const TextInput: React.ForwardRefExoticComponent<Omit<TextInputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
37
|
+
|
|
38
|
+
interface LabelProps extends React.ComponentProps<typeof LabelPrimitive.Root> {
|
|
39
|
+
}
|
|
40
|
+
declare const Label: React.ForwardRefExoticComponent<Omit<LabelProps, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
41
|
+
|
|
42
|
+
interface TextareaProps extends React.ComponentProps<"textarea"> {
|
|
43
|
+
}
|
|
44
|
+
declare const Textarea: React.ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
45
|
+
|
|
46
|
+
declare const separatorOrientations: readonly ["horizontal", "vertical"];
|
|
47
|
+
interface SeparatorProps extends React.ComponentProps<typeof SeparatorPrimitive.Root> {
|
|
48
|
+
orientation?: typeof separatorOrientations[number];
|
|
49
|
+
}
|
|
50
|
+
declare const Separator: React.ForwardRefExoticComponent<Omit<SeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
+
|
|
52
|
+
interface CheckboxProps extends React.ComponentProps<typeof CheckboxPrimitive.Root> {
|
|
53
|
+
}
|
|
54
|
+
declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
55
|
+
|
|
29
56
|
declare function Modal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>): react_jsx_runtime.JSX.Element;
|
|
30
57
|
declare function ModalTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>): react_jsx_runtime.JSX.Element;
|
|
31
58
|
declare function ModalPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>): react_jsx_runtime.JSX.Element;
|
|
@@ -130,6 +157,16 @@ type ThemeCategory = {
|
|
|
130
157
|
order: number;
|
|
131
158
|
themes: Record<string, ThemeMetadata>;
|
|
132
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* Centralized theme category order
|
|
162
|
+
* Used everywhere to ensure consistency
|
|
163
|
+
* Custom category is included but handled specially (optional, user-created files)
|
|
164
|
+
*
|
|
165
|
+
* ⚠️ IF YOU UPDATE THIS, ALSO UPDATE:
|
|
166
|
+
* 1. scripts/themeConfig.js - THEME_CATEGORY_ORDER (JavaScript version)
|
|
167
|
+
* 2. scripts/apply-theme-sync.js - THEME_CATEGORY_ORDER constant (standalone script, can't import)
|
|
168
|
+
*/
|
|
169
|
+
declare const THEME_CATEGORY_ORDER: readonly ["color", "typography", "shape", "density", "animation", "custom"];
|
|
133
170
|
/**
|
|
134
171
|
* Register a custom theme dynamically
|
|
135
172
|
* Allows users to add themes without modifying the base config
|
|
@@ -178,4 +215,4 @@ declare function getCurrentCSSVariables(): Record<string, string>;
|
|
|
178
215
|
*/
|
|
179
216
|
declare function applyThemeSync(): void;
|
|
180
217
|
|
|
181
|
-
export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
|
218
|
+
export { Badge, Button, Checkbox, Label, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, THEME_CATEGORY_ORDER, TextInput, Textarea, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,11 @@ var classVarianceAuthority = require('class-variance-authority');
|
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
-
var
|
|
9
|
+
var LabelPrimitive = require('@radix-ui/react-label');
|
|
10
|
+
var SeparatorPrimitive = require('@radix-ui/react-separator');
|
|
11
|
+
var CheckboxPrimitive = require('@radix-ui/react-checkbox');
|
|
10
12
|
var lucideReact = require('lucide-react');
|
|
13
|
+
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
11
14
|
var SelectPrimitive = require('@radix-ui/react-select');
|
|
12
15
|
var TooltipPrimitive = require('@radix-ui/react-tooltip');
|
|
13
16
|
|
|
@@ -30,6 +33,9 @@ function _interopNamespace(e) {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
|
+
var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
37
|
+
var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
|
|
38
|
+
var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
|
|
33
39
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
34
40
|
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
35
41
|
var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
|
|
@@ -109,6 +115,98 @@ var Badge = React__namespace.forwardRef(({ className, variant, asChild = false,
|
|
|
109
115
|
);
|
|
110
116
|
});
|
|
111
117
|
Badge.displayName = "Badge";
|
|
118
|
+
var TextInput = React__namespace.forwardRef(
|
|
119
|
+
({ className, type = "text", ...props }, ref) => {
|
|
120
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
121
|
+
"input",
|
|
122
|
+
{
|
|
123
|
+
ref,
|
|
124
|
+
type,
|
|
125
|
+
"data-slot": "text-input",
|
|
126
|
+
className: cn(
|
|
127
|
+
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
128
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
129
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
130
|
+
className
|
|
131
|
+
),
|
|
132
|
+
...props
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
TextInput.displayName = "TextInput";
|
|
138
|
+
var Label = React__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
139
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
140
|
+
LabelPrimitive__namespace.Root,
|
|
141
|
+
{
|
|
142
|
+
ref,
|
|
143
|
+
"data-slot": "label",
|
|
144
|
+
className: cn(
|
|
145
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
146
|
+
className
|
|
147
|
+
),
|
|
148
|
+
...props
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
Label.displayName = "Label";
|
|
153
|
+
var Textarea = React__namespace.forwardRef(
|
|
154
|
+
({ className, ...props }, ref) => {
|
|
155
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
"textarea",
|
|
157
|
+
{
|
|
158
|
+
ref,
|
|
159
|
+
"data-slot": "textarea",
|
|
160
|
+
className: cn(
|
|
161
|
+
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
162
|
+
className
|
|
163
|
+
),
|
|
164
|
+
...props
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
Textarea.displayName = "Textarea";
|
|
170
|
+
var Separator = React__namespace.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => {
|
|
171
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
172
|
+
SeparatorPrimitive__namespace.Root,
|
|
173
|
+
{
|
|
174
|
+
ref,
|
|
175
|
+
"data-slot": "separator",
|
|
176
|
+
decorative,
|
|
177
|
+
orientation,
|
|
178
|
+
className: cn(
|
|
179
|
+
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
180
|
+
className
|
|
181
|
+
),
|
|
182
|
+
...props
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
Separator.displayName = "Separator";
|
|
187
|
+
var Checkbox = React__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
188
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
189
|
+
CheckboxPrimitive__namespace.Root,
|
|
190
|
+
{
|
|
191
|
+
ref,
|
|
192
|
+
"data-slot": "checkbox",
|
|
193
|
+
className: cn(
|
|
194
|
+
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
195
|
+
className
|
|
196
|
+
),
|
|
197
|
+
...props,
|
|
198
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
199
|
+
CheckboxPrimitive__namespace.Indicator,
|
|
200
|
+
{
|
|
201
|
+
"data-slot": "checkbox-indicator",
|
|
202
|
+
className: "grid place-content-center text-current transition-none",
|
|
203
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-3.5" })
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
Checkbox.displayName = "Checkbox";
|
|
112
210
|
function Modal({
|
|
113
211
|
...props
|
|
114
212
|
}) {
|
|
@@ -434,6 +532,7 @@ function TooltipContent({
|
|
|
434
532
|
}
|
|
435
533
|
|
|
436
534
|
// src/themes/themeConfig.ts
|
|
535
|
+
var THEME_CATEGORY_ORDER = ["color", "typography", "shape", "density", "animation", "custom"];
|
|
437
536
|
var baseThemeCategories = {
|
|
438
537
|
color: {
|
|
439
538
|
name: "Color",
|
|
@@ -524,11 +623,25 @@ var baseThemeCategories = {
|
|
|
524
623
|
description: "Fast, brisk animations"
|
|
525
624
|
}
|
|
526
625
|
}
|
|
626
|
+
},
|
|
627
|
+
custom: {
|
|
628
|
+
name: "Custom",
|
|
629
|
+
order: 6,
|
|
630
|
+
themes: {
|
|
631
|
+
brand: {
|
|
632
|
+
name: "Brand",
|
|
633
|
+
file: "custom/brand.json",
|
|
634
|
+
icon: "\u{1F3AF}",
|
|
635
|
+
description: "Brand colors with purple and pink accents"
|
|
636
|
+
},
|
|
637
|
+
minimal: {
|
|
638
|
+
name: "Minimal",
|
|
639
|
+
file: "custom/minimal.json",
|
|
640
|
+
icon: "\u26AA",
|
|
641
|
+
description: "Minimal theme with reduced spacing"
|
|
642
|
+
}
|
|
643
|
+
}
|
|
527
644
|
}
|
|
528
|
-
// Custom themes are not included in base config
|
|
529
|
-
// They should be discovered dynamically or registered by users
|
|
530
|
-
// Users can add custom themes by creating files in /tokens/themes/custom/
|
|
531
|
-
// and registering them using registerTheme()
|
|
532
645
|
};
|
|
533
646
|
var discoveredThemesCache = null;
|
|
534
647
|
async function discoverThemes() {
|
|
@@ -748,9 +861,15 @@ function flattenToCSS(tokens, prefix = "", result = {}, isColorContext = false)
|
|
|
748
861
|
const value = tokens[key];
|
|
749
862
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
750
863
|
const enteringColor = key === "color" && prefix === "";
|
|
864
|
+
const enteringTypography = key === "typography" && prefix === "";
|
|
865
|
+
const enteringShape = key === "shape" && prefix === "";
|
|
751
866
|
const inColorContext = isColorContext || enteringColor;
|
|
752
867
|
if (enteringColor) {
|
|
753
868
|
flattenToCSS(value, "", result, true);
|
|
869
|
+
} else if (enteringTypography) {
|
|
870
|
+
flattenToCSS(value, "", result, false);
|
|
871
|
+
} else if (enteringShape) {
|
|
872
|
+
flattenToCSS(value, "", result, false);
|
|
754
873
|
} else if (inColorContext) {
|
|
755
874
|
flattenToCSS(value, "", result, true);
|
|
756
875
|
} else {
|
|
@@ -860,26 +979,19 @@ async function generateAndApplyTheme(selectedThemes = {}) {
|
|
|
860
979
|
}
|
|
861
980
|
const palette = palettes.palette;
|
|
862
981
|
let merged = deepMerge(base, { palette });
|
|
863
|
-
|
|
864
|
-
for (const category of categoryOrder) {
|
|
865
|
-
if (category === "custom") continue;
|
|
982
|
+
for (const category of THEME_CATEGORY_ORDER) {
|
|
866
983
|
const themeId = selectedThemes[category];
|
|
867
984
|
if (!themeId) continue;
|
|
868
985
|
const themePath = `/tokens/themes/${category}/${themeId}.json`;
|
|
869
986
|
const themeData = await loadTokenFile(themePath);
|
|
870
987
|
if (themeData) {
|
|
871
988
|
merged = deepMerge(merged, themeData);
|
|
872
|
-
} else
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
const customData = await loadTokenFile(customPath);
|
|
879
|
-
if (customData) {
|
|
880
|
-
merged = deepMerge(merged, customData);
|
|
881
|
-
} else if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
882
|
-
console.warn(`Custom theme file not found: ${customPath} (this is normal if you haven't created it yet)`);
|
|
989
|
+
} else {
|
|
990
|
+
if (category !== "custom" && typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
991
|
+
console.warn(`Theme file not found: ${themePath}`);
|
|
992
|
+
} else if (category === "custom" && typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
993
|
+
console.warn(`Custom theme file not found: ${themePath} (this is normal if you haven't created it yet)`);
|
|
994
|
+
}
|
|
883
995
|
}
|
|
884
996
|
}
|
|
885
997
|
const resolved = resolveReferences(merged, palette);
|
|
@@ -1338,8 +1450,7 @@ function applyThemeSync() {
|
|
|
1338
1450
|
const palettes = loadJSONSync("/tokens/palettes.json");
|
|
1339
1451
|
const palette = palettes?.palette || {};
|
|
1340
1452
|
let merged = deepMergeSync(base, { palette });
|
|
1341
|
-
const
|
|
1342
|
-
for (const category of categoryOrder) {
|
|
1453
|
+
for (const category of THEME_CATEGORY_ORDER) {
|
|
1343
1454
|
const themeId = selectedThemes[category];
|
|
1344
1455
|
if (!themeId) continue;
|
|
1345
1456
|
const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`);
|
|
@@ -1347,12 +1458,6 @@ function applyThemeSync() {
|
|
|
1347
1458
|
merged = deepMergeSync(merged, themeData);
|
|
1348
1459
|
}
|
|
1349
1460
|
}
|
|
1350
|
-
if (selectedThemes.custom) {
|
|
1351
|
-
const customData = loadJSONSync(`/tokens/themes/custom/${selectedThemes.custom}.json`);
|
|
1352
|
-
if (customData) {
|
|
1353
|
-
merged = deepMergeSync(merged, customData);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
1461
|
const resolved = resolveReferencesSync(merged, palette);
|
|
1357
1462
|
const cssVars = flattenToCSSSync(resolved);
|
|
1358
1463
|
const mappedVars = mapToTailwindVarsSync(cssVars);
|
|
@@ -1478,9 +1583,15 @@ function flattenToCSSSync(tokens, prefix = "", result = {}, isColorContext = fal
|
|
|
1478
1583
|
const value = tokens[key];
|
|
1479
1584
|
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
1480
1585
|
const enteringColor = key === "color" && prefix === "";
|
|
1586
|
+
const enteringTypography = key === "typography" && prefix === "";
|
|
1587
|
+
const enteringShape = key === "shape" && prefix === "";
|
|
1481
1588
|
const inColorContext = isColorContext || enteringColor;
|
|
1482
1589
|
if (enteringColor) {
|
|
1483
1590
|
flattenToCSSSync(value, "", result, true);
|
|
1591
|
+
} else if (enteringTypography) {
|
|
1592
|
+
flattenToCSSSync(value, "", result, false);
|
|
1593
|
+
} else if (enteringShape) {
|
|
1594
|
+
flattenToCSSSync(value, "", result, false);
|
|
1484
1595
|
} else if (inColorContext) {
|
|
1485
1596
|
flattenToCSSSync(value, "", result, true);
|
|
1486
1597
|
} else {
|
|
@@ -1526,6 +1637,8 @@ function mapToTailwindVarsSync(cssVars) {
|
|
|
1526
1637
|
|
|
1527
1638
|
exports.Badge = Badge;
|
|
1528
1639
|
exports.Button = Button;
|
|
1640
|
+
exports.Checkbox = Checkbox;
|
|
1641
|
+
exports.Label = Label;
|
|
1529
1642
|
exports.Modal = Modal;
|
|
1530
1643
|
exports.ModalClose = ModalClose;
|
|
1531
1644
|
exports.ModalContent = ModalContent;
|
|
@@ -1546,6 +1659,10 @@ exports.SelectScrollUpButton = SelectScrollUpButton;
|
|
|
1546
1659
|
exports.SelectSeparator = SelectSeparator;
|
|
1547
1660
|
exports.SelectTrigger = SelectTrigger;
|
|
1548
1661
|
exports.SelectValue = SelectValue;
|
|
1662
|
+
exports.Separator = Separator;
|
|
1663
|
+
exports.THEME_CATEGORY_ORDER = THEME_CATEGORY_ORDER;
|
|
1664
|
+
exports.TextInput = TextInput;
|
|
1665
|
+
exports.Textarea = Textarea;
|
|
1549
1666
|
exports.ThemeToggle = ThemeToggle;
|
|
1550
1667
|
exports.Tooltip = Tooltip;
|
|
1551
1668
|
exports.TooltipContent = TooltipContent;
|
|
@@ -1563,5 +1680,3 @@ exports.getThemesForCategory = getThemesForCategory;
|
|
|
1563
1680
|
exports.registerTheme = registerTheme;
|
|
1564
1681
|
exports.useTheme = useTheme;
|
|
1565
1682
|
exports.useThemeToggle = useThemeToggle;
|
|
1566
|
-
//# sourceMappingURL=index.js.map
|
|
1567
|
-
//# sourceMappingURL=index.js.map
|