@hkdigital/lib-core 0.5.90 → 0.5.92

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.
@@ -0,0 +1,445 @@
1
+ # ReactiveDataStore
2
+
3
+ Reactive key-value data store with fine-grained reactivity built on Svelte 5's
4
+ `SvelteMap`.
5
+
6
+ ## Features
7
+
8
+ - **Fine-grained reactivity**: Effects only re-run when specific keys change
9
+ - **Strict mode**: Throws errors on uninitialized key access
10
+ - **Production guard**: Dev-only data mode for development helpers
11
+ - **Full CRUD API**: Set, get, update, delete, check existence, clear
12
+ - **Type-safe**: Use constants for keys to get autocomplete and typo prevention
13
+
14
+ ## Basic Usage
15
+
16
+ ```javascript
17
+ import { ReactiveDataStore } from '$lib/state/classes.js';
18
+
19
+ // Create a store
20
+ const store = new ReactiveDataStore({
21
+ initialData: {
22
+ score: 0,
23
+ level: 1,
24
+ playerName: 'Alice'
25
+ }
26
+ });
27
+
28
+ // Set data
29
+ store.set('score', 100);
30
+
31
+ // Get data (reactive)
32
+ $effect(() => {
33
+ const score = store.get('score');
34
+ console.log('Score changed:', score);
35
+ });
36
+
37
+ // Update multiple values
38
+ store.update({
39
+ score: 200,
40
+ level: 5
41
+ });
42
+
43
+ // Check existence
44
+ if (store.has('score')) {
45
+ // ...
46
+ }
47
+
48
+ // Get all data (snapshot)
49
+ const allData = store.getAll();
50
+
51
+ // Delete
52
+ store.delete('temporaryFlag');
53
+
54
+ // Clear all
55
+ store.clear();
56
+
57
+ // Get size
58
+ console.log(`Store has ${store.size} entries`);
59
+ ```
60
+
61
+ ## Options
62
+
63
+ ```javascript
64
+ const store = new ReactiveDataStore({
65
+ // Initial key-value pairs
66
+ initialData: {},
67
+
68
+ // Throw on uninitialized key access (default: true)
69
+ strictMode: true,
70
+
71
+ // Dev-only mode (default: false)
72
+ productionGuard: false,
73
+
74
+ // Custom error message prefix (default: 'Data key')
75
+ errorPrefix: 'Custom prefix'
76
+ });
77
+ ```
78
+
79
+ ## Fine-Grained Reactivity
80
+
81
+ ReactiveDataStore uses `SvelteMap` internally, providing fine-grained
82
+ reactivity where effects only re-run when the specific keys they access change.
83
+
84
+ ```javascript
85
+ const store = new ReactiveDataStore({
86
+ initialData: { score: 0, lives: 3 }
87
+ });
88
+
89
+ // Effect 1: Only re-runs when 'score' changes
90
+ $effect(() => {
91
+ const score = store.get('score');
92
+ console.log('Score:', score);
93
+ });
94
+
95
+ // Effect 2: Only re-runs when 'lives' changes
96
+ $effect(() => {
97
+ const lives = store.get('lives');
98
+ console.log('Lives:', lives);
99
+ });
100
+
101
+ // This only triggers Effect 1, not Effect 2
102
+ store.set('score', 100);
103
+
104
+ // This only triggers Effect 2, not Effect 1
105
+ store.set('lives', 2);
106
+ ```
107
+
108
+ ## Strict Mode (Default)
109
+
110
+ By default, ReactiveDataStore throws errors when accessing uninitialized keys.
111
+ This helps catch typos and ensures data is properly initialized.
112
+
113
+ ```javascript
114
+ const store = new ReactiveDataStore();
115
+
116
+ // ❌ Throws: "Data key "score" is not initialized."
117
+ store.get('score');
118
+
119
+ // ✅ Initialize first
120
+ store.set('score', 0);
121
+ store.get('score'); // Works
122
+
123
+ // Or initialize via constructor
124
+ const store2 = new ReactiveDataStore({
125
+ initialData: { score: 0 }
126
+ });
127
+ store2.get('score'); // Works
128
+ ```
129
+
130
+ ### Disabling Strict Mode
131
+
132
+ ```javascript
133
+ const store = new ReactiveDataStore({
134
+ strictMode: false
135
+ });
136
+
137
+ // Returns undefined instead of throwing
138
+ const score = store.get('nonexistent'); // undefined
139
+ ```
140
+
141
+ ## Production Guard (Dev-Only Data)
142
+
143
+ Use `productionGuard: true` for development-only data that should not be
144
+ accessed in production.
145
+
146
+ ```javascript
147
+ const devStore = new ReactiveDataStore({
148
+ initialData: {
149
+ autoNavigation: false,
150
+ skipAnimations: false,
151
+ mockApi: 'localhost'
152
+ },
153
+ productionGuard: true,
154
+ errorPrefix: 'Dev data key'
155
+ });
156
+
157
+ // In development mode:
158
+ devStore.set('autoNavigation', true); // ✅ Works
159
+ const value = devStore.get('autoNavigation'); // ✅ Works
160
+
161
+ // In production:
162
+ devStore.set('autoNavigation', true); // ✅ Silent no-op (safe)
163
+ devStore.get('autoNavigation'); // ❌ Throws error (programming bug!)
164
+ ```
165
+
166
+ **Why this design?**
167
+
168
+ - **SET operations**: Safe to call conditionally in production (no-op)
169
+ - **GET/HAS operations**: Reading dev data in production is a programming
170
+ error that should fail fast
171
+
172
+ ## Using with PageMachine
173
+
174
+ ReactiveDataStore is used internally by PageMachine for data management:
175
+
176
+ ```javascript
177
+ import { PageMachine } from '$lib/state/machines.js';
178
+
179
+ const machine = new PageMachine({
180
+ startPath: '/intro',
181
+ initialData: {
182
+ score: 0,
183
+ tutorialSeen: false
184
+ },
185
+ initialDevData: {
186
+ autoNav: false,
187
+ skipAnimations: false
188
+ }
189
+ });
190
+
191
+ // Access via read-only getters
192
+ machine.data.set('score', 100);
193
+ machine.data.get('score');
194
+
195
+ machine.devData.set('autoNav', true);
196
+ machine.devData.get('autoNav');
197
+ ```
198
+
199
+ ## Best Practices
200
+
201
+ ### 1. Use Constants for Keys
202
+
203
+ Avoid magic strings - use constants for autocomplete and typo prevention:
204
+
205
+ ```javascript
206
+ // ✅ Good - use constants
207
+ const KEY_SCORE = 'score';
208
+ const KEY_PLAYER_NAME = 'player-name';
209
+ const KEY_TUTORIAL_SEEN = 'tutorial-seen';
210
+
211
+ store.set(KEY_SCORE, 100);
212
+ const score = store.get(KEY_SCORE);
213
+
214
+ // ❌ Avoid - magic strings
215
+ store.set('score', 100);
216
+ const score = store.get('scroe'); // Typo! No error until runtime
217
+ ```
218
+
219
+ ### 2. Initialize Data in Constructor
220
+
221
+ Always initialize expected keys in the constructor for strict mode:
222
+
223
+ ```javascript
224
+ // ✅ Good
225
+ const store = new ReactiveDataStore({
226
+ initialData: {
227
+ score: 0,
228
+ lives: 3,
229
+ playerName: ''
230
+ }
231
+ });
232
+
233
+ // ❌ Avoid - uninitialized keys
234
+ const store = new ReactiveDataStore();
235
+ store.get('score'); // Throws error
236
+ ```
237
+
238
+ ### 3. Use Dev Data for Development Helpers
239
+
240
+ Keep development-only flags separate with production guard:
241
+
242
+ ```javascript
243
+ // Regular data
244
+ const data = new ReactiveDataStore({
245
+ initialData: {
246
+ score: 0,
247
+ level: 1
248
+ }
249
+ });
250
+
251
+ // Dev-only data
252
+ const devData = new ReactiveDataStore({
253
+ initialData: {
254
+ autoNavigation: false,
255
+ skipAnimations: false,
256
+ debugMode: false
257
+ },
258
+ productionGuard: true,
259
+ errorPrefix: 'Dev data key'
260
+ });
261
+ ```
262
+
263
+ ### 4. Use getAll() for Serialization Only
264
+
265
+ `getAll()` returns a snapshot (plain object), not a reactive value. Use it for
266
+ serialization or inspection, not for reactive tracking:
267
+
268
+ ```javascript
269
+ // ✅ Good - serialization
270
+ const snapshot = store.getAll();
271
+ await saveToServer(snapshot);
272
+
273
+ // ✅ Good - inspection
274
+ console.log('Current state:', store.getAll());
275
+
276
+ // ❌ Avoid - for reactivity
277
+ $effect(() => {
278
+ const data = store.getAll(); // Re-runs on ANY key change
279
+ console.log(data.score); // Use store.get('score') instead
280
+ });
281
+ ```
282
+
283
+ ## API Reference
284
+
285
+ ### Constructor
286
+
287
+ ```javascript
288
+ new ReactiveDataStore(options)
289
+ ```
290
+
291
+ **Options:**
292
+ - `initialData` (object): Initial key-value pairs
293
+ - `strictMode` (boolean): Throw on uninitialized keys (default: `true`)
294
+ - `productionGuard` (boolean): Dev-only mode (default: `false`)
295
+ - `errorPrefix` (string): Error message prefix (default: `'Data key'`)
296
+
297
+ ### Methods
298
+
299
+ #### `set(key, value)`
300
+
301
+ Set a data property value. Triggers reactivity for this key.
302
+
303
+ ```javascript
304
+ store.set('score', 100);
305
+ ```
306
+
307
+ #### `get(key)`
308
+
309
+ Get a data property value. Creates a reactive dependency on this key.
310
+
311
+ ```javascript
312
+ const score = store.get('score');
313
+ ```
314
+
315
+ **Throws:** Error if key not initialized (strict mode)
316
+
317
+ #### `getAll()`
318
+
319
+ Get all data as a plain object snapshot (not reactive).
320
+
321
+ ```javascript
322
+ const snapshot = store.getAll();
323
+ ```
324
+
325
+ #### `update(updates)`
326
+
327
+ Update multiple properties at once.
328
+
329
+ ```javascript
330
+ store.update({
331
+ score: 100,
332
+ level: 5,
333
+ lives: 2
334
+ });
335
+ ```
336
+
337
+ #### `has(key)`
338
+
339
+ Check if a key exists.
340
+
341
+ ```javascript
342
+ if (store.has('score')) {
343
+ // Key exists
344
+ }
345
+ ```
346
+
347
+ #### `delete(key)`
348
+
349
+ Delete a property.
350
+
351
+ ```javascript
352
+ const deleted = store.delete('temporaryFlag');
353
+ ```
354
+
355
+ **Returns:** `true` if key existed and was deleted
356
+
357
+ #### `clear()`
358
+
359
+ Clear all data properties.
360
+
361
+ ```javascript
362
+ store.clear();
363
+ ```
364
+
365
+ #### `size` (getter)
366
+
367
+ Get the number of data entries.
368
+
369
+ ```javascript
370
+ console.log(`Store has ${store.size} entries`);
371
+ ```
372
+
373
+ ## Common Patterns
374
+
375
+ ### Persisting to Server
376
+
377
+ ```javascript
378
+ const store = new ReactiveDataStore({
379
+ initialData: {
380
+ score: 0,
381
+ level: 1,
382
+ preferences: {}
383
+ }
384
+ });
385
+
386
+ // Save snapshot to server
387
+ async function saveProgress() {
388
+ const data = store.getAll();
389
+ await fetch('/api/save', {
390
+ method: 'POST',
391
+ body: JSON.stringify(data)
392
+ });
393
+ }
394
+
395
+ // Load from server
396
+ async function loadProgress() {
397
+ const response = await fetch('/api/load');
398
+ const data = await response.json();
399
+ store.update(data);
400
+ }
401
+ ```
402
+
403
+ ### Computed Values
404
+
405
+ ```javascript
406
+ const store = new ReactiveDataStore({
407
+ initialData: {
408
+ score: 0,
409
+ multiplier: 1
410
+ }
411
+ });
412
+
413
+ // Computed value based on store data
414
+ const totalScore = $derived(
415
+ store.get('score') * store.get('multiplier')
416
+ );
417
+ ```
418
+
419
+ ### Conditional Effects
420
+
421
+ ```javascript
422
+ const store = new ReactiveDataStore({
423
+ initialData: {
424
+ level: 1,
425
+ lives: 3
426
+ }
427
+ });
428
+
429
+ // Effect only runs when level changes and lives > 0
430
+ $effect(() => {
431
+ const level = store.get('level');
432
+ const lives = store.get('lives');
433
+
434
+ if (lives > 0) {
435
+ console.log(`Playing level ${level}`);
436
+ }
437
+ });
438
+ ```
439
+
440
+ ## See Also
441
+
442
+ - [PageMachine](../../machines/page-machine/README.md) - Uses ReactiveDataStore
443
+ for route-aware data management
444
+ - [SubscribersCount](../subscribers-count/SubscribersCount.js) - Another state
445
+ utility class
@@ -135,32 +135,32 @@ export class PuzzleState extends PageMachine {
135
135
  return this.current === ROUTE_COMPLETE;
136
136
  }
