@tribepad/themis 1.0.5 → 1.0.7

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 (59) hide show
  1. package/dist/elements/MatrixGrid/MatrixGrid.d.ts +31 -0
  2. package/dist/elements/MatrixGrid/MatrixGrid.d.ts.map +1 -0
  3. package/dist/elements/MatrixGrid/MatrixGrid.styles.d.ts +48 -0
  4. package/dist/elements/MatrixGrid/MatrixGrid.styles.d.ts.map +1 -0
  5. package/dist/elements/MatrixGrid/MatrixGrid.types.d.ts +75 -0
  6. package/dist/elements/MatrixGrid/MatrixGrid.types.d.ts.map +1 -0
  7. package/dist/elements/MatrixGrid/index.d.ts +5 -0
  8. package/dist/elements/MatrixGrid/index.d.ts.map +1 -0
  9. package/dist/elements/MatrixGrid/index.js +3 -0
  10. package/dist/elements/MatrixGrid/index.js.map +1 -0
  11. package/dist/elements/MatrixGrid/index.mjs +3 -0
  12. package/dist/elements/MatrixGrid/index.mjs.map +1 -0
  13. package/dist/elements/RatingScale/RatingScale.d.ts +32 -0
  14. package/dist/elements/RatingScale/RatingScale.d.ts.map +1 -0
  15. package/dist/elements/RatingScale/RatingScale.styles.d.ts +52 -0
  16. package/dist/elements/RatingScale/RatingScale.styles.d.ts.map +1 -0
  17. package/dist/elements/RatingScale/RatingScale.types.d.ts +73 -0
  18. package/dist/elements/RatingScale/RatingScale.types.d.ts.map +1 -0
  19. package/dist/elements/RatingScale/index.d.ts +5 -0
  20. package/dist/elements/RatingScale/index.d.ts.map +1 -0
  21. package/dist/elements/RatingScale/index.js +3 -0
  22. package/dist/elements/RatingScale/index.js.map +1 -0
  23. package/dist/elements/RatingScale/index.mjs +3 -0
  24. package/dist/elements/RatingScale/index.mjs.map +1 -0
  25. package/dist/elements/SituationalJudgement/SituationalJudgement.d.ts +36 -0
  26. package/dist/elements/SituationalJudgement/SituationalJudgement.d.ts.map +1 -0
  27. package/dist/elements/SituationalJudgement/SituationalJudgement.styles.d.ts +19 -0
  28. package/dist/elements/SituationalJudgement/SituationalJudgement.styles.d.ts.map +1 -0
  29. package/dist/elements/SituationalJudgement/SituationalJudgement.types.d.ts +67 -0
  30. package/dist/elements/SituationalJudgement/SituationalJudgement.types.d.ts.map +1 -0
  31. package/dist/elements/SituationalJudgement/index.d.ts +5 -0
  32. package/dist/elements/SituationalJudgement/index.d.ts.map +1 -0
  33. package/dist/elements/SituationalJudgement/index.js +3 -0
  34. package/dist/elements/SituationalJudgement/index.js.map +1 -0
  35. package/dist/elements/SituationalJudgement/index.mjs +3 -0
  36. package/dist/elements/SituationalJudgement/index.mjs.map +1 -0
  37. package/dist/elements/Tabs/Tabs.d.ts +2 -2
  38. package/dist/elements/Tabs/Tabs.d.ts.map +1 -1
  39. package/dist/elements/Tabs/Tabs.types.d.ts +3 -0
  40. package/dist/elements/Tabs/Tabs.types.d.ts.map +1 -1
  41. package/dist/elements/Tabs/index.js +1 -1
  42. package/dist/elements/Tabs/index.js.map +1 -1
  43. package/dist/elements/Tabs/index.mjs +1 -1
  44. package/dist/elements/Tabs/index.mjs.map +1 -1
  45. package/dist/elements/index.d.ts +6 -0
  46. package/dist/elements/index.d.ts.map +1 -1
  47. package/dist/elements/index.js +1 -1
  48. package/dist/elements/index.js.map +1 -1
  49. package/dist/elements/index.mjs +1 -1
  50. package/dist/elements/index.mjs.map +1 -1
  51. package/dist/index.js +2 -2
  52. package/dist/index.js.map +1 -1
  53. package/dist/index.mjs +2 -2
  54. package/dist/index.mjs.map +1 -1
  55. package/package.json +15 -15
  56. package/src/elements/MatrixGrid/MatrixGrid.stories.tsx +292 -0
  57. package/src/elements/RatingScale/RatingScale.stories.tsx +379 -0
  58. package/src/elements/SituationalJudgement/SituationalJudgement.stories.tsx +305 -0
  59. package/src/elements/Tabs/Tabs.stories.tsx +231 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tribepad/themis",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Accessible React component library built on React Aria primitives",
