@intellectif/lk-react 1.0.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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-5HVUKXF3.js +28 -0
  3. package/dist/chunk-5HVUKXF3.js.map +1 -0
  4. package/dist/chunk-5KW7TFX3.js +240 -0
  5. package/dist/chunk-5KW7TFX3.js.map +1 -0
  6. package/dist/chunk-6OBRYL4C.cjs +84 -0
  7. package/dist/chunk-6OBRYL4C.cjs.map +1 -0
  8. package/dist/chunk-B3FUUKZ2.js +91 -0
  9. package/dist/chunk-B3FUUKZ2.js.map +1 -0
  10. package/dist/chunk-CPF2JJG6.cjs +96 -0
  11. package/dist/chunk-CPF2JJG6.cjs.map +1 -0
  12. package/dist/chunk-HD2AIQRD.cjs +30 -0
  13. package/dist/chunk-HD2AIQRD.cjs.map +1 -0
  14. package/dist/chunk-IZNMQSQP.js +65 -0
  15. package/dist/chunk-IZNMQSQP.js.map +1 -0
  16. package/dist/chunk-L3EV5LIX.js +77 -0
  17. package/dist/chunk-L3EV5LIX.js.map +1 -0
  18. package/dist/chunk-O3GWWJFS.cjs +242 -0
  19. package/dist/chunk-O3GWWJFS.cjs.map +1 -0
  20. package/dist/chunk-QBA6UXMS.cjs +160 -0
  21. package/dist/chunk-QBA6UXMS.cjs.map +1 -0
  22. package/dist/chunk-RI53A36N.cjs +98 -0
  23. package/dist/chunk-RI53A36N.cjs.map +1 -0
  24. package/dist/chunk-TVK3SVV6.cjs +67 -0
  25. package/dist/chunk-TVK3SVV6.cjs.map +1 -0
  26. package/dist/chunk-W2L66WHW.js +158 -0
  27. package/dist/chunk-W2L66WHW.js.map +1 -0
  28. package/dist/chunk-ZPD7BGCF.js +96 -0
  29. package/dist/chunk-ZPD7BGCF.js.map +1 -0
  30. package/dist/components/ActivitySequence.cjs +16 -0
  31. package/dist/components/ActivitySequence.cjs.map +1 -0
  32. package/dist/components/ActivitySequence.d.cts +25 -0
  33. package/dist/components/ActivitySequence.d.ts +25 -0
  34. package/dist/components/ActivitySequence.js +7 -0
  35. package/dist/components/ActivitySequence.js.map +1 -0
  36. package/dist/components/FillInTheBlanks.cjs +14 -0
  37. package/dist/components/FillInTheBlanks.cjs.map +1 -0
  38. package/dist/components/FillInTheBlanks.d.cts +21 -0
  39. package/dist/components/FillInTheBlanks.d.ts +21 -0
  40. package/dist/components/FillInTheBlanks.js +5 -0
  41. package/dist/components/FillInTheBlanks.js.map +1 -0
  42. package/dist/components/MultipleChoice.cjs +14 -0
  43. package/dist/components/MultipleChoice.cjs.map +1 -0
  44. package/dist/components/MultipleChoice.d.cts +12 -0
  45. package/dist/components/MultipleChoice.d.ts +12 -0
  46. package/dist/components/MultipleChoice.js +5 -0
  47. package/dist/components/MultipleChoice.js.map +1 -0
  48. package/dist/hooks/useActivityState.cjs +12 -0
  49. package/dist/hooks/useActivityState.cjs.map +1 -0
  50. package/dist/hooks/useActivityState.d.cts +22 -0
  51. package/dist/hooks/useActivityState.d.ts +22 -0
  52. package/dist/hooks/useActivityState.js +3 -0
  53. package/dist/hooks/useActivityState.js.map +1 -0
  54. package/dist/hooks/useXAPI.cjs +12 -0
  55. package/dist/hooks/useXAPI.cjs.map +1 -0
  56. package/dist/hooks/useXAPI.d.cts +15 -0
  57. package/dist/hooks/useXAPI.d.ts +15 -0
  58. package/dist/hooks/useXAPI.js +3 -0
  59. package/dist/hooks/useXAPI.js.map +1 -0
  60. package/dist/index.cjs +50 -0
  61. package/dist/index.cjs.map +1 -0
  62. package/dist/index.d.cts +10 -0
  63. package/dist/index.d.ts +10 -0
  64. package/dist/index.js +9 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/theme/ThemeProvider.cjs +24 -0
  67. package/dist/theme/ThemeProvider.cjs.map +1 -0
  68. package/dist/theme/ThemeProvider.d.cts +39 -0
  69. package/dist/theme/ThemeProvider.d.ts +39 -0
  70. package/dist/theme/ThemeProvider.js +3 -0
  71. package/dist/theme/ThemeProvider.js.map +1 -0
  72. package/dist/theme/defaults.css +50 -0
  73. package/dist/theme/skin.css +352 -0
  74. package/dist/types-iknDq5tf.d.cts +17 -0
  75. package/dist/types-iknDq5tf.d.ts +17 -0
  76. package/package.json +86 -0