137
137
 
138
- // Persistent settings/progress (use getData/setData)
138
+ // Persistent settings/progress (use machine.data)
139
139
  get hasSeenTutorial() {
140
- return this.getData(KEY_TUTORIAL_SEEN) || false;
140
+ return this.data.get(KEY_TUTORIAL_SEEN) || false;
141
141
  }
142
142
 
143
143
  markTutorialComplete() {
144
- this.setData(KEY_TUTORIAL_SEEN, true);
144
+ this.data.set(KEY_TUTORIAL_SEEN, true);
145
145
  }
146
146
 
147
147
  get highestLevel() {
148
- return this.getData(KEY_HIGHEST_LEVEL) || 1;
148
+ return this.data.get(KEY_HIGHEST_LEVEL) || 1;
149
149
  }
150
150
 
151
151
  updateHighestLevel(level) {
152
152
  const current = this.highestLevel;
153
153
  if (level > current) {
154
- this.setData(KEY_HIGHEST_LEVEL, level);
154
+ this.data.set(KEY_HIGHEST_LEVEL, level);
155
155
  }
156
156
  }
157
157
 
158
158
  get difficulty() {
159
- return this.getData(KEY_DIFFICULTY) || 'normal';
159
+ return this.data.get(KEY_DIFFICULTY) || 'normal';
160
160
  }
161
161
 
162
162
  setDifficulty(level) {
163
- this.setData(KEY_DIFFICULTY, level);
163
+ this.data.set(KEY_DIFFICULTY, level);
164
164
  }
165
165
 
166
166
  // Optional: Lifecycle methods
@@ -273,11 +273,25 @@ puzzleState.isStartPath(path) // Check if path is start path
273
273
  puzzleState.isOnStartPath // Check if on start path
274
274
  puzzleState.redirectToStartPath() // Navigate to start path
275
275
 
276
- // Persistent data properties
277
- puzzleState.setData(KEY_NAME, value)
278
- puzzleState.getData(KEY_NAME)
279
- puzzleState.getAllData()
280
- puzzleState.updateData({ KEY1: val1, KEY2: val2 })
276
+ // Persistent data properties (via ReactiveDataStore)
277
+ puzzleState.data.set(KEY_NAME, value)
278
+ puzzleState.data.get(KEY_NAME)
279
+ puzzleState.data.getAll()
280
+ puzzleState.data.update({ KEY1: val1, KEY2: val2 })
281
+ puzzleState.data.has(KEY_NAME)
282
+ puzzleState.data.delete(KEY_NAME)
283
+ puzzleState.data.clear()
284
+ puzzleState.data.size
285
+
286
+ // Dev data properties (dev-only, via ReactiveDataStore)
287
+ puzzleState.devData.set(KEY_DEV_NAME, value)
288
+ puzzleState.devData.get(KEY_DEV_NAME)
289
+ puzzleState.devData.getAll()
290
+ puzzleState.devData.update({ KEY1: val1 })
291
+ puzzleState.devData.has(KEY_DEV_NAME)
292
+ puzzleState.devData.delete(KEY_DEV_NAME)
293
+ puzzleState.devData.clear()
294
+ puzzleState.devData.size
281
295
 
282
296
  // Visited routes tracking
283
297
  puzzleState.hasVisited(route) // e.g., hasVisited('/puzzle/intro')
@@ -296,9 +310,9 @@ puzzleState.hasSeenTutorial
296
310
 
297
311
  ## Data Storage Guidelines
298
312
 
299
- ### When to use `getData/setData` (PageMachine)
313
+ ### When to use `machine.data` (ReactiveDataStore)
300
314
 
301
- Use PageMachine's data properties for **persistent settings and progress**:
315
+ Use PageMachine's data store for **persistent settings and progress**:
302
316
 
303
317
  - ✅ Tutorial completion flags
304
318
  - ✅ User preferences (difficulty, language, sound)
@@ -319,13 +333,39 @@ const KEY_DIFFICULTY = 'difficulty';
319
333
  const KEY_HIGHEST_LEVEL = 'highest-level';
320
334
 
321
335
  // Use constants (not strings!)
322
- pageMachine.setData(KEY_TUTORIAL_SEEN, true); // ✅ Good
323
- pageMachine.setData(KEY_DIFFICULTY, 'hard'); // ✅ Good
324
- pageMachine.setData(KEY_HIGHEST_LEVEL, 5); // ✅ Good
336
+ pageMachine.data.set(KEY_TUTORIAL_SEEN, true); // ✅ Good
337
+ pageMachine.data.set(KEY_DIFFICULTY, 'hard'); // ✅ Good
338
+ pageMachine.data.set(KEY_HIGHEST_LEVEL, 5); // ✅ Good
325
339
 
326
340
  // DON'T use magic strings
327
- pageMachine.setData('tutorial-seen', true); // ❌ Avoid
328
- pageMachine.setData('TUTORIAL_SEEN', true); // ❌ Avoid
341
+ pageMachine.data.set('tutorial-seen', true); // ❌ Avoid
342
+ pageMachine.data.set('TUTORIAL_SEEN', true); // ❌ Avoid
343
+ ```
344
+
345
+ ### When to use `machine.devData` (Dev-only ReactiveDataStore)
346
+
347
+ Use PageMachine's devData store for **development helpers**:
348
+
349
+ - ✅ Auto-navigation flags
350
+ - ✅ Skip animations/delays
351
+ - ✅ Mock API endpoints
352
+ - ✅ Debug mode flags
353
+ - ✅ Development-only settings
354
+
355
+ **IMPORTANT**: Use KEY_DEV_ prefix for dev data constants:
356
+
357
+ ```javascript
358
+ // Define constants (at top of file)
359
+ const KEY_DEV_AUTO_NAVIGATION = 'dev-auto-navigation';
360
+ const KEY_DEV_SKIP_ANIMATIONS = 'dev-skip-animations';
361
+ const KEY_DEV_MOCK_API = 'dev-mock-api';
362
+
363
+ // Use in development (no-op in production)
364
+ pageMachine.devData.set(KEY_DEV_AUTO_NAVIGATION, true); // ✅ Good
365
+ pageMachine.devData.set(KEY_DEV_SKIP_ANIMATIONS, false); // ✅ Good
366
+
367
+ // Reading in production throws error (programming bug)
368
+ const autoNav = pageMachine.devData.get(KEY_DEV_AUTO_NAVIGATION);
329
369
  ```
330
370
 
331
371
  ### When to use GameLogic with `$state`
@@ -358,6 +398,17 @@ export class PuzzleGameLogic {
358
398
  - Routes are the source of truth (no state abstraction layer)
359
399
  - Use route constants for clarity and maintainability
360
400
  - Always sync in `$effect` watching `$page.url.pathname`
361
- - Use constants for data keys (e.g., `KEY_TUTORIAL_SEEN`)
401
+ - Use constants for data keys (e.g., `KEY_TUTORIAL_SEEN`, `KEY_DEV_AUTO_NAV`)
362
402
  - Separate persistent data (PageMachine) from reactive state (GameLogic)
363
403
  - Handle animations in pages using `$effect` or `onMount`
404
+ - Data and devData use [ReactiveDataStore](../../classes/reactive-data-store/README.md)
405
+ for fine-grained reactivity
406
+ - Access data via read-only getters: `machine.data.get()`, `machine.devData.set()`
407
+
408
+ ## See Also
409
+
410
+ - [ReactiveDataStore](../../classes/reactive-data-store/README.md) - The
411
+ underlying reactive data storage implementation
412
+ - [FiniteStateMachine](../finite-state-machine/README.md) - For enforced state
413
+ transitions
414
+ - [State Context](../../context/README.md) - For providing state to components
@@ -0,0 +1,121 @@
1
+ # UI Component Changes
2
+
3
+ ## Property Name Changes (2026-01)
4
+
5
+ ### Background
6
+ Skeleton.dev has updated their component API standards, and we follow
7
+ skeleton standards for consistency across the ecosystem.
8
+
9
+ ### Changes
10
+
11
+ #### `classes` → `class`
12
+ All UI components now accept `class` instead of `classes` for CSS
13
+ class names.
14
+
15
+ #### `base` → removed
16
+ The `base` property has been deprecated. Use `class` instead.
17
+
18
+ #### `bg` → removed
19
+ The `bg` property has been deprecated. Use `class` instead.
20
+
21
+ ### Migration Guide
22
+
23
+ **Before:**
24
+ ```svelte
25
+ <SteezeIcon
26
+ base="icon-base"
27
+ classes="text-primary-500"
28
+ src={icon}
29
+ />
30
+
31
+ <GameBox
32
+ base="box-base"
33
+ bg="bg-surface-100"
34
+ classes="rounded-md"
35
+ />
36
+ ```
37
+
38
+ **After:**
39
+ ```svelte
40
+ <SteezeIcon
41
+ class="icon-base text-primary-500"
42
+ src={icon}
43
+ />
44
+
45
+ <GameBox
46
+ class="box-base bg-surface-100 rounded-md"
47
+ />
48
+ ```
49
+
50
+ ### Implementation Pattern
51
+
52
+ All components follow this exact pattern for backward compatibility:
53
+
54
+ **JSDoc Type:**
55
+ ```javascript
56
+ /**
57
+ * @type {{
58
+ * class?: string,
59
+ * base?: string, // Deprecated: use 'class' instead
60
+ * bg?: string, // Deprecated: use 'class' instead (if applicable)
61
+ * classes?: string, // Deprecated: use 'class' instead
62
+ * // ... other props
63
+ * }}
64
+ */
65
+ ```
66
+
67
+ **Props Destructuring:**
68
+ ```javascript
69
+ const {
70
+ class: className,
71
+ base, // Deprecated: kept for backward compatibility
72
+ bg, // Deprecated: kept for backward compatibility (if applicable)
73
+ classes, // Deprecated: kept for backward compatibility
74
+ // ... other props
75
+ } = $props();
76
+ ```
77
+
78
+ **Class Attribute Usage:**
79
+ ```svelte
80
+ <!-- With bg prop -->
81
+ <div class="{base ?? ''} {bg ?? ''} {className ?? classes ?? ''}"></div>
82
+
83
+ <!-- Without bg prop -->
84
+ <div class="{base ?? ''} {className ?? classes ?? ''}"></div>
85
+ ```
86
+
87
+ **Priority Order:**
88
+ 1. `base` - applied first if provided
89
+ 2. `bg` - applied second if provided and component supports it
90
+ 3. `className` - from new `class` prop, applied if `classes` not provided
91
+ 4. `classes` - deprecated fallback, applied if `className` not provided
92
+
93
+ ### Backward Compatibility
94
+
95
+ During the transition period, components accept both old and new
96
+ property names:
97
+
98
+ - `class` - new standard (recommended)
99
+ - `classes` - deprecated, still works
100
+ - `base` - deprecated, still works
101
+ - `bg` - deprecated, still works (GameBox only)
102
+
103
+ All properties will be merged if provided together, allowing gradual
104
+ migration without breaking existing code.
105
+
106
+ ### Timeline
107
+
108
+ - **Now**: Both old and new properties supported
109
+ - **Future**: `base`, `bg`, and `classes` will be removed in a future
110
+ major version
111
+
112
+ ### Affected Components
113
+
114
+ - `SteezeIcon.svelte`
115
+ - `GameBox.svelte`
116
+ - `ImageBox.svelte`
117
+ - `Presenter.svelte`
118
+ - `GridLayers.svelte`
119
+ - `Panel.svelte`
120
+ - `Button.svelte`
121
+ - More components will be updated following this pattern
@@ -26,9 +26,10 @@
26
26
 
27
27
  /**
28
28
  * @type {{
29
- * base?: string,
30
- * bg?: string,
31
- * classes?: string,
29
+ * class?: string,
30
+ * base?: string, // Deprecated: use 'class' instead
31
+ * bg?: string, // Deprecated: use 'class' instead
32
+ * classes?: string, // Deprecated: use 'class' instead
32
33
  * style?: string,
33
34
  * aspectOnLandscape?: number,
34
35
  * aspectOnPortrait?: number,
@@ -57,9 +58,10 @@
57
58
  */
58
59
  const {
59
60
  // > Style
60
- base = '',
61
- bg = '',
62
- classes = '',
61
+ class: className,
62
+ base, // Deprecated: kept for backward compatibility
63
+ bg, // Deprecated: kept for backward compatibility
64
+ classes, // Deprecated: kept for backward compatibility
63
65
  style = '',
64
66
 
65
67
  // > Functional properties
@@ -468,8 +470,9 @@
468
470
  <div
469
471
  data-component="game-box"
470
472
  data-orientation={isLandscape ? 'landscape' : 'portrait'}
471
- class="{base} {bg} {classes}"
473
+ class="{base ?? ''} {bg ?? ''} {className ?? classes ?? ''}"
472
474
  class:isMobile
475
+ style:position="relative"
473
476
  style:width="{gameWidth}px"
474
477
  style:height="{gameHeight}px"
475
478
  style:--game-width={gameWidth}
@@ -3,6 +3,7 @@ type GameBox = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
5
  [attr: string]: any;
6
+ class?: string | undefined;
6
7
  base?: string | undefined;
7
8
  bg?: string | undefined;
8
9
  classes?: string | undefined;
@@ -51,6 +52,7 @@ type GameBox = {
51
52
  };
52
53
  declare const GameBox: import("svelte").Component<{
53
54
  [attr: string]: any;
55
+ class?: string;
54
56
  base?: string;
55
57
  bg?: string;
56
58
  classes?: string;
@@ -1,6 +1,12 @@
1
1
  <script>
2
+ // import { onMount } from 'svelte';
3
+
2
4
  import { enableContainerScaling } from '../../../design/index.js';
3
5
 
6
+ // onMount( () => {
7
+ // console.debug('[ScaledContainer] mounted');
8
+ // } );
9
+
4
10
  /**
5
11
  * Wrapper component that applies container scaling to its children
6
12
  *
@@ -41,8 +47,8 @@
41
47
  !width ||
42
48
  !height ||
43
49
  !design ||
44
- !clamping ||
45
- hidden
50
+ !clamping
51
+ || hidden
46
52
  ) {
47
53
  return;
48
54
  }
@@ -62,16 +68,13 @@
62
68
  <div
63
69
  data-component="scaled-container"
64
70
  bind:this={container}
65
- class:hidden
71
+ style:position="absolute"
72
+ style:top="0"
73
+ style:left="0"
66
74
  style:width="{width}px"
67
75
  style:height="{height}px"
76
+ style:display={hidden ? "none" : "block"}
68
77
  >
69
78
  {@render snippet(snippetParams)}
70
79
  </div>
71
80
  {/if}
72
-
73
- <style>
74
- .hidden {
75
- visibility: hidden;
76
- }
77
- </style>
@@ -6,11 +6,12 @@
6
6
  * enabling layered layouts with natural height behavior.
7
7
  *
8
8
  * @type {{
9
- * base?: string,
10
- * bg?: string,
9
+ * class?: string,
10
+ * base?: string, // Deprecated: use 'class' instead
11
+ * bg?: string, // Deprecated: use 'class' instead
11
12
  * padding?: string,
12
13
  * margin?: string,
13
- * classes?: string,
14
+ * classes?: string, // Deprecated: use 'class' instead
14
15
  * style?: string,
15
16
  * overflow?: string,
16
17
  * children: import('svelte').Snippet,
@@ -19,11 +20,12 @@
19
20
  */
20
21
  const {
21
22
  // Container styles
22
- base = '',
23
- bg = '',
23
+ class: className,
24
+ base, // Deprecated: kept for backward compatibility
25
+ bg, // Deprecated: kept for backward compatibility
24
26
  padding = '',
25
27
  margin = '',
26
- classes = '',
28
+ classes, // Deprecated: kept for backward compatibility
27
29
  style = '',
28
30
  overflow = '',
29
31
 
@@ -48,7 +50,7 @@
48
50
 
49
51
  <div
50
52
  data-component="grid-layers"
51
- class="grid {base} {bg} {classes} {margin} {padding} {overflow}"
53
+ class="grid {base ?? ''} {bg ?? ''} {className ?? classes ?? ''} {margin} {padding} {overflow}"
52
54
  style={containerStyle}
53
55
  {...attrs}
54
56
  >
@@ -3,6 +3,7 @@ type GridLayers = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
5
  [attr: string]: any;
6
+ class?: string | undefined;
6
7
  base?: string | undefined;
7
8
  bg?: string | undefined;
8
9
  padding?: string | undefined;
@@ -15,6 +16,7 @@ type GridLayers = {
15
16
  };
16
17
  declare const GridLayers: import("svelte").Component<{
17
18
  [attr: string]: any;
19
+ class?: string;
18
20
  base?: string;
19
21
  bg?: string;
20
22
  padding?: string;
@@ -4,9 +4,10 @@
4
4
 
5
5
  /**
6
6
  * @type {{
7
- * base?: string,
8
- * bg?: string,
9
- * classes?: string,
7
+ * class?: string,
8
+ * base?: string, // Deprecated: use 'class' instead
9
+ * bg?: string, // Deprecated: use 'class' instead
10
+ * classes?: string, // Deprecated: use 'class' instead
10
11
  * width?: string,
11
12
  * height?: string,
12
13
  * aspect?: string,
@@ -23,9 +24,10 @@
23
24
  */
24
25
  let {
25
26
  // Style
26
- base,
27
- bg,
28
- classes,
27
+ class: className,
28
+ base, // Deprecated: kept for backward compatibility
29
+ bg, // Deprecated: kept for backward compatibility
30
+ classes, // Deprecated: kept for backward compatibility
29
31
  width,
30
32
  height,
31
33
  aspect,
@@ -172,7 +174,7 @@
172
174
  <div
173
175
  data-component="image-box"
174
176
  bind:this={containerElem}
175
- class="{base} {bg} {aspect} {overflow} {width} {height} {classes}"
177
+ class="{base ?? ''} {bg ?? ''} {aspect} {overflow} {width} {height} {className ?? classes ?? ''}"
176
178
  style:--fit={fit}
177
179
  style:--pos={position}
178
180
  style:width={width || (height && aspect) ? undefined : '100%'}
@@ -3,6 +3,7 @@ type ImageBox = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
5
  [attr: string]: any;
6
+ class?: string | undefined;
6
7
  base?: string | undefined;
7
8
  bg?: string | undefined;
8
9
  classes?: string | undefined;
@@ -21,6 +22,7 @@ type ImageBox = {
21
22
  };
22
23
  declare const ImageBox: import("svelte").Component<{
23
24
  [attr: string]: any;
25
+ class?: string;
24
26
  base?: string;
25
27
  bg?: string;
26
28
  classes?: string;
@@ -16,7 +16,8 @@
16
16
 
17
17
  /**
18
18
  * @type {{
19
- * classes?: string,
19
+ * class?: string,
20
+ * classes?: string, // Deprecated: use 'class' instead
20
21
  * slides?: import("./typedef.js").Slide[],
21
22
  * presenterRef?: import('./Presenter.state.svelte.js').PresenterRef,
22
23
  * layoutSnippet: import('svelte').Snippet<[Slide|null, Layer]>,
@@ -25,7 +26,8 @@
25
26
  */
26
27
  let {
27
28
  // > Style
28
- classes,
29
+ class: className,
30
+ classes, // Deprecated: kept for backward compatibility
29
31
 
30
32
  // > Functional
31
33
  slides,
@@ -109,7 +111,7 @@
109
111
  });
110
112
  </script>
111
113
 
112
- <GridLayers data-feature="presenter" {classes}>
114
+ <GridLayers data-feature="presenter" class={className ?? classes ?? ''}>
113
115
  <div
114
116
  data-layer="layer1"
115
117
  style:z-index={presenter.layerA.z}
@@ -2,6 +2,7 @@ export default Presenter;
2
2
  type Presenter = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
+ class?: string | undefined;
5
6
  classes?: string | undefined;
6
7
  slides?: Slide[] | undefined;
7
8
  presenterRef?: PresenterRef | undefined;
@@ -10,6 +11,7 @@ type Presenter = {
10
11
  }>): void;
11
12
  };
12
13
  declare const Presenter: import("svelte").Component<{
14
+ class?: string;
13
15
  classes?: string;
14
16
  slides?: import("./typedef.js").Slide[];
15
17
  presenterRef?: import("./Presenter.state.svelte.js").PresenterRef;
@@ -3,9 +3,10 @@
3
3
 
4
4
  /**
5
5
  * @type {{
6
- * base?: string,
7
- * bg?: string,
8
- * classes?: string,
6
+ * class?: string,
7
+ * base?: string, // Deprecated: use 'class' instead
8
+ * bg?: string, // Deprecated: use 'class' instead
9
+ * classes?: string, // Deprecated: use 'class' instead
9
10
  * type?: string,
10
11
  * role?: 'primary' | 'secondary' | 'tertiary' | 'custom',
11
12
  * size?: 'sm' | 'md' | 'lg',
@@ -25,9 +26,10 @@
25
26
  */
26
27
  const {
27
28
  // Style
28
- base,
29
- bg,
30
- classes,
29
+ class: className,
30
+ base, // Deprecated: kept for backward compatibility
31
+ bg, // Deprecated: kept for backward compatibility
32
+ classes, // Deprecated: kept for backward compatibility
31
33
 
32
34
  type = '',
33
35
  role = 'primary',
@@ -66,7 +68,7 @@
66
68
  data-variant={variant}
67
69
  data-mode={mode}
68
70
  type={buttonType}
69
- class="{base} {bg} {classes} {stateClasses}"
71
+ class="{base ?? ''} {bg ?? ''} {className ?? classes ?? ''} {stateClasses}"
70
72
  disabled={disabled || loading}
71
73
  aria-busy={loading}
72
74
  aria-pressed={selected}
@@ -3,6 +3,7 @@ type Button = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
5
  [key: string]: any;
6
+ class?: string | undefined;
6
7
  base?: string | undefined;
7
8
  bg?: string | undefined;
8
9
  classes?: string | undefined;
@@ -24,6 +25,7 @@ type Button = {
24
25
  };
25
26
  declare const Button: import("svelte").Component<{
26
27
  [key: string]: any;
28
+ class?: string;
27
29
  base?: string;
28
30
  bg?: string;
29
31
  classes?: string;
@@ -23,8 +23,9 @@
23
23
  * theme - name of the icon theme (e.g. 'solid' or 'outline')
24
24
  *
25
25
  * @type {{
26
- * base?: string,
27
- * classes?: string
26
+ * class?: string,
27
+ * base?: string, // Deprecated: use 'class' instead
28
+ * classes?: string, // Deprecated: use 'class' instead
28
29
  * size?: string,
29
30
  * variant?: string,
30
31
  * src: import('./typedef.js').IconSource,
@@ -33,8 +34,9 @@
33
34
  */
34
35
  let {
35
36
  // Style
36
- base,
37
- classes,
37
+ class: className,
38
+ base, // Deprecated: kept for backward compatibility
39
+ classes, // Deprecated: kept for backward compatibility
38
40
 
39
41
  size = 'md',
40
42
  variant = '',
@@ -72,7 +74,7 @@
72
74
  data-variant={variant}
73
75
  {...icon.a}
74
76
  xmlns="http://www.w3.org/2000/svg"
75
- class="{base} {classes}"
77
+ class="{base ?? ''} {className ?? classes ?? ''}"
76
78
  {...attrs}
77
79
  >
78
80
  {#each icon.path ?? [] as a}
@@ -2,6 +2,7 @@ export default SteezeIcon;
2
2
  type SteezeIcon = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
+ class?: string | undefined;
5
6
  base?: string | undefined;
6
7
  classes?: string | undefined;
7
8
  size?: string | undefined;
@@ -13,6 +14,7 @@ type SteezeIcon = {
13
14
  }>): void;
14
15
  };
15
16
  declare const SteezeIcon: import("svelte").Component<{
17
+ class?: string;
16
18
  base?: string;
17
19
  classes?: string;
18
20
  size?: string;
@@ -7,9 +7,10 @@
7
7
 
8
8
  /**
9
9
  * @type {{
10
- * base?: string,
11
- * bg?: string,
12
- * classes?: string,
10
+ * class?: string,
11
+ * base?: string, // Deprecated: use 'class' instead
12
+ * bg?: string, // Deprecated: use 'class' instead
13
+ * classes?: string, // Deprecated: use 'class' instead
13
14
  * width?: 'sm' | 'md' | 'lg',
14
15
  * variant?: string,
15
16
  * children?: import('svelte').Snippet,
@@ -17,9 +18,10 @@
17
18
  */
18
19
  const {
19
20
  // Style
20
- base,
21
- bg,
22
- classes,
21
+ class: className,
22
+ base, // Deprecated: kept for backward compatibility
23
+ bg, // Deprecated: kept for backward compatibility
24
+ classes, // Deprecated: kept for backward compatibility
23
25
 
24
26
  width = 'md',
25
27
  variant = 'light',
@@ -36,7 +38,7 @@
36
38
  data-component="panel"
37
39
  data-width={width}
38
40
  data-variant={variant}
39
- class="{base} {bg} {classes}"
41
+ class="{base ?? ''} {bg ?? ''} {className ?? classes ?? ''}"
40
42
  {...attrs}
41
43
  >
42
44
  {@render children()}
@@ -2,6 +2,7 @@ export default Panel;
2
2
  type Panel = {
3
3
  $on?(type: string, callback: (e: any) => void): () => void;
4
4
  $set?(props: Partial<{
5
+ class?: string | undefined;
5
6
  base?: string | undefined;
6
7
  bg?: string | undefined;
7
8
  classes?: string | undefined;
@@ -13,6 +14,7 @@ type Panel = {
13
14
  }>): void;
14
15
  };
15
16
  declare const Panel: import("svelte").Component<{
17
+ class?: string;
16
18
  base?: string;
17
19
  bg?: string;
18
20
  classes?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.90",
3
+ "version": "0.5.92",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"