5
5
  "author": "Tribepad <mbasford@tribepad.com>",
6
6
  "license": "MIT",
@@ -130,38 +130,38 @@
130
130
  "react-aria": "^3.35.0",
131
131
  "react-aria-components": "^1.5.0",
132
132
  "react-stately": "^3.33.0",
133
- "tailwind-merge": "^3.4.0"
133
+ "tailwind-merge": "^3.5.0"
134
134
  },
135
135
  "devDependencies": {
136
- "@eslint/js": "^9.0.0",
136
+ "@eslint/js": "^9.39.3",
137
137
  "@size-limit/preset-small-lib": "^11.0.0",
138
- "@storybook/addon-a11y": "^10.2.8",
139
- "@storybook/react-vite": "^10.2.8",
140
- "@tailwindcss/vite": "^4.1.18",
138
+ "@storybook/addon-a11y": "^10.2.10",
139
+ "@storybook/react-vite": "^10.2.10",
140
+ "@tailwindcss/vite": "^4.2.0",
141
141
  "@testing-library/jest-dom": "^6.0.0",
142
142
  "@testing-library/react": "^16.0.0",
143
143
  "@testing-library/user-event": "^14.0.0",
144
- "@types/node": "^25.2.2",
145
- "@types/react": "^19.0.0",
144
+ "@types/node": "^25.3.5",
145
+ "@types/react": "^19.2.14",
146
146
  "@types/react-dom": "^19.0.0",
147
- "@typescript-eslint/eslint-plugin": "^8.0.0",
148
- "@typescript-eslint/parser": "^8.0.0",
149
- "@vitejs/plugin-react": "^5.1.3",
147
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
148
+ "@typescript-eslint/parser": "^8.56.1",
149
+ "@vitejs/plugin-react": "^5.1.4",
150
150
  "@vitest/coverage-v8": "^4.0.0",
151
151
  "eslint": "^9.0.0",
152
152
  "eslint-plugin-jsx-a11y": "^6.10.2",
153
153
  "globals": "^17.3.0",
154
- "happy-dom": "^20.5.3",
154
+ "happy-dom": "^20.7.0",
155
155
  "jest-axe": "^10.0.0",
156
- "jsdom": "^28.0.0",
156
+ "jsdom": "^28.1.0",
157
157
  "lucide-react": ">=0.400.0",
158
158
  "react": "^19.0.0",
159
159
  "react-dom": "^19.0.0",
160
160
  "size-limit": "^11.0.0",
161
- "storybook": "^10.2.8",
161
+ "storybook": "^10.2.10",
162
162
  "tsup": "^8.0.0",
163
163
  "tsx": "^4.0.0",
164
- "typescript": "^5.6.0",
164
+ "typescript": "^5.9.3",
165
165
  "vitest": "^4.0.18",
166
166
  "zod": "^4.3.6"
167
167
  },