@@ -0,0 +1,39 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ThemeTokens } from '@intellectif/lk-core';
3
+ import { ReactNode } from 'react';
4
+
5
+ /**
6
+ * Dark-mode colour overrides, merged over {@link defaultTheme} by
7
+ * `ThemeProvider`. Colours only — spacing/typography/shape/motion are
8
+ * theme-invariant. All pairs verified WCAG 2.2 AA against the dark surface.
9
+ */
10
+ declare const darkTheme: Partial<ThemeTokens>;
11
+
12
+ /**
13
+ * Canonical default theme token values. `defaults.css` mirrors these exactly.
14
+ * Palette is a neutral monochrome (ElevenLabs-like) so the SDK is brand-neutral
15
+ * out of the box; consumers rebrand via `ThemeProvider`. All colour pairs are
16
+ * verified to meet WCAG 2.2 AA: 4.5:1 for normal text, 3:1 for UI / focus ring
17
+ * (see theme/__tests__/contrast.test.ts).
18
+ */
19
+ declare const defaultTheme: ThemeTokens;
20
+
21
+ interface ThemeProviderProps {
22
+ /** Partial token overrides. When provided, dark auto-detection is disabled. */
23
+ theme?: Partial<ThemeTokens>;
24
+ children: ReactNode;
25
+ }
26
+ /**
27
+ * Provides theme tokens to descendant activity components as scoped inline CSS
28
+ * custom properties on a wrapper `<div>`, and via {@link useTheme}.
29
+ *
30
+ * Resolution: an explicit `theme` prop merges over {@link defaultTheme} (and
31
+ * suppresses dark auto-detect, per Req 13.5). With no `theme` prop, the OS
32
+ * `prefers-color-scheme: dark` preference auto-applies {@link darkTheme}.
33
+ * SSR-safe: the server snapshot is always light, so hydration never mismatches.
34
+ */
35
+ declare function ThemeProvider({ theme, children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
36
+ /** Returns the currently active theme tokens (defaults when no provider). */
37
+ declare function useTheme(): ThemeTokens;
38
+
39
+ export { ThemeProvider, type ThemeProviderProps, darkTheme, defaultTheme, useTheme };
@@ -0,0 +1,3 @@
1
+ export { ThemeProvider, darkTheme, defaultTheme, useTheme } from '../chunk-B3FUUKZ2.js';
2
+ //# sourceMappingURL=ThemeProvider.js.map
3
+ //# sourceMappingURL=ThemeProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"ThemeProvider.js"}
@@ -0,0 +1,50 @@
1
+ /*
2
+ * learning-kit default theme tokens.
3
+ *
4
+ * Tailwind-safety contract: this file contains ONLY :root custom-property
5
+ * declarations. No reset/normalize/preflight, no element selectors, no
6
+ * utility classes, no @layer/@apply. The --lk-* namespace is disjoint from
7
+ * Tailwind's --tw-* / --color-* / --spacing-*, so this is purely additive
8
+ * and cannot conflict with Tailwind preflight or consumer styles.
9
+ *
10
+ * Mirrors theme/tokens.ts (the canonical source). Keep in sync.
11
+ */
12
+ :root {
13
+ /* Colours — neutral monochrome (mirrors tokens.ts) */
14
+ --lk-color-primary: #18181b;
15
+ --lk-color-primary-hover: #27272a;
16
+ --lk-color-surface: #ffffff;
17
+ --lk-color-surface-raised: #fafafa;
18
+ --lk-color-border: #e4e4e7;
19
+ --lk-color-text: #18181b;
20
+ --lk-color-text-muted: #52525b;
21
+ --lk-color-success: #15803d;
22
+ --lk-color-error: #b91c1c;
23
+ --lk-color-warning: #b45309;
24
+ --lk-color-focus-ring: #18181b;
25
+
26
+ /* Spacing */
27
+ --lk-spacing-xs: 4px;
28
+ --lk-spacing-sm: 8px;
29
+ --lk-spacing-md: 16px;
30
+ --lk-spacing-lg: 24px;
31
+ --lk-spacing-xl: 32px;
32
+
33
+ /* Typography */
34
+ --lk-font-family-base: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
35
+ --lk-font-size-sm: 0.875rem;
36
+ --lk-font-size-base: 1rem;
37
+ --lk-font-size-lg: 1.125rem;
38
+ --lk-font-weight-normal: 400;
39
+ --lk-font-weight-bold: 700;
40
+ --lk-line-height-base: 1.5;
41
+
42
+ /* Shape */
43
+ --lk-radius-sm: 0.25rem;
44
+ --lk-radius-base: 0.5rem;
45
+ --lk-radius-lg: 0.75rem;
46
+
47
+ /* Motion */
48
+ --lk-transition-fast: 150ms ease;
49
+ --lk-transition-base: 250ms ease;
50
+ }
@@ -0,0 +1,352 @@
1
+ /*
2
+ * learning-kit OPTIONAL default skin — a slick, neutral monochrome look
3
+ * (ElevenLabs-like). Entirely token-driven, so `ThemeProvider` / dark mode
4
+ * restyle it for free.
5
+ *
6
+ * Override contract: every rule lives in the `lk-skin` CSS cascade layer.
7
+ * Unlayered author styles ALWAYS win over layered styles, so a consumer can
8
+ * restyle any `.lk-*` hook with plain CSS and no `!important`. Import order:
9
+ * import '@intellectif/lk-react/theme/defaults.css'; (tokens)
10
+ * import '@intellectif/lk-react/theme/skin.css'; (this — optional)
11
+ * This file is NOT imported by the components; it is opt-in and is kept
12
+ * separate from the tokens-only `defaults.css` (Tailwind-safety contract).
13
+ */
14
+
15
+ @layer lk-skin {
16
+ .lk-mc,
17
+ .lk-fib {
18
+ font-family: var(--lk-font-family-base);
19
+ font-size: var(--lk-font-size-base);
20
+ line-height: var(--lk-line-height-base);
21
+ color: var(--lk-color-text);
22
+ background: var(--lk-color-surface);
23
+ padding: var(--lk-spacing-lg);
24
+ border: 1px solid var(--lk-color-border);
25
+ border-radius: var(--lk-radius-lg);
26
+ }
27
+
28
+ .lk-mc *,
29
+ .lk-fib * {
30
+ box-sizing: border-box;
31
+ }
32
+
33
+ .lk-mc fieldset,
34
+ .lk-fib fieldset {
35
+ margin: 0;
36
+ padding: 0;
37
+ border: 0;
38
+ }
39
+
40
+ .lk-mc legend {
41
+ padding: 0;
42
+ margin-bottom: var(--lk-spacing-md);
43
+ font-size: var(--lk-font-size-lg);
44
+ font-weight: var(--lk-font-weight-bold);
45
+ }
46
+
47
+ /* ── Activity media (image / audio / video / embed) ──────────────────── */
48
+ .lk-media {
49
+ margin: 0 0 var(--lk-spacing-lg);
50
+ }
51
+
52
+ .lk-media-el {
53
+ display: block;
54
+ max-width: 100%;
55
+ height: auto;
56
+ border-radius: var(--lk-radius-base);
57
+ border: 1px solid var(--lk-color-border);
58
+ }
59
+
60
+ /* Responsive 16:9 frame for embedded players. */
61
+ .lk-media-embed {
62
+ position: relative;
63
+ width: 100%;
64
+ aspect-ratio: 16 / 9;
65
+ }
66
+
67
+ .lk-media-embed .lk-media-el {
68
+ position: absolute;
69
+ inset: 0;
70
+ width: 100%;
71
+ height: 100%;
72
+ }
73
+
74
+ /* ── Activity sequence (question-set pager) ──────────────────────────── */
75
+ .lk-seq-progress {
76
+ margin-bottom: var(--lk-spacing-sm);
77
+ font-size: var(--lk-font-size-sm);
78
+ font-weight: var(--lk-font-weight-bold);
79
+ color: var(--lk-color-text-muted);
80
+ }
81
+
82
+ .lk-seq-question:focus {
83
+ outline: none;
84
+ }
85
+
86
+ .lk-seq-nav {
87
+ display: flex;
88
+ justify-content: space-between;
89
+ gap: var(--lk-spacing-md);
90
+ margin-top: var(--lk-spacing-md);
91
+ }
92
+
93
+ .lk-seq-nav button {
94
+ padding: var(--lk-spacing-sm) var(--lk-spacing-lg);
95
+ font: inherit;
96
+ font-weight: var(--lk-font-weight-bold);
97
+ color: var(--lk-color-text);
98
+ background: var(--lk-color-surface);
99
+ border: 1px solid var(--lk-color-border);
100
+ border-radius: var(--lk-radius-base);
101
+ cursor: pointer;
102
+ transition: var(--lk-transition-fast);
103
+ }
104
+
105
+ .lk-seq-nav button:hover:not(:disabled) {
106
+ border-color: var(--lk-color-primary);
107
+ }
108
+
109
+ .lk-seq-nav button:disabled {
110
+ opacity: 0.5;
111
+ cursor: default;
112
+ }
113
+
114
+ /* ── Multiple choice options ─────────────────────────────────────────── */
115
+ .lk-mc-option {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: var(--lk-spacing-sm);
119
+ padding: var(--lk-spacing-md);
120
+ margin-bottom: var(--lk-spacing-sm);
121
+ border: 1px solid var(--lk-color-border);
122
+ border-radius: var(--lk-radius-base);
123
+ background: var(--lk-color-surface);
124
+ cursor: pointer;
125
+ transition: var(--lk-transition-fast);
126
+ }
127
+
128
+ .lk-mc-option:hover {
129
+ border-color: var(--lk-color-primary);
130
+ background: var(--lk-color-surface-raised);
131
+ }
132
+
133
+ .lk-mc-option:has(input:checked) {
134
+ border-color: var(--lk-color-primary);
135
+ box-shadow: inset 0 0 0 1px var(--lk-color-primary);
136
+ }
137
+
138
+ .lk-mc-option:has(input:disabled) {
139
+ cursor: default;
140
+ }
141
+
142
+ .lk-mc-option[data-correct="true"] {
143
+ border-color: var(--lk-color-success);
144
+ box-shadow: inset 0 0 0 1px var(--lk-color-success);
145
+ }
146
+
147
+ .lk-mc-option[data-correct="false"]:has(input:checked) {
148
+ border-color: var(--lk-color-error);
149
+ box-shadow: inset 0 0 0 1px var(--lk-color-error);
150
+ }
151
+
152
+ .lk-mc-option input {
153
+ accent-color: var(--lk-color-primary);
154
+ width: 1rem;
155
+ height: 1rem;
156
+ margin: 0;
157
+ }
158
+
159
+ .lk-mc-option-feedback {
160
+ margin-left: auto;
161
+ font-size: var(--lk-font-size-sm);
162
+ color: var(--lk-color-text-muted);
163
+ }
164
+
165
+ /* ── Fill-in-the-blanks passage ──────────────────────────────────────── */
166
+ /* Generous line-height so inline blanks on wrapped lines never collide. */
167
+ .lk-fib-passage {
168
+ margin: 0 0 var(--lk-spacing-lg);
169
+ font-size: var(--lk-font-size-lg);
170
+ line-height: 2.6;
171
+ }
172
+
173
+ .lk-fib-blank {
174
+ position: relative;
175
+ display: inline-flex;
176
+ align-items: center;
177
+ gap: var(--lk-spacing-xs);
178
+ vertical-align: middle;
179
+ margin: 0 2px;
180
+ }
181
+
182
+ /* Explicit font metrics: `font: inherit` would pull the passage's large
183
+ line-height (2.6) into the field and balloon its height. */
184
+ .lk-fib-blank input {
185
+ font-family: var(--lk-font-family-base);
186
+ font-size: var(--lk-font-size-base);
187
+ line-height: 1.4;
188
+ color: var(--lk-color-text);
189
+ padding: 2px var(--lk-spacing-sm);
190
+ border: 1px solid var(--lk-color-border);
191
+ background: var(--lk-color-surface);
192
+ border-radius: var(--lk-radius-sm);
193
+ min-width: 7ch;
194
+ transition: var(--lk-transition-fast);
195
+ }
196
+
197
+ .lk-fib-blank input:hover {
198
+ border-color: var(--lk-color-primary);
199
+ }
200
+
201
+ /* Contained focus (no outline-offset) so the ring stays inside the line
202
+ box and never bleeds into the line above/below. */
203
+ .lk-fib-blank input:focus-visible {
204
+ outline: none;
205
+ border-color: var(--lk-color-focus-ring);
206
+ box-shadow: 0 0 0 2px var(--lk-color-focus-ring);
207
+ }
208
+
209
+ .lk-fib-blank input[data-correct="true"] {
210
+ border-color: var(--lk-color-success);
211
+ }
212
+
213
+ .lk-fib-blank input[data-correct="false"] {
214
+ border-color: var(--lk-color-error);
215
+ }
216
+
217
+ /* Icon hint button: a subtle circular affordance, not a text pill. */
218
+ .lk-fib-hint-btn {
219
+ display: inline-flex;
220
+ align-items: center;
221
+ justify-content: center;
222
+ color: var(--lk-color-text-muted);
223
+ background: var(--lk-color-surface-raised);
224
+ border: 1px solid var(--lk-color-border);
225
+ border-radius: 50%;
226
+ padding: 3px;
227
+ line-height: 0;
228
+ cursor: pointer;
229
+ }
230
+
231
+ .lk-fib-hint-btn:hover {
232
+ border-color: var(--lk-color-primary);
233
+ color: var(--lk-color-text);
234
+ }
235
+
236
+ /* Inline per-blank feedback shown after submission. */
237
+ .lk-fib-blank-feedback {
238
+ margin-left: var(--lk-spacing-xs);
239
+ font-size: var(--lk-font-size-sm);
240
+ color: var(--lk-color-text-muted);
241
+ }
242
+
243
+ .lk-fib-blank-feedback[data-correct="true"] {
244
+ color: var(--lk-color-success);
245
+ }
246
+
247
+ .lk-fib-blank-feedback[data-correct="false"] {
248
+ color: var(--lk-color-error);
249
+ }
250
+
251
+ /* Learner control to declutter feedback after submission. */
252
+ .lk-fib-feedback-toggle {
253
+ margin-top: var(--lk-spacing-md);
254
+ font-size: var(--lk-font-size-sm);
255
+ color: var(--lk-color-text-muted);
256
+ background: none;
257
+ border: 0;
258
+ padding: 0;
259
+ cursor: pointer;
260
+ text-decoration: underline;
261
+ }
262
+
263
+ .lk-fib-feedback-toggle:hover {
264
+ color: var(--lk-color-text);
265
+ }
266
+
267
+ /* Revealed hint rendered as a floating popover above the blank. The empty
268
+ placeholder span (pre-reveal) is hidden so nothing shows until clicked. */
269
+ .lk-fib-blank [aria-live]:empty {
270
+ display: none;
271
+ }
272
+
273
+ .lk-fib-blank [aria-live]:not(:empty) {
274
+ position: absolute;
275
+ bottom: calc(100% + 6px);
276
+ left: 0;
277
+ z-index: 1;
278
+ max-width: 16rem;
279
+ padding: var(--lk-spacing-xs) var(--lk-spacing-sm);
280
+ font-size: var(--lk-font-size-sm);
281
+ line-height: var(--lk-line-height-base);
282
+ color: var(--lk-color-surface);
283
+ background: var(--lk-color-text);
284
+ border-radius: var(--lk-radius-sm);
285
+ box-shadow: 0 4px 12px rgb(0 0 0 / 18%);
286
+ }
287
+
288
+ /* Little caret pointing at the blank. */
289
+ .lk-fib-blank [aria-live]:not(:empty)::after {
290
+ content: "";
291
+ position: absolute;
292
+ top: 100%;
293
+ left: var(--lk-spacing-sm);
294
+ border: 5px solid transparent;
295
+ border-top-color: var(--lk-color-text);
296
+ }
297
+
298
+ .lk-fib-answer {
299
+ padding: var(--lk-spacing-xs) var(--lk-spacing-sm);
300
+ border-radius: var(--lk-radius-sm);
301
+ background: color-mix(in srgb, var(--lk-color-success) 14%, var(--lk-color-surface));
302
+ color: var(--lk-color-text);
303
+ font-weight: var(--lk-font-weight-bold);
304
+ }
305
+
306
+ /* ── Submit buttons ──────────────────────────────────────────────────── */
307
+ .lk-mc button[type="submit"],
308
+ .lk-fib button[type="submit"] {
309
+ margin-top: var(--lk-spacing-md);
310
+ padding: var(--lk-spacing-sm) var(--lk-spacing-lg);
311
+ font: inherit;
312
+ font-weight: var(--lk-font-weight-bold);
313
+ color: var(--lk-color-surface);
314
+ background: var(--lk-color-primary);
315
+ border: 0;
316
+ border-radius: var(--lk-radius-base);
317
+ cursor: pointer;
318
+ transition: var(--lk-transition-fast);
319
+ }
320
+
321
+ .lk-mc button[type="submit"]:hover,
322
+ .lk-fib button[type="submit"]:hover {
323
+ background: var(--lk-color-primary-hover);
324
+ }
325
+
326
+ .lk-mc button[type="submit"]:disabled,
327
+ .lk-fib button[type="submit"]:disabled {
328
+ opacity: 0.55;
329
+ cursor: default;
330
+ }
331
+
332
+ /* ── Focus ring (keyboard) ───────────────────────────────────────────── */
333
+ .lk-mc :focus-visible,
334
+ .lk-fib :focus-visible {
335
+ outline: 2px solid var(--lk-color-focus-ring);
336
+ outline-offset: 2px;
337
+ }
338
+
339
+ /* Inline controls in the passage use a contained ring (no offset) so the
340
+ focus indicator never overlaps the line above/below. */
341
+ .lk-fib-blank button:focus-visible {
342
+ outline-offset: 0;
343
+ }
344
+
345
+ /* ── Feedback / status region ────────────────────────────────────────── */
346
+ .lk-mc > [aria-live],
347
+ .lk-fib > [aria-live] {
348
+ margin-top: var(--lk-spacing-md);
349
+ color: var(--lk-color-text-muted);
350
+ font-size: var(--lk-font-size-sm);
351
+ }
352
+ }
@@ -0,0 +1,17 @@
1
+ import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
2
+
3
+ /**
4
+ * The consistent prop contract shared by every activity component (Req 3.1).
5
+ * Defined here (React-specific) rather than in lk-core, which is React-free.
6
+ */
7
+ interface ActivityProps<TData extends ActivityData = ActivityData> {
8
+ data: TData;
9
+ onComplete: (result: ActivityResult) => void;
10
+ onInteraction?: (event: InteractionEvent) => void;
11
+ /** Per-instance token overrides, applied as inline CSS vars on the root. */
12
+ theme?: Partial<ThemeTokens>;
13
+ locale?: string;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ export type { ActivityProps as A };
@@ -0,0 +1,17 @@
1
+ import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
2
+
3
+ /**
4
+ * The consistent prop contract shared by every activity component (Req 3.1).
5
+ * Defined here (React-specific) rather than in lk-core, which is React-free.
6
+ */
7
+ interface ActivityProps<TData extends ActivityData = ActivityData> {
8
+ data: TData;
9
+ onComplete: (result: ActivityResult) => void;
10
+ onInteraction?: (event: InteractionEvent) => void;
11
+ /** Per-instance token overrides, applied as inline CSS vars on the root. */
12
+ theme?: Partial<ThemeTokens>;
13
+ locale?: string;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ export type { ActivityProps as A };
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@intellectif/lk-react",
3
+ "version": "1.0.0",
4
+ "description": "React 19 activity components, hooks, and theming for learning-kit",
5
+ "type": "module",
6
+ "sideEffects": [
7
+ "**/*.css"
8
+ ],
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./components/ActivitySequence": {
16
+ "types": "./dist/components/ActivitySequence.d.ts",
17
+ "import": "./dist/components/ActivitySequence.js",
18
+ "require": "./dist/components/ActivitySequence.cjs"
19
+ },
20
+ "./components/MultipleChoice": {
21
+ "types": "./dist/components/MultipleChoice.d.ts",
22
+ "import": "./dist/components/MultipleChoice.js",
23
+ "require": "./dist/components/MultipleChoice.cjs"
24
+ },
25
+ "./components/FillInTheBlanks": {
26
+ "types": "./dist/components/FillInTheBlanks.d.ts",
27
+ "import": "./dist/components/FillInTheBlanks.js",
28
+ "require": "./dist/components/FillInTheBlanks.cjs"
29
+ },
30
+ "./hooks/useActivityState": {
31
+ "types": "./dist/hooks/useActivityState.d.ts",
32
+ "import": "./dist/hooks/useActivityState.js",
33
+ "require": "./dist/hooks/useActivityState.cjs"
34
+ },
35
+ "./hooks/useXAPI": {
36
+ "types": "./dist/hooks/useXAPI.d.ts",
37
+ "import": "./dist/hooks/useXAPI.js",
38
+ "require": "./dist/hooks/useXAPI.cjs"
39
+ },
40
+ "./theme/ThemeProvider": {
41
+ "types": "./dist/theme/ThemeProvider.d.ts",
42
+ "import": "./dist/theme/ThemeProvider.js",
43
+ "require": "./dist/theme/ThemeProvider.cjs"
44
+ },
45
+ "./theme/defaults.css": "./dist/theme/defaults.css",
46
+ "./theme/skin.css": "./dist/theme/skin.css"
47
+ },
48
+ "main": "./dist/index.cjs",
49
+ "module": "./dist/index.js",
50
+ "types": "./dist/index.d.ts",
51
+ "files": [
52
+ "dist"
53
+ ],
54
+ "peerDependencies": {
55
+ "react": "^19",
56
+ "react-dom": "^19",
57
+ "@intellectif/lk-core": "^0.2.0"
58
+ },
59
+ "devDependencies": {
60
+ "@axe-core/react": "^4.10.0",
61
+ "@playwright/test": "^1.49.0",
62
+ "@testing-library/jest-dom": "^6.6.3",
63
+ "@testing-library/react": "^16.1.0",
64
+ "@testing-library/user-event": "^14.5.2",
65
+ "@types/react": "^19.0.0",
66
+ "@types/react-dom": "^19.0.0",
67
+ "@vitest/coverage-v8": "^4.1.6",
68
+ "fast-check": "^3.22.0",
69
+ "jsdom": "^25.0.1",
70
+ "msw": "^2.6.0",
71
+ "react": "^19.0.0",
72
+ "react-dom": "^19.0.0",
73
+ "tsup": "^8.3.0",
74
+ "vitest": "^4.1.6",
75
+ "vitest-axe": "^0.1.0",
76
+ "@intellectif/lk-core": "0.2.0"
77
+ },
78
+ "license": "MIT",
79
+ "scripts": {
80
+ "build": "tsup",
81
+ "test": "vitest run",
82
+ "coverage": "vitest run --coverage",
83
+ "lint": "biome check .",
84
+ "e2e": "playwright test -c ../../playwright.config.ts"
85
+ }
86
+ }