@tribepad/themis 1.0.16 → 1.0.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tribepad/themis",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Accessible React component library built on React Aria primitives",
5
5
  "author": "Tribepad <mbasford@tribepad.com>",
6
6
  "license": "MIT",
@@ -0,0 +1,289 @@
1
+ /**
2
+ * ColorPicker Component Stories
3
+ *
4
+ * Storybook stories demonstrating all modes, variants, sizes, and states.
5
+ */
6
+
7
+ import { useState } from 'react';
8
+ import type { Meta, StoryObj } from '@storybook/react-vite';
9
+ import { ColorPicker } from './ColorPicker';
10
+ import type { Color } from 'react-aria-components';
11
+
12
+ const meta = {
13
+ title: 'Elements/ColorPicker',
14
+ component: ColorPicker,
15
+ parameters: {
16
+ layout: 'centered',
17
+ docs: {
18
+ description: {
19
+ component:
20
+ 'Accessible color picker with swatch presets, advanced picker, or both. Built on React Aria ColorPicker and ColorSwatchPicker primitives for WCAG 2.2 AAA compliance.',
21
+ },
22
+ },
23
+ },
24
+ tags: ['autodocs'],
25
+ argTypes: {
26
+ mode: {
27
+ control: 'select',
28
+ options: ['swatch', 'advanced', 'both'],
29
+ description: 'Which picker UI to display',
30
+ table: { defaultValue: { summary: 'both' } },
31
+ },
32
+ size: {
33
+ control: 'select',
34
+ options: ['sm', 'default', 'lg'],
35
+ description: 'Size variant',
36
+ table: { defaultValue: { summary: 'default' } },
37
+ },
38
+ label: {
39
+ control: 'text',
40
+ description: 'Label text',
41
+ },
42
+ description: {
43
+ control: 'text',
44
+ description: 'Helper text below the label',
45
+ },
46
+ errorMessage: {
47
+ control: 'text',
48
+ description: 'Error message when isInvalid is true',
49
+ },
50
+ isDisabled: {
51
+ control: 'boolean',
52
+ description: 'Whether the picker is disabled',
53
+ },
54
+ isRequired: {
55
+ control: 'boolean',
56
+ description: 'Whether a value is required',
57
+ },
58
+ isInvalid: {
59
+ control: 'boolean',
60
+ description: 'Whether the field is in an invalid state',
61
+ },
62
+ isReadOnly: {
63
+ control: 'boolean',
64
+ description: 'Whether the field is read-only',
65
+ },
66
+ },
67
+ } satisfies Meta<typeof ColorPicker>;
68
+
69
+ export default meta;
70
+ type Story = StoryObj<typeof meta>;
71
+
72
+ // =============================================================================
73
+ // Default (Both Mode)
74
+ // =============================================================================
75
+
76
+ export const Default: Story = {
77
+ args: {
78
+ label: 'Brand Color',
79
+ defaultValue: '#7c3aed',
80
+ },
81
+ };
82
+
83
+ // =============================================================================
84
+ // Swatch Only
85
+ // =============================================================================
86
+
87
+ export const SwatchOnly: Story = {
88
+ args: {
89
+ label: 'Pick a color',
90
+ mode: 'swatch',
91
+ defaultValue: '#ff0000',
92
+ },
93
+ };
94
+
95
+ // =============================================================================
96
+ // Advanced Only
97
+ // =============================================================================
98
+
99
+ export const AdvancedOnly: Story = {
100
+ args: {
101
+ label: 'Custom Color',
102
+ mode: 'advanced',
103
+ defaultValue: '#4a86e8',
104
+ },
105
+ };
106
+
107
+ // =============================================================================
108
+ // Custom Swatch Colors
109
+ // =============================================================================
110
+
111
+ export const CustomColors: Story = {
112
+ args: {
113
+ label: 'Theme Color',
114
+ mode: 'swatch',
115
+ colors: [
116
+ '#ef4444', '#f97316', '#eab308', '#22c55e',
117
+ '#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899',
118
+ ],
119
+ defaultValue: '#3b82f6',
120
+ },
121
+ };
122
+
123
+ // =============================================================================
124
+ // With Description
125
+ // =============================================================================
126
+
127
+ export const WithDescription: Story = {
128
+ args: {
129
+ label: 'Brand Color',
130
+ description: 'Choose the primary color for your brand. This will be used across all marketing materials.',
131
+ defaultValue: '#7c3aed',
132
+ },
133
+ };
134
+
135
+ // =============================================================================
136
+ // Required
137
+ // =============================================================================
138
+
139
+ export const Required: Story = {
140
+ args: {
141
+ label: 'Primary Color',
142
+ isRequired: true,
143
+ defaultValue: '#000000',
144
+ },
145
+ };
146
+
147
+ // =============================================================================
148
+ // Invalid State
149
+ // =============================================================================
150
+
151
+ export const Invalid: Story = {
152
+ args: {
153
+ label: 'Color',
154
+ isInvalid: true,
155
+ errorMessage: 'Please select a valid brand color',
156
+ defaultValue: '#000000',
157
+ },
158
+ };
159
+
160
+ // =============================================================================
161
+ // Disabled
162
+ // =============================================================================
163
+
164
+ export const Disabled: Story = {
165
+ args: {
166
+ label: 'Color',
167
+ isDisabled: true,
168
+ defaultValue: '#7c3aed',
169
+ },
170
+ };
171
+
172
+ // =============================================================================
173
+ // Read Only
174
+ // =============================================================================
175
+
176
+ export const ReadOnly: Story = {
177
+ args: {
178
+ label: 'Assigned Color',
179
+ isReadOnly: true,
180
+ defaultValue: '#22c55e',
181
+ },
182
+ };
183
+
184
+ // =============================================================================
185
+ // Size: Small
186
+ // =============================================================================
187
+
188
+ export const SizeSmall: Story = {
189
+ args: {
190
+ label: 'Color',
191
+ size: 'sm',
192
+ defaultValue: '#ff0000',
193
+ },
194
+ };
195
+
196
+ // =============================================================================
197
+ // Size: Large
198
+ // =============================================================================
199
+
200
+ export const SizeLarge: Story = {
201
+ args: {
202
+ label: 'Color',
203
+ size: 'lg',
204
+ defaultValue: '#0000ff',
205
+ },
206
+ };
207
+
208
+ // =============================================================================
209
+ // Controlled
210
+ // =============================================================================
211
+
212
+ function ControlledExample() {
213
+ const [hex, setHex] = useState('#7c3aed');
214
+
215
+ return (
216
+ <div className="flex flex-col gap-4">
217
+ <ColorPicker
218
+ label="Controlled Color"
219
+ value={hex}
220
+ onChange={(color: Color) => setHex(color.toString('hex'))}
221
+ />
222
+ <p className="text-sm text-[var(--muted-foreground)]">
223
+ Selected: <code className="font-mono">{hex}</code>
224
+ </p>
225
+ </div>
226
+ );
227
+ }
228
+
229
+ export const Controlled: Story = {
230
+ render: () => <ControlledExample />,
231
+ };
232
+
233
+ // =============================================================================
234
+ // With Form Name
235
+ // =============================================================================
236
+
237
+ export const WithFormName: Story = {
238
+ args: {
239
+ label: 'Brand Color',
240
+ name: 'brand_color',
241
+ defaultValue: '#7c3aed',
242
+ description: 'This color will be submitted as a hidden form field named "brand_color".',
243
+ },
244
+ };
245
+
246
+ // =============================================================================
247
+ // All Sizes Comparison
248
+ // =============================================================================
249
+
250
+ function AllSizesExample() {
251
+ return (
252
+ <div className="flex flex-col gap-6">
253
+ <ColorPicker label="Small" size="sm" mode="advanced" defaultValue="#ef4444" />
254
+ <ColorPicker label="Default" size="default" mode="advanced" defaultValue="#3b82f6" />
255
+ <ColorPicker label="Large" size="lg" mode="advanced" defaultValue="#22c55e" />
256
+ </div>
257
+ );
258
+ }
259
+
260
+ export const AllSizes: Story = {
261
+ render: () => <AllSizesExample />,
262
+ };
263
+
264
+ // =============================================================================
265
+ // All Modes Comparison
266
+ // =============================================================================
267
+
268
+ function AllModesExample() {
269
+ return (
270
+ <div className="flex flex-col gap-8">
271
+ <div>
272
+ <h3 className="text-sm font-medium mb-2 text-[var(--content-foreground)]">Swatch Only</h3>
273
+ <ColorPicker mode="swatch" defaultValue="#ff0000" />
274
+ </div>
275
+ <div>
276
+ <h3 className="text-sm font-medium mb-2 text-[var(--content-foreground)]">Advanced Only</h3>
277
+ <ColorPicker mode="advanced" defaultValue="#3b82f6" />
278
+ </div>
279
+ <div>
280
+ <h3 className="text-sm font-medium mb-2 text-[var(--content-foreground)]">Both (Default)</h3>
281
+ <ColorPicker mode="both" defaultValue="#7c3aed" />
282
+ </div>
283
+ </div>
284
+ );
285
+ }
286
+
287
+ export const AllModes: Story = {
288
+ render: () => <AllModesExample />,
289
+ };