@@ -0,0 +1,292 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { MatrixGrid } from './MatrixGrid';
4
+
5
+ const LIKERT_COLUMNS = [
6
+ { id: 'sd', label: 'Strongly Disagree' },
7
+ { id: 'd', label: 'Disagree' },
8
+ { id: 'n', label: 'Neutral' },
9
+ { id: 'a', label: 'Agree' },
10
+ { id: 'sa', label: 'Strongly Agree' },
11
+ ];
12
+
13
+ const LIKERT_ROWS = [
14
+ { id: 'q1', label: 'The product meets my needs' },
15
+ { id: 'q2', label: 'The product is easy to use' },
16
+ { id: 'q3', label: 'The product is reliable' },
17
+ ];
18
+
19
+ const meta = {
20
+ title: 'Elements/MatrixGrid',
21
+ component: MatrixGrid,
22
+ parameters: {
23
+ layout: 'centered',
24
+ docs: {
25
+ description: {
26
+ component:
27
+ 'Grid-style survey question with rows (statements) and columns (rating options). Each row has a single radio selection. Built with role="grid" ARIA pattern for 2D keyboard navigation.',
28
+ },
29
+ },
30
+ },
31
+ tags: ['autodocs'],
32
+ argTypes: {
33
+ size: {
34
+ control: 'select',
35
+ options: ['sm', 'default', 'lg'],
36
+ description: 'Component size',
37
+ table: { defaultValue: { summary: 'default' } },
38
+ },
39
+ isDisabled: { control: 'boolean' },
40
+ isReadOnly: { control: 'boolean' },
41
+ isRequired: { control: 'boolean' },
42
+ isInvalid: { control: 'boolean' },
43
+ label: { control: 'text' },
44
+ description: { control: 'text' },
45
+ errorMessage: { control: 'text' },
46
+ },
47
+ } satisfies Meta<typeof MatrixGrid>;
48
+
49
+ export default meta;
50
+ type Story = StoryObj<typeof meta>;
51
+
52
+ // =============================================================================
53
+ // Default
54
+ // =============================================================================
55
+
56
+ export const Default: Story = {
57
+ args: {
58
+ label: 'Product Evaluation',
59
+ rows: LIKERT_ROWS,
60
+ columns: LIKERT_COLUMNS,
61
+ },
62
+ };
63
+
64
+ // =============================================================================
65
+ // Large Matrix
66
+ // =============================================================================
67
+
68
+ export const LargeMatrix: Story = {
69
+ args: {
70
+ label: 'Comprehensive Service Assessment',
71
+ rows: [
72
+ { id: 'q1', label: 'Quality of service' },
73
+ { id: 'q2', label: 'Value for money' },
74
+ { id: 'q3', label: 'Staff friendliness' },
75
+ { id: 'q4', label: 'Wait time' },
76
+ { id: 'q5', label: 'Cleanliness of facility' },
77
+ { id: 'q6', label: 'Ease of scheduling' },
78
+ { id: 'q7', label: 'Communication clarity' },
79
+ { id: 'q8', label: 'Follow-up care' },
80
+ ],
81
+ columns: [
82
+ { id: 'vp', label: 'Very Poor' },
83
+ { id: 'p', label: 'Poor' },
84
+ { id: 'f', label: 'Fair' },
85
+ { id: 'g', label: 'Good' },
86
+ { id: 'vg', label: 'Very Good' },
87
+ { id: 'e', label: 'Excellent' },
88
+ { id: 'na', label: 'N/A' },
89
+ ],
90
+ },
91
+ parameters: {
92
+ docs: {
93
+ description: { story: 'Large matrix with 8 rows and 7 columns. Scrolls horizontally on small screens.' },
94
+ },
95
+ },
96
+ };
97
+
98
+ // =============================================================================
99
+ // Sizes
100
+ // =============================================================================
101
+
102
+ export const AllSizes: Story = {
103
+ render: () => (
104
+ <div className="flex flex-col gap-8">
105
+ <MatrixGrid
106
+ label="Small"
107
+ rows={LIKERT_ROWS.slice(0, 2)}
108
+ columns={LIKERT_COLUMNS}
109
+ size="sm"
110
+ />
111
+ <MatrixGrid
112
+ label="Default"
113
+ rows={LIKERT_ROWS.slice(0, 2)}
114
+ columns={LIKERT_COLUMNS}
115
+ size="default"
116
+ />
117
+ <MatrixGrid
118
+ label="Large"
119
+ rows={LIKERT_ROWS.slice(0, 2)}
120
+ columns={LIKERT_COLUMNS}
121
+ size="lg"
122
+ />
123
+ </div>
124
+ ),
125
+ };
126
+
127
+ // =============================================================================
128
+ // States
129
+ // =============================================================================
130
+
131
+ export const Disabled: Story = {
132
+ args: {
133
+ label: 'Survey (Closed)',
134
+ rows: LIKERT_ROWS,
135
+ columns: LIKERT_COLUMNS,
136
+ value: { q1: 'a', q2: 'sa', q3: 'n' },
137
+ isDisabled: true,
138
+ },
139
+ };
140
+
141
+ export const ReadOnly: Story = {
142
+ args: {
143
+ label: 'Previous Responses',
144
+ rows: LIKERT_ROWS,
145
+ columns: LIKERT_COLUMNS,
146
+ value: { q1: 'sa', q2: 'a', q3: 'n' },
147
+ isReadOnly: true,
148
+ },
149
+ };
150
+
151
+ export const Required: Story = {
152
+ args: {
153
+ label: 'Required Assessment',
154
+ rows: LIKERT_ROWS,
155
+ columns: LIKERT_COLUMNS,
156
+ isRequired: true,
157
+ },
158
+ };
159
+
160
+ export const Invalid: Story = {
161
+ args: {
162
+ label: 'Assessment',
163
+ rows: LIKERT_ROWS,
164
+ columns: LIKERT_COLUMNS,
165
+ isInvalid: true,
166
+ errorMessage: 'Please answer all rows before continuing.',
167
+ },
168
+ };
169
+
170
+ export const WithDescription: Story = {
171
+ args: {
172
+ label: 'Training Effectiveness',
173
+ description: 'Rate each aspect of the training programme you attended.',
174
+ rows: LIKERT_ROWS,
175
+ columns: LIKERT_COLUMNS,
176
+ },
177
+ };
178
+
179
+ // =============================================================================
180
+ // Controlled Example
181
+ // =============================================================================
182
+
183
+ export const ControlledExample: Story = {
184
+ render: () => {
185
+ const [value, setValue] = useState<Record<string, string | null>>({});
186
+ return (
187
+ <div className="max-w-2xl">
188
+ <MatrixGrid
189
+ label="Controlled Matrix"
190
+ rows={LIKERT_ROWS}
191
+ columns={LIKERT_COLUMNS}
192
+ value={value}
193
+ onChange={setValue}
194
+ />
195
+ <pre className="mt-4 rounded bg-[var(--muted)] p-3 text-xs">
196
+ {JSON.stringify(value, null, 2)}
197
+ </pre>
198
+ </div>
199
+ );
200
+ },
201
+ parameters: {
202
+ docs: {
203
+ description: { story: 'Controlled component with state displayed below.' },
204
+ },
205
+ },
206
+ };
207
+
208
+ // =============================================================================
209
+ // Real-world Examples
210
+ // =============================================================================
211
+
212
+ export const SatisfactionSurvey: Story = {
213
+ render: () => {
214
+ const [value, setValue] = useState<Record<string, string | null>>({});
215
+ const rows = [
216
+ { id: 'onboarding', label: 'Onboarding process' },
217
+ { id: 'tools', label: 'Tools and resources' },
218
+ { id: 'management', label: 'Management support' },
219
+ { id: 'culture', label: 'Company culture' },
220
+ { id: 'growth', label: 'Growth opportunities' },
221
+ ];
222
+ const columns = [
223
+ { id: 'vs', label: 'Very Unsatisfied' },
224
+ { id: 's', label: 'Unsatisfied' },
225
+ { id: 'n', label: 'Neutral' },
226
+ { id: 'st', label: 'Satisfied' },
227
+ { id: 'vst', label: 'Very Satisfied' },
228
+ ];
229
+ const answered = Object.keys(value).length;
230
+ return (
231
+ <div className="max-w-2xl rounded-lg border border-[var(--border)] bg-[var(--content-background)] p-6">
232
+ <MatrixGrid
233
+ label="Employee Satisfaction Survey"
234
+ description="Please rate your satisfaction with each aspect of your role."
235
+ rows={rows}
236
+ columns={columns}
237
+ value={value}
238
+ onChange={setValue}
239
+ isRequired
240
+ />
241
+ <p className="mt-3 text-sm text-[var(--muted-foreground)]">
242
+ {answered} of {rows.length} answered
243
+ </p>
244
+ </div>
245
+ );
246
+ },
247
+ parameters: {
248
+ docs: {
249
+ description: { story: 'Employee satisfaction survey with progress indicator.' },
250
+ },
251
+ },
252
+ };
253
+
254
+ export const EmployeeFeedback: Story = {
255
+ args: {
256
+ label: 'Peer Feedback',
257
+ description: 'Rate your colleague on the following competencies.',
258
+ rows: [
259
+ { id: 'comm', label: 'Communication' },
260
+ { id: 'team', label: 'Teamwork' },
261
+ { id: 'init', label: 'Initiative' },
262
+ { id: 'quality', label: 'Quality of work' },
263
+ { id: 'time', label: 'Time management' },
264
+ ],
265
+ columns: [
266
+ { id: 'ni', label: 'Needs Improvement' },
267
+ { id: 'me', label: 'Meets Expectations' },
268
+ { id: 'ee', label: 'Exceeds Expectations' },
269
+ { id: 'ex', label: 'Exceptional' },
270
+ ],
271
+ isRequired: true,
272
+ },
273
+ parameters: {
274
+ docs: {
275
+ description: { story: '360-degree feedback form with 4-point competency scale.' },
276
+ },
277
+ },
278
+ };
279
+
280
+ export const CustomStyling: Story = {
281
+ args: {
282
+ label: 'Custom Styled Grid',
283
+ rows: LIKERT_ROWS.slice(0, 2),
284
+ columns: LIKERT_COLUMNS.slice(0, 3),
285
+ className: 'p-4 rounded-lg border border-[var(--border)] bg-[var(--content-background)]',
286
+ },
287
+ parameters: {
288
+ docs: {
289
+ description: { story: 'Demonstrates custom className pass-through for container styling.' },
290
+ },
291
+ },
292
+ };