@tribepad/themis 1.1.3 → 1.2.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/elements/Wizard/Wizard.d.ts +35 -0
  3. package/dist/elements/Wizard/Wizard.d.ts.map +1 -0
  4. package/dist/elements/Wizard/Wizard.styles.d.ts +43 -0
  5. package/dist/elements/Wizard/Wizard.styles.d.ts.map +1 -0
  6. package/dist/elements/Wizard/Wizard.types.d.ts +222 -0
  7. package/dist/elements/Wizard/Wizard.types.d.ts.map +1 -0
  8. package/dist/elements/Wizard/WizardContent.d.ts +14 -0
  9. package/dist/elements/Wizard/WizardContent.d.ts.map +1 -0
  10. package/dist/elements/Wizard/WizardContext.d.ts +16 -0
  11. package/dist/elements/Wizard/WizardContext.d.ts.map +1 -0
  12. package/dist/elements/Wizard/WizardLayout.d.ts +19 -0
  13. package/dist/elements/Wizard/WizardLayout.d.ts.map +1 -0
  14. package/dist/elements/Wizard/WizardMobileProgress.d.ts +16 -0
  15. package/dist/elements/Wizard/WizardMobileProgress.d.ts.map +1 -0
  16. package/dist/elements/Wizard/WizardNavigation.d.ts +14 -0
  17. package/dist/elements/Wizard/WizardNavigation.d.ts.map +1 -0
  18. package/dist/elements/Wizard/WizardStep.d.ts +12 -0
  19. package/dist/elements/Wizard/WizardStep.d.ts.map +1 -0
  20. package/dist/elements/Wizard/WizardStepper.d.ts +12 -0
  21. package/dist/elements/Wizard/WizardStepper.d.ts.map +1 -0
  22. package/dist/elements/Wizard/index.d.ts +12 -0
  23. package/dist/elements/Wizard/index.d.ts.map +1 -0
  24. package/dist/elements/Wizard/index.js +3 -0
  25. package/dist/elements/Wizard/index.js.map +1 -0
  26. package/dist/elements/Wizard/index.mjs +3 -0
  27. package/dist/elements/Wizard/index.mjs.map +1 -0
  28. package/dist/elements/index.d.ts +2 -0
  29. package/dist/elements/index.d.ts.map +1 -1
  30. package/dist/elements/index.js +1 -1
  31. package/dist/elements/index.js.map +1 -1
  32. package/dist/elements/index.mjs +1 -1
  33. package/dist/elements/index.mjs.map +1 -1
  34. package/dist/index.js +2 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +2 -2
  37. package/dist/index.mjs.map +1 -1
  38. package/package.json +1 -1
  39. package/src/elements/Wizard/Wizard.stories.tsx +285 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tribepad/themis",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
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,285 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState, type ReactElement } from 'react';
3
+ import { Image, Palette, Sparkles, Upload, CheckCircle } from 'lucide-react';
4
+ import { Wizard } from './Wizard';
5
+ import type { WizardStepDescriptor } from './Wizard.types';
6
+
7
+ const STEPS: WizardStepDescriptor[] = [
8
+ { id: 'welcome', label: 'Welcome', description: 'Getting started' },
9
+ { id: 'logo', label: 'Logo', description: 'Upload your company logo' },
10
+ { id: 'colours', label: 'Colours', description: 'Choose your brand colours' },
11
+ { id: 'image', label: 'Login image', description: 'Upload a login image' },
12
+ { id: 'done', label: 'All done' },
13
+ ];
14
+
15
+ const meta = {
16
+ title: 'Elements/Wizard',
17
+ component: Wizard,
18
+ parameters: {
19
+ layout: 'fullscreen',
20
+ docs: {
21
+ description: {
22
+ component:
23
+ 'Linear multi-step wizard with WCAG 2.2 AAA compliance. Compound components (Wizard.Stepper, Wizard.Content, Wizard.Step, Wizard.Navigation, Wizard.MobileProgress, Wizard.Layout) share state via context. Steps keyed by `id` (not positional index). Polite live region announces "Step N of M"; assertive region handles errors.',
24
+ },
25
+ },
26
+ },
27
+ tags: ['autodocs'],
28
+ } satisfies Meta<typeof Wizard>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ function DefaultHarness(): ReactElement {
34
+ const [step, setStep] = useState(0);
35
+ return (
36
+ <div className="h-screen">
37
+ <Wizard
38
+ currentStep={step}
39
+ steps={STEPS}
40
+ onStepChange={(ev): void => setStep(ev.index)}
41
+ >
42
+ <Wizard.Layout
43
+ stepper={
44
+ <Wizard.Stepper sectionLabel="Branding" sectionNumber={1} totalSections={3} />
45
+ }
46
+ helpText="All steps optional — everything can be revisited later in ATS Settings."
47
+ >
48
+ <Wizard.MobileProgress />
49
+ <Wizard.Content>
50
+ <Wizard.Step id="welcome" icon={<Sparkles />}>
51
+ <p>Welcome to the branding setup. We&apos;ll guide you through a few steps.</p>
52
+ </Wizard.Step>
53
+ <Wizard.Step id="logo" icon={<Image />}>
54
+ <p>Upload your logo. SVG or PNG recommended.</p>
55
+ </Wizard.Step>
56
+ <Wizard.Step id="colours" icon={<Palette />}>
57
+ <p>Pick your primary and accent colours.</p>
58
+ </Wizard.Step>
59
+ <Wizard.Step id="image" icon={<Upload />}>
60
+ <p>Upload an image for the login screen.</p>
61
+ </Wizard.Step>
62
+ <Wizard.Step id="done" icon={<CheckCircle />}>
63
+ <p>That&apos;s it! You can revisit any step later.</p>
64
+ </Wizard.Step>
65
+ </Wizard.Content>
66
+ <Wizard.Navigation
67
+ showSkip
68
+ labels={{
69
+ start: "Let's go",
70
+ next: 'Next',
71
+ finish: 'Finish setup',
72
+ back: 'Back',
73
+ skip: 'Skip for now',
74
+ }}
75
+ />
76
+ </Wizard.Layout>
77
+ </Wizard>
78
+ </div>
79
+ );
80
+ }
81
+
82
+ export const Default: Story = {
83
+ render: () => <DefaultHarness />,
84
+ };
85
+
86
+ function WithPreviewHarness(): ReactElement {
87
+ const [step, setStep] = useState(1);
88
+ return (
89
+ <div className="h-screen">
90
+ <Wizard
91
+ currentStep={step}
92
+ steps={STEPS}
93
+ onStepChange={(ev): void => setStep(ev.index)}
94
+ >
95
+ <Wizard.Layout
96
+ stepper={
97
+ <Wizard.Stepper sectionLabel="Branding" sectionNumber={1} totalSections={3} />
98
+ }
99
+ preview={
100
+ <div>
101
+ <h4 className="text-sm font-semibold text-[var(--content-foreground)]">
102
+ Live preview
103
+ </h4>
104
+ <p className="mt-2 text-xs text-[var(--menu-muted)]">
105
+ Decorative aside — not exposed to assistive tech.
106
+ </p>
107
+ </div>
108
+ }
109
+ helpText="All steps optional — everything can be revisited later."
110
+ >
111
+ <Wizard.MobileProgress />
112
+ <Wizard.Content>
113
+ {STEPS.map((s) => (
114
+ <Wizard.Step key={s.id} id={s.id}>
115
+ <p>{s.label} step content</p>
116
+ </Wizard.Step>
117
+ ))}
118
+ </Wizard.Content>
119
+ <Wizard.Navigation
120
+ showSkip
121
+ labels={{ start: "Let's go", finish: 'Finish setup' }}
122
+ />
123
+ </Wizard.Layout>
124
+ </Wizard>
125
+ </div>
126
+ );
127
+ }
128
+
129
+ export const WithPreview: Story = {
130
+ render: () => <WithPreviewHarness />,
131
+ };
132
+
133
+ function MobileHarness(): ReactElement {
134
+ const [step, setStep] = useState(1);
135
+ const mobileSteps = STEPS.slice(0, 4);
136
+ // Override `lg:hidden` on MobileProgress so it renders at any viewport for docs.
137
+ // In real usage, the stepper takes over at lg+ and MobileProgress stays hidden.
138
+ return (
139
+ <div style={{ maxWidth: 420, margin: '0 auto' }} className="rounded-lg border border-[var(--border)] bg-[var(--content-background)]">
140
+ <Wizard
141
+ currentStep={step}
142
+ steps={mobileSteps}
143
+ onStepChange={(ev): void => setStep(ev.index)}
144
+ >
145
+ <Wizard.MobileProgress className="lg:flex" />
146
+ <div className="px-4 pb-4">
147
+ <Wizard.Content>
148
+ {mobileSteps.map((s) => (
149
+ <Wizard.Step key={s.id} id={s.id}>
150
+ <p className="text-sm text-[var(--menu-muted)]">{s.label} step body. Narrow viewport: the progress dots above replace the vertical stepper.</p>
151
+ </Wizard.Step>
152
+ ))}
153
+ </Wizard.Content>
154
+ <Wizard.Navigation showSkip />
155
+ </div>
156
+ </Wizard>
157
+ </div>
158
+ );
159
+ }
160
+
161
+ export const Mobile: Story = {
162
+ render: () => <MobileHarness />,
163
+ parameters: {
164
+ docs: {
165
+ description: {
166
+ story:
167
+ 'At <1024px viewports, the vertical `Wizard.Stepper` hides and `Wizard.MobileProgress` replaces it with a role="progressbar" dot indicator. aria-valuetext announces "Step N of M: Title".',
168
+ },
169
+ },
170
+ },
171
+ };
172
+
173
+ function LoadingHarness(): ReactElement {
174
+ return (
175
+ <div className="h-screen">
176
+ <Wizard
177
+ currentStep={1}
178
+ steps={STEPS}
179
+ onStepChange={(): void => undefined}
180
+ isLoading
181
+ >
182
+ <Wizard.Stepper sectionLabel="Branding" sectionNumber={1} totalSections={3} />
183
+ <Wizard.Content>
184
+ {STEPS.map((s) => (
185
+ <Wizard.Step key={s.id} id={s.id}>
186
+ <p>{s.label} body — saving…</p>
187
+ </Wizard.Step>
188
+ ))}
189
+ </Wizard.Content>
190
+ <Wizard.Navigation />
191
+ </Wizard>
192
+ </div>
193
+ );
194
+ }
195
+
196
+ export const Loading: Story = {
197
+ render: () => <LoadingHarness />,
198
+ };
199
+
200
+ function ErrorsHarness(): ReactElement {
201
+ const [step, setStep] = useState(1);
202
+ return (
203
+ <div className="h-screen">
204
+ <Wizard
205
+ currentStep={step}
206
+ steps={STEPS}
207
+ onStepChange={(ev): void => setStep(ev.index)}
208
+ errors={['Email is required', 'Password is too short']}
209
+ >
210
+ <Wizard.Content>
211
+ {STEPS.map((s) => (
212
+ <Wizard.Step key={s.id} id={s.id}>
213
+ <p>{s.label} body</p>
214
+ </Wizard.Step>
215
+ ))}
216
+ </Wizard.Content>
217
+ <Wizard.Navigation />
218
+ </Wizard>
219
+ </div>
220
+ );
221
+ }
222
+
223
+ export const WithErrors: Story = {
224
+ render: () => <ErrorsHarness />,
225
+ };
226
+
227
+ function AllDoneHarness(): ReactElement {
228
+ return (
229
+ <div className="h-screen">
230
+ <Wizard
231
+ currentStep={STEPS.length - 1}
232
+ steps={STEPS}
233
+ onStepChange={(): void => undefined}
234
+ >
235
+ <Wizard.Stepper sectionLabel="Branding" sectionNumber={1} totalSections={3} />
236
+ <Wizard.Content>
237
+ {STEPS.map((s) => (
238
+ <Wizard.Step
239
+ key={s.id}
240
+ id={s.id}
241
+ icon={s.id === 'done' ? <CheckCircle /> : undefined}
242
+ >
243
+ <p>{s.label} body</p>
244
+ </Wizard.Step>
245
+ ))}
246
+ </Wizard.Content>
247
+ <Wizard.Navigation />
248
+ </Wizard>
249
+ </div>
250
+ );
251
+ }
252
+
253
+ export const AllDone: Story = {
254
+ render: () => <AllDoneHarness />,
255
+ };
256
+
257
+ function RTLHarness(): ReactElement {
258
+ const [step, setStep] = useState(1);
259
+ return (
260
+ <div dir="rtl" className="h-screen">
261
+ <Wizard
262
+ currentStep={step}
263
+ steps={STEPS.slice(0, 4)}
264
+ onStepChange={(ev): void => setStep(ev.index)}
265
+ >
266
+ <Wizard.Stepper sectionLabel="الإعداد" sectionNumber={1} totalSections={3} />
267
+ <Wizard.Content>
268
+ {STEPS.slice(0, 4).map((s) => (
269
+ <Wizard.Step key={s.id} id={s.id}>
270
+ <p>{s.label} body (RTL)</p>
271
+ </Wizard.Step>
272
+ ))}
273
+ </Wizard.Content>
274
+ <Wizard.Navigation
275
+ labels={{ back: 'رجوع', next: 'التالي', skip: 'تخطي' }}
276
+ showSkip
277
+ />
278
+ </Wizard>
279
+ </div>
280
+ );
281
+ }
282
+
283
+ export const RTL: Story = {
284
+ render: () => <RTLHarness />,
285
+ };