@happyvertical/smrt-ui 0.57.12 → 0.57.14

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.
@@ -1,6 +1,14 @@
1
- /** DOM adapter helpers shared by addressable control Implementations. */
2
1
  export declare function focusControl(node: HTMLElement): void;
3
2
  export declare function revealControl(node: HTMLElement): void;
3
+ /** Existing control descriptors keep their void return contract. */
4
4
  export declare function highlightControl(node: HTMLElement, durationMs?: number): void;
5
+ export declare function highlightControl(node: HTMLElement, durationMs: number, options: {
6
+ presentation: 'outline';
7
+ }): void;
8
+ export declare function highlightControl(node: HTMLElement, durationMs: number, options: {
9
+ presentation: 'spotlight';
10
+ dismissLabel: string;
11
+ onDismiss?: () => void;
12
+ }): () => void;
5
13
  export declare function emitControlChange(node: HTMLElement): void;
6
14
  //# sourceMappingURL=control-dom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"control-dom.d.ts","sourceRoot":"","sources":["../../../src/components/forms/control-dom.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAYzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAKpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAMrD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,SAAO,GAAG,IAAI,CAK3E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAMzD"}
1
+ {"version":3,"file":"control-dom.d.ts","sourceRoot":"","sources":["../../../src/components/forms/control-dom.ts"],"names":[],"mappings":"AAcA,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAKpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAMrD;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;AAC/E,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IAAE,YAAY,EAAE,SAAS,CAAA;CAAE,GACnC,IAAI,CAAC;AACR,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IACP,YAAY,EAAE,WAAW,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,GACA,MAAM,IAAI,CAAC;AAgCd,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAMzD"}
@@ -1,3 +1,4 @@
1
+ import { paintControlSpotlight } from './control-spotlight.js';
1
2
  /** DOM adapter helpers shared by addressable control Implementations. */
2
3
  const focusableControlSelector = [
3
4
  'input:not([type="hidden"]):not(:disabled)',
@@ -21,12 +22,25 @@ export function revealControl(node) {
21
22
  behavior: 'smooth',
22
23
  });
23
24
  }
24
- export function highlightControl(node, durationMs = 1600) {
25
- node.dataset.smrtHighlighted = 'true';
26
- globalThis.setTimeout(() => {
27
- if (node.isConnected)
28
- delete node.dataset.smrtHighlighted;
29
- }, durationMs);
25
+ export function highlightControl(node, durationMs = 1600, options) {
26
+ let disposed = false;
27
+ const remove = options?.presentation === 'spotlight'
28
+ ? paintControlSpotlight(node, options)
29
+ : (() => {
30
+ node.dataset.smrtHighlighted = 'true';
31
+ return () => {
32
+ delete node.dataset.smrtHighlighted;
33
+ };
34
+ })();
35
+ const timer = globalThis.setTimeout(() => cleanup(), durationMs);
36
+ const cleanup = () => {
37
+ if (disposed)
38
+ return;
39
+ disposed = true;
40
+ globalThis.clearTimeout(timer);
41
+ remove();
42
+ };
43
+ return cleanup;
30
44
  }
31
45
  export function emitControlChange(node) {
32
46
  queueMicrotask(() => {
@@ -0,0 +1,6 @@
1
+ /** Passive viewport veil around an actual control; no guide/navigation state. */
2
+ export declare function paintControlSpotlight(node: HTMLElement, options: {
3
+ dismissLabel: string;
4
+ onDismiss?: () => void;
5
+ }): () => void;
6
+ //# sourceMappingURL=control-spotlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-spotlight.d.ts","sourceRoot":"","sources":["../../../src/components/forms/control-spotlight.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,GACxD,MAAM,IAAI,CA+FZ"}
@@ -0,0 +1,96 @@
1
+ /** Passive viewport veil around an actual control; no guide/navigation state. */
2
+ export function paintControlSpotlight(node, options) {
3
+ const doc = node.ownerDocument;
4
+ const view = doc.defaultView;
5
+ if (!view || !node.isConnected)
6
+ return () => { };
7
+ const root = doc.createElement('div');
8
+ root.dataset.smrtComponent = 'ControlSpotlight';
9
+ const tokens = view.getComputedStyle(node);
10
+ Object.assign(root.style, {
11
+ position: 'fixed',
12
+ inset: '0',
13
+ pointerEvents: 'none',
14
+ zIndex: tokens.getPropertyValue('--smrt-z-index-overlay').trim() || '1200',
15
+ });
16
+ const veil = doc.createElement('div');
17
+ veil.dataset.smrtSpotlightVeil = '';
18
+ veil.setAttribute('aria-hidden', 'true');
19
+ Object.assign(veil.style, {
20
+ position: 'absolute',
21
+ inset: '0',
22
+ pointerEvents: 'none',
23
+ // Spotlight is a guidance veil, matching the contact spotlight rather
24
+ // than the theme's lighter modal scrim. Other overlays keep their tokens.
25
+ background: 'rgba(3, 5, 9, 0.72)',
26
+ });
27
+ const button = doc.createElement('button');
28
+ button.type = 'button';
29
+ button.textContent = options.dismissLabel;
30
+ button.setAttribute('aria-label', options.dismissLabel);
31
+ Object.assign(button.style, {
32
+ position: 'absolute',
33
+ insetInlineEnd: '1rem',
34
+ pointerEvents: 'auto',
35
+ cursor: 'pointer',
36
+ padding: '0.5rem 1rem',
37
+ borderRadius: tokens.getPropertyValue('--smrt-radius-medium').trim() || '0.5rem',
38
+ background: tokens.getPropertyValue('--smrt-color-surface').trim() || '#fff',
39
+ color: tokens.getPropertyValue('--smrt-color-on-surface').trim() || '#111',
40
+ border: tokens.getPropertyValue('--smrt-hairline').trim() ||
41
+ '1px solid currentColor',
42
+ font: 'inherit',
43
+ });
44
+ root.append(veil, button);
45
+ let disposed = false;
46
+ let frame = 0;
47
+ const cleanup = () => {
48
+ if (disposed)
49
+ return;
50
+ disposed = true;
51
+ view.cancelAnimationFrame(frame);
52
+ root.remove();
53
+ button.removeEventListener('click', dismiss);
54
+ };
55
+ const dismiss = () => {
56
+ cleanup();
57
+ options.onDismiss?.();
58
+ };
59
+ const update = () => {
60
+ if (disposed)
61
+ return;
62
+ // The shell exposes its occupied phone footer track on descendants.
63
+ // Read it live: a guide can remain active while the viewport crosses to phone.
64
+ const footerTrack = view
65
+ .getComputedStyle(node)
66
+ .getPropertyValue('--smrt-admin-shell-phone-bar-track')
67
+ .trim();
68
+ button.style.insetBlockEnd = `calc(1rem + ${footerTrack || 'env(safe-area-inset-bottom, 0px)'})`;
69
+ const r = node.getBoundingClientRect();
70
+ if (!node.isConnected ||
71
+ node.closest('[hidden],[inert],[aria-hidden="true"]') ||
72
+ (typeof node.checkVisibility === 'function' && !node.checkVisibility()) ||
73
+ r.width <= 0 ||
74
+ r.height <= 0 ||
75
+ r.right <= 0 ||
76
+ r.bottom <= 0 ||
77
+ r.left >= view.innerWidth ||
78
+ r.top >= view.innerHeight) {
79
+ dismiss();
80
+ return;
81
+ }
82
+ const x1 = Math.max(0, Math.round(r.left - 8));
83
+ const y1 = Math.max(0, Math.round(r.top - 8));
84
+ const x2 = Math.min(view.innerWidth, Math.round(r.right + 8));
85
+ const y2 = Math.min(view.innerHeight, Math.round(r.bottom + 8));
86
+ veil.style.clipPath = `polygon(evenodd, 0 0, 100% 0, 100% 100%, 0 100%, 0 0, ${x1}px ${y1}px, ${x1}px ${y2}px, ${x2}px ${y2}px, ${x2}px ${y1}px, ${x1}px ${y1}px)`;
87
+ // Track movement caused by scrolling, resizing or surrounding layout. No
88
+ // animation/interpolation is applied, including under reduced motion.
89
+ frame = view.requestAnimationFrame(update);
90
+ };
91
+ button.addEventListener('click', dismiss);
92
+ update();
93
+ if (!disposed)
94
+ doc.body.append(root);
95
+ return cleanup;
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-ui",
3
- "version": "0.57.12",
3
+ "version": "0.57.14",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Domain-agnostic Svelte 5 UI runtime for SMRT: primitives, i18n client, theme system, and module UI registry",
6
6
  "type": "module",
@@ -164,7 +164,7 @@
164
164
  "access": "public"
165
165
  },
166
166
  "dependencies": {
167
- "@happyvertical/smrt-types": "0.57.12",
167
+ "@happyvertical/smrt-types": "0.57.14",
168
168
  "esm-env": "^1.2.2"
169
169
  },
170
170
  "peerDependencies": {