@pie-players/pie-tool-ruler 0.1.6 → 0.1.9

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,11 +1,12 @@
1
1
  {
2
2
  "name": "@pie-players/pie-tool-ruler",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Ruler measurement tool for PIE assessment player",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/pie-framework/pie-players.git"
8
+ "url": "git+https://github.com/pie-framework/pie-players.git",
9
+ "directory": "packages/tool-ruler"
9
10
  },
10
11
  "publishConfig": {
11
12
  "access": "public"
@@ -44,9 +45,9 @@
44
45
  "unpkg": "./dist/tool-ruler.js",
45
46
  "jsdelivr": "./dist/tool-ruler.js",
46
47
  "dependencies": {
47
- "@pie-players/pie-assessment-toolkit": "0.2.5",
48
- "@pie-players/pie-players-shared": "0.2.2",
49
- "@sveltejs/kit": "^2.52.0",
48
+ "@pie-players/pie-assessment-toolkit": "0.2.9",
49
+ "@pie-players/pie-context": "0.1.1",
50
+ "@pie-players/pie-players-shared": "0.2.5",
50
51
  "daisyui": "^5.5.18",
51
52
  "moveable": "^0.53.0"
52
53
  },
@@ -64,5 +65,13 @@
64
65
  "typescript": "^5.7.0",
65
66
  "vite": "^7.0.8",
66
67
  "vite-plugin-dts": "^4.5.3"
67
- }
68
+ },
69
+ "homepage": "https://github.com/pie-framework/pie-players/tree/master/packages/tool-ruler#readme",
70
+ "bugs": {
71
+ "url": "https://github.com/pie-framework/pie-players/issues"
72
+ },
73
+ "engines": {
74
+ "node": ">=18.0.0"
75
+ },
76
+ "sideEffects": true
68
77
  }
package/tool-ruler.svelte CHANGED
@@ -1,31 +1,40 @@
1
1
  <svelte:options
2
2
  customElement={{
3
3
  tag: 'pie-tool-ruler',
4
- shadow: 'none',
4
+ shadow: 'open',
5
5
  props: {
6
6
  visible: { type: 'Boolean', attribute: 'visible' },
7
- toolId: { type: 'String', attribute: 'tool-id' },
8
- coordinator: { type: 'Object' }
7
+ toolId: { type: 'String', attribute: 'tool-id' }
9
8
  }
10
9
  }}
11
10
  />
12
11
 
13
12
  <script lang="ts">
14
- import type { IToolCoordinator } from '@pie-players/pie-assessment-toolkit';
15
- import { ZIndexLayer } from '@pie-players/pie-assessment-toolkit';
13
+ import {
14
+ connectToolRuntimeContext,
15
+ ZIndexLayer,
16
+ } from '@pie-players/pie-assessment-toolkit';
17
+ import type {
18
+ AssessmentToolkitRuntimeContext,
19
+ IToolCoordinator,
20
+ } from '@pie-players/pie-assessment-toolkit';
16
21
  import Moveable from 'moveable';
17
22
  import { onDestroy, onMount } from 'svelte';
18
23
  import rulerCm from './ruler-cm.svg';
19
24
  import rulerInches from './ruler-inches.svg';
20
25
 
21
26
  // Props
22
- let { visible = false, toolId = 'ruler', coordinator }: { visible?: boolean; toolId?: string; coordinator?: IToolCoordinator } = $props();
27
+ let { visible = false, toolId = 'ruler' }: { visible?: boolean; toolId?: string } = $props();
23
28
 
24
29
  // Check if running in browser
25
30
  const isBrowser = typeof window !== 'undefined';
26
31
 
27
32
  // State
28
33
  let containerEl = $state<HTMLDivElement | undefined>();
34
+ let runtimeContext = $state<AssessmentToolkitRuntimeContext | null>(null);
35
+ const coordinator = $derived(
36
+ runtimeContext?.toolCoordinator as IToolCoordinator | undefined,
37
+ );
29
38
  let announceText = $state('');
30
39
  let unit = $state<'inches' | 'cm'>('inches');
31
40
  let moveable: Moveable | null = null;
@@ -38,6 +47,13 @@
38
47
  const ROTATE_STEP = 5; // degrees
39
48
  const FINE_ROTATE_STEP = 1; // degrees
40
49
 
50
+ $effect(() => {
51
+ if (!containerEl) return;
52
+ return connectToolRuntimeContext(containerEl, (value: AssessmentToolkitRuntimeContext) => {
53
+ runtimeContext = value;
54
+ });
55
+ });
56
+
41
57
  let currentRuler = $derived(unit === 'inches' ? rulerInches : rulerCm);
42
58
 
43
59
  function announce(message: string) {
@@ -247,7 +263,7 @@
247
263
 
248
264
  {#if visible && isBrowser}
249
265
  <!-- Screen reader announcements -->
250
- <div class="sr-only" role="status" aria-live="polite" aria-atomic="true">
266
+ <div class="pie-sr-only" role="status" aria-live="polite" aria-atomic="true">
251
267
  {announceText}
252
268
  </div>
253
269
 
@@ -255,7 +271,7 @@
255
271
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
256
272
  <div
257
273
  bind:this={containerEl}
258
- class="ruler-frame"
274
+ class="pie-tool-ruler"
259
275
  data-moveablejs-tool-id={toolId}
260
276
  onpointerdown={() => coordinator?.bringToFront(containerEl)}
261
277
  onkeydown={handleKeyDown}
@@ -264,19 +280,24 @@
264
280
  aria-label="Ruler tool. Use arrow keys to move, Shift+arrows to rotate, PageUp/PageDown for fine rotation, U to toggle units. Current unit: {unit}"
265
281
  aria-roledescription="Draggable and rotatable ruler measurement tool"
266
282
  >
267
- <div class="ruler-container">
283
+ <div class="pie-tool-ruler__container">
268
284
  <img
269
- class="ruler"
285
+ class="pie-tool-ruler__image"
270
286
  src={currentRuler}
271
287
  alt="Ruler showing {unit}"
272
288
  draggable="false"
273
289
  />
274
290
 
275
291
  <!-- Unit toggle button group (matching production implementation style) -->
276
- <div class="btn-group" onpointerdown={(e) => e.stopPropagation()}>
292
+ <div
293
+ class="pie-tool-ruler__unit-group"
294
+ role="group"
295
+ aria-label="Ruler unit selection"
296
+ onpointerdown={(e) => e.stopPropagation()}
297
+ >
277
298
  <button
278
- class="unit-btn"
279
- class:active={unit === 'inches'}
299
+ class="pie-tool-ruler__unit-button"
300
+ class:pie-tool-ruler__unit-button--active={unit === 'inches'}
280
301
  onclick={() => {
281
302
  unit = 'inches';
282
303
  announce('Switched to inches');
@@ -285,11 +306,11 @@
285
306
  aria-label="Switch to inches"
286
307
  aria-pressed={unit === 'inches'}
287
308
  >
288
- <span class="btn-label">Inches</span>
309
+ <span class="pie-tool-ruler__unit-label">Inches</span>
289
310
  </button>
290
311
  <button
291
- class="unit-btn"
292
- class:active={unit === 'cm'}
312
+ class="pie-tool-ruler__unit-button"
313
+ class:pie-tool-ruler__unit-button--active={unit === 'cm'}
293
314
  onclick={() => {
294
315
  unit = 'cm';
295
316
  announce('Switched to centimeters');
@@ -298,7 +319,7 @@
298
319
  aria-label="Switch to centimeters"
299
320
  aria-pressed={unit === 'cm'}
300
321
  >
301
- <span class="btn-label">Centimeters</span>
322
+ <span class="pie-tool-ruler__unit-label">Centimeters</span>
302
323
  </button>
303
324
  </div>
304
325
  </div>
@@ -306,7 +327,7 @@
306
327
  {/if}
307
328
 
308
329
  <style>
309
- .sr-only {
330
+ .pie-sr-only {
310
331
  position: absolute;
311
332
  width: 1px;
312
333
  height: 1px;
@@ -318,7 +339,7 @@
318
339
  border-width: 0;
319
340
  }
320
341
 
321
- .ruler-frame {
342
+ .pie-tool-ruler {
322
343
  border-left: 1px solid #000;
323
344
  border-right: 1px solid #000;
324
345
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); /* Matching production implementation shadow */
@@ -333,35 +354,35 @@
333
354
  width: 540px; /* Matching production implementation frame width */
334
355
  }
335
356
 
336
- .ruler-frame:focus {
357
+ .pie-tool-ruler:focus {
337
358
  outline: 3px solid #4A90E2;
338
359
  outline-offset: 2px;
339
360
  }
340
361
 
341
- .ruler-frame:focus-visible {
362
+ .pie-tool-ruler:focus-visible {
342
363
  outline: 3px solid #4A90E2;
343
364
  outline-offset: 2px;
344
365
  }
345
366
 
346
- .ruler-container {
367
+ .pie-tool-ruler__container {
347
368
  background-color: rgb(255 255 255 / 90%); /* Matching production implementation semi-transparent white background */
348
369
  position: relative;
349
370
  }
350
371
 
351
- .ruler-container,
352
- .ruler {
372
+ .pie-tool-ruler__container,
373
+ .pie-tool-ruler__image {
353
374
  height: 100px; /* Matching production implementation ruler height */
354
375
  width: 864px; /* Matching production implementation ruler width */
355
376
  }
356
377
 
357
- .ruler {
378
+ .pie-tool-ruler__image {
358
379
  position: relative;
359
380
  z-index: 2;
360
381
  display: block;
361
382
  }
362
383
 
363
384
  /* Unit toggle button group (matching production implementation style) */
364
- .btn-group {
385
+ .pie-tool-ruler__unit-group {
365
386
  border: 1px solid var(--pie-primary, #3f51b5); /* Matching production implementation primary color */
366
387
  bottom: 0.5rem; /* Matching production implementation positioning */
367
388
  left: 0.5rem; /* Matching production implementation positioning */
@@ -373,7 +394,7 @@
373
394
  overflow: hidden;
374
395
  }
375
396
 
376
- .unit-btn {
397
+ .pie-tool-ruler__unit-button {
377
398
  background: white;
378
399
  border: none;
379
400
  border-right: 1px solid var(--pie-primary, #3f51b5);
@@ -384,25 +405,25 @@
384
405
  transition: background-color 0.2s, color 0.2s;
385
406
  }
386
407
 
387
- .unit-btn:last-child {
408
+ .pie-tool-ruler__unit-button:last-child {
388
409
  border-right: none;
389
410
  }
390
411
 
391
- .unit-btn:hover {
412
+ .pie-tool-ruler__unit-button:hover {
392
413
  background-color: rgba(63, 81, 181, 0.1);
393
414
  }
394
415
 
395
- .unit-btn.active {
416
+ .pie-tool-ruler__unit-button.pie-tool-ruler__unit-button--active {
396
417
  background-color: var(--pie-primary, #3f51b5);
397
418
  color: white;
398
419
  }
399
420
 
400
- .unit-btn:focus-visible {
421
+ .pie-tool-ruler__unit-button:focus-visible {
401
422
  outline: 2px solid var(--pie-primary, #3f51b5);
402
423
  outline-offset: 2px;
403
424
  }
404
425
 
405
- .btn-label {
426
+ .pie-tool-ruler__unit-label {
406
427
  display: inline-block;
407
428
  font-size: 12px;
408
429
  line-height: 1.4;