@dxos/react-ui-attention 0.8.4-main.4a85c3132b → 0.8.4-main.51f1e5ca51

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 (44) hide show
  1. package/dist/lib/browser/{chunk-TAZUDNJI.mjs → chunk-DAIZNFKL.mjs} +118 -155
  2. package/dist/lib/browser/chunk-DAIZNFKL.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +14 -10
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +1 -2
  7. package/dist/lib/browser/testing/index.mjs.map +1 -1
  8. package/dist/lib/browser/types.mjs +0 -6
  9. package/dist/lib/node-esm/{chunk-FT553KKP.mjs → chunk-HZTQDMTS.mjs} +118 -154
  10. package/dist/lib/node-esm/chunk-HZTQDMTS.mjs.map +7 -0
  11. package/dist/lib/node-esm/index.mjs +14 -10
  12. package/dist/lib/node-esm/index.mjs.map +3 -3
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +1 -2
  15. package/dist/lib/node-esm/testing/index.mjs.map +1 -1
  16. package/dist/lib/node-esm/types.mjs +0 -6
  17. package/dist/types/src/attention.d.ts +41 -10
  18. package/dist/types/src/attention.d.ts.map +1 -1
  19. package/dist/types/src/components/AttentionGlyph.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/AttentionProvider.d.ts +8 -10
  21. package/dist/types/src/components/AttentionProvider.d.ts.map +1 -1
  22. package/dist/types/src/components/AttentionProvider.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/SelectionProvider.d.ts.map +1 -1
  24. package/dist/types/src/index.d.ts +0 -1
  25. package/dist/types/src/index.d.ts.map +1 -1
  26. package/dist/types/src/selection.d.ts.map +1 -1
  27. package/dist/types/src/testing/decorators/withAttention.d.ts.map +1 -1
  28. package/dist/types/src/types.d.ts +0 -1
  29. package/dist/types/src/types.d.ts.map +1 -1
  30. package/dist/types/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +15 -25
  32. package/src/attention.test.ts +179 -23
  33. package/src/attention.ts +132 -54
  34. package/src/components/AttentionGlyph.tsx +1 -1
  35. package/src/components/AttentionProvider.stories.tsx +0 -1
  36. package/src/components/AttentionProvider.tsx +16 -43
  37. package/src/index.ts +0 -1
  38. package/src/types.ts +0 -3
  39. package/dist/lib/browser/chunk-PAZBZOO2.mjs +0 -7
  40. package/dist/lib/browser/chunk-PAZBZOO2.mjs.map +0 -7
  41. package/dist/lib/browser/chunk-TAZUDNJI.mjs.map +0 -7
  42. package/dist/lib/node-esm/chunk-FT553KKP.mjs.map +0 -7
  43. package/dist/lib/node-esm/chunk-PMGNPL4M.mjs +0 -9
  44. package/dist/lib/node-esm/chunk-PMGNPL4M.mjs.map +0 -7
@@ -1,38 +1,30 @@
1
- import {
2
- ATTENDABLE_PATH_SEPARATOR
3
- } from "./chunk-PAZBZOO2.mjs";
4
-
5
1
  // src/attention.ts
6
2
  import { Atom } from "@effect-atom/atom-react";
7
- import { ComplexMap } from "@dxos/util";
8
- var stringKey = (key) => key.join(",");
9
3
  var AttentionManager = class {
10
4
  _registry;
11
- // Each attention path is associated with an attention atom.
12
- // The lookup is not a reactive object to ensure that attention for each path is subscribable independently.
13
- _map = new ComplexMap(stringKey);
5
+ _map = /* @__PURE__ */ new Map();
14
6
  _currentAtom;
15
7
  constructor(_registry, initial = []) {
16
8
  this._registry = _registry;
17
- this._currentAtom = Atom.make([]);
9
+ this._currentAtom = Atom.make([]).pipe(Atom.keepAlive);
18
10
  if (initial.length > 0) {
19
11
  this.update(initial);
20
12
  }
21
13
  }
22
14
  /**
23
- * Atom for the currently attended element path.
15
+ * Atom for the currently attended element IDs.
24
16
  */
25
17
  get current() {
26
18
  return this._currentAtom;
27
19
  }
28
20
  /**
29
- * Gets the currently attended element path.
21
+ * Gets the currently attended element IDs.
30
22
  */
31
23
  getCurrent() {
32
24
  return this._registry.get(this._currentAtom);
33
25
  }
34
26
  /**
35
- * Subscribe to changes in the current attention path.
27
+ * Subscribe to changes in the current attention IDs.
36
28
  */
37
29
  subscribeCurrent(cb) {
38
30
  this._registry.get(this._currentAtom);
@@ -41,30 +33,30 @@ var AttentionManager = class {
41
33
  });
42
34
  }
43
35
  /**
44
- * All attention paths.
36
+ * All tracked qualified IDs.
45
37
  */
46
38
  keys() {
47
39
  return Array.from(this._map.keys());
48
40
  }
49
41
  /**
50
- * Get the attention state for a given path.
42
+ * Get the attention state for a given qualified ID.
51
43
  */
52
- get(key) {
53
- const atom = this._getAtom(key);
44
+ get(id) {
45
+ const atom = this._getAtom(id);
54
46
  return this._registry.get(atom);
55
47
  }
56
48
  /**
57
- * Subscribe to changes in the attention state for a given path.
49
+ * Subscribe to changes in the attention state for a given qualified ID.
58
50
  */
59
- subscribe(key, cb) {
60
- const atom = this._getAtom(key);
51
+ subscribe(id, cb) {
52
+ const atom = this._getAtom(id);
61
53
  this._registry.get(atom);
62
54
  return this._registry.subscribe(atom, () => {
63
55
  cb(this._registry.get(atom));
64
56
  });
65
57
  }
66
- _getAtom(key) {
67
- const existing = this._map.get(key);
58
+ _getAtom(id) {
59
+ const existing = this._map.get(id);
68
60
  if (existing) {
69
61
  return existing;
70
62
  }
@@ -72,43 +64,70 @@ var AttentionManager = class {
72
64
  hasAttention: false,
73
65
  isAncestor: false,
74
66
  isRelated: false
75
- });
76
- this._map.set(key, newAtom);
67
+ }).pipe(Atom.keepAlive);
68
+ this._map.set(id, newAtom);
77
69
  return newAtom;
78
70
  }
79
71
  /**
80
72
  * Update the currently attended element.
73
+ * Takes the array of qualified IDs collected from the DOM; the first element is the primary attended item.
74
+ * Ancestry is derived from the progressive prefixes of the primary ID.
75
+ * Relatedness is derived from the segment ID: any tracked key whose last `/` segment matches the
76
+ * attended ID's segment ID is marked `isRelated`. Additionally, if the primary ID is a linked segment
77
+ * (starts with `~`), its immediate parent gets `isRelated` alongside `isAncestor`.
81
78
  *
82
79
  * @internal
83
80
  */
84
- update(nextKey) {
85
- const currentKey = this.getCurrent();
86
- const currentRelatedTo = currentKey[0];
87
- const nextRelatedTo = nextKey[0];
88
- this._getAtom([
89
- nextRelatedTo
90
- ]);
91
- const currentRelatedKeys = this.keys().filter((key) => key[0] === currentRelatedTo);
92
- const nextRelatedKeys = this.keys().filter((key) => key[0] === nextRelatedTo && stringKey(key) !== stringKey(nextKey));
93
- const prevRelatedKeys = currentRelatedKeys.filter((curr) => !nextRelatedKeys.find((next) => stringKey(curr) === stringKey(next)));
94
- const currentAncestorKeys = currentKey.slice(1).map((_, i) => currentKey.slice(i + 1, currentKey.length));
95
- const nextAncestorKeys = nextKey.slice(1).map((_, i) => nextKey.slice(i + 1, nextKey.length));
96
- const prevAncestorKeys = currentAncestorKeys.filter((curr) => !nextAncestorKeys.find((next) => stringKey(curr) === stringKey(next)));
97
- this._registry.set(this._currentAtom, nextKey);
98
- prevRelatedKeys.forEach((key) => this._set(key, {}));
99
- prevAncestorKeys.forEach((key) => this._set(key, {}));
100
- nextRelatedKeys.forEach((key) => this._set(key, {
101
- isRelated: true
102
- }));
103
- nextAncestorKeys.forEach((key) => this._set(key, {
104
- isAncestor: true
105
- }));
106
- this._set(nextKey, {
107
- hasAttention: true
108
- });
81
+ update(nextIds) {
82
+ const primaryId = nextIds[0];
83
+ if (!primaryId) {
84
+ return;
85
+ }
86
+ const currentIds = this.getCurrent();
87
+ const prevPrimaryId = currentIds[0];
88
+ if (prevPrimaryId) {
89
+ const prevPrefixes = expandAttendableId(prevPrimaryId);
90
+ for (const prefix of prevPrefixes) {
91
+ this._set(prefix, {});
92
+ }
93
+ const prevSegmentId = getSegmentId(prevPrimaryId);
94
+ for (const key of this.keys()) {
95
+ if (getSegmentId(key) === prevSegmentId) {
96
+ this._set(key, {});
97
+ }
98
+ }
99
+ }
100
+ this._registry.set(this._currentAtom, nextIds);
101
+ const prefixes = expandAttendableId(primaryId);
102
+ const prefixSet = new Set(prefixes);
103
+ const linkedParent = isLinkedSegment(primaryId) ? getParentId(primaryId) : void 0;
104
+ for (const prefix of prefixes) {
105
+ if (prefix === primaryId) {
106
+ this._set(prefix, {
107
+ hasAttention: true
108
+ });
109
+ } else if (prefix === linkedParent) {
110
+ this._set(prefix, {
111
+ isAncestor: true,
112
+ isRelated: true
113
+ });
114
+ } else {
115
+ this._set(prefix, {
116
+ isAncestor: true
117
+ });
118
+ }
119
+ }
120
+ const segmentId = getSegmentId(primaryId);
121
+ for (const key of this.keys()) {
122
+ if (!prefixSet.has(key) && getSegmentId(key) === segmentId) {
123
+ this._set(key, {
124
+ isRelated: true
125
+ });
126
+ }
127
+ }
109
128
  }
110
- _set(key, attention) {
111
- const atom = this._getAtom(key);
129
+ _set(id, attention) {
130
+ const atom = this._getAtom(id);
112
131
  this._registry.set(atom, {
113
132
  hasAttention: attention.hasAttention ?? false,
114
133
  isAncestor: attention.isAncestor ?? false,
@@ -128,7 +147,7 @@ var getAttendables = (selector, cursor, acc = []) => {
128
147
  return getAttendables(selector, trigger, acc);
129
148
  }
130
149
  } else {
131
- acc.push(...attendableId.split(ATTENDABLE_PATH_SEPARATOR));
150
+ acc.push(attendableId);
132
151
  return !closestAttendable.parentElement ? acc : getAttendables(selector, closestAttendable.parentElement, acc);
133
152
  }
134
153
  }
@@ -136,6 +155,30 @@ var getAttendables = (selector, cursor, acc = []) => {
136
155
  ...new Set(acc)
137
156
  ];
138
157
  };
158
+ var LINKED_PREFIX = "~";
159
+ var expandAttendableId = (qualifiedId) => {
160
+ const segments = qualifiedId.split("/");
161
+ return segments.map((_, index) => segments.slice(0, index + 1).join("/"));
162
+ };
163
+ var isLinkedSegment = (qualifiedId) => {
164
+ const lastSegment = qualifiedId.split("/").pop() ?? "";
165
+ return lastSegment.startsWith(LINKED_PREFIX);
166
+ };
167
+ var linkedSegment = (variant) => `${LINKED_PREFIX}${variant}`;
168
+ var getLinkedVariant = (qualifiedId) => {
169
+ const lastSegment = qualifiedId.split("/").pop() ?? "";
170
+ return lastSegment.startsWith(LINKED_PREFIX) ? lastSegment.slice(LINKED_PREFIX.length) : lastSegment;
171
+ };
172
+ var getParentId = (qualifiedId) => {
173
+ if (!qualifiedId) {
174
+ return void 0;
175
+ }
176
+ const lastSlash = qualifiedId.lastIndexOf("/");
177
+ return lastSlash > 0 ? qualifiedId.slice(0, lastSlash) : void 0;
178
+ };
179
+ var getSegmentId = (qualifiedId) => {
180
+ return qualifiedId.split("/").pop() ?? qualifiedId;
181
+ };
139
182
 
140
183
  // src/components/AttentionProvider.tsx
141
184
  import { RegistryContext } from "@effect-atom/atom-react";
@@ -151,8 +194,7 @@ var ATTENTION_NAME = "Attention";
151
194
  var ATTENDABLE_ATTRIBUTE = "data-attendable-id";
152
195
  var ATTENTION_SOURCE_ATTRIBUTE = "data-w-attention-source";
153
196
  var [AttentionContextProvider, useAttentionContext] = createContext(ATTENTION_NAME, {
154
- attention: void 0,
155
- path: []
197
+ attention: void 0
156
198
  });
157
199
  var UNKNOWN_ATTENDABLE = {
158
200
  hasAttention: false,
@@ -160,32 +202,21 @@ var UNKNOWN_ATTENDABLE = {
160
202
  isRelated: false
161
203
  };
162
204
  var useAttention = (attendableId) => {
163
- const { attention, path } = useAttentionContext(ATTENTION_NAME);
205
+ const { attention } = useAttentionContext(ATTENTION_NAME);
164
206
  const [state, setState] = useState(UNKNOWN_ATTENDABLE);
165
- const key = useMemo(() => {
166
- if (!attendableId) {
167
- return void 0;
168
- }
169
- return [
170
- ...attendableId.split(ATTENDABLE_PATH_SEPARATOR),
171
- ...path
172
- ];
173
- }, [
174
- attendableId,
175
- path
176
- ]);
177
207
  useEffect(() => {
178
- if (!key || !attention) {
208
+ if (!attendableId || !attention) {
179
209
  setState(UNKNOWN_ATTENDABLE);
180
210
  return;
181
211
  }
182
- setState(attention.get(key));
183
- return attention.subscribe(key, (newState) => {
212
+ const currentState = attention.get(attendableId);
213
+ setState(currentState);
214
+ return attention.subscribe(attendableId, (newState) => {
184
215
  setState(newState);
185
216
  });
186
217
  }, [
187
218
  attention,
188
- key
219
+ attendableId
189
220
  ]);
190
221
  return state;
191
222
  };
@@ -220,10 +251,6 @@ var useAttentionAttributes = (attendableId) => {
220
251
  hasAttention
221
252
  ]);
222
253
  };
223
- var useAttentionPath = () => {
224
- const { path } = useAttentionContext(ATTENTION_NAME);
225
- return path;
226
- };
227
254
  var RootAttentionProvider = ({ children, attention: propsAttention, onChange }) => {
228
255
  const registry = useContext(RegistryContext);
229
256
  const attention = useDefaultValue(propsAttention, () => new AttentionManager(registry));
@@ -231,12 +258,7 @@ var RootAttentionProvider = ({ children, attention: propsAttention, onChange })
231
258
  log("focus", {
232
259
  related: event.relatedTarget,
233
260
  target: event.target
234
- }, {
235
- F: __dxlog_file,
236
- L: 130,
237
- S: void 0,
238
- C: (f, a) => f(...a)
239
- });
261
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 83, S: void 0 });
240
262
  const selector = [
241
263
  "[data-attendable-id]",
242
264
  ...Array.from(document.querySelectorAll("[aria-controls]")).map((el) => `[id="${el.getAttribute("aria-controls")}"]`)
@@ -249,35 +271,20 @@ var RootAttentionProvider = ({ children, attention: propsAttention, onChange })
249
271
  }
250
272
  };
251
273
  return /* @__PURE__ */ React.createElement(AttentionContextProvider, {
252
- attention,
253
- path: []
274
+ attention
254
275
  }, /* @__PURE__ */ React.createElement("div", {
255
276
  role: "none",
256
277
  className: "contents",
257
278
  onFocusCapture: handleFocus
258
279
  }, children));
259
280
  };
260
- var AttentionProvider = ({ id, children }) => {
261
- const { attention, path } = useAttentionContext(ATTENTION_NAME);
262
- const nextPath = useMemo(() => [
263
- id,
264
- ...path
265
- ], [
266
- id,
267
- path
268
- ]);
269
- return /* @__PURE__ */ React.createElement(AttentionContextProvider, {
270
- attention,
271
- path: nextPath
272
- }, children);
273
- };
274
281
  var AttendableContainer = /* @__PURE__ */ forwardRef(({ id, classNames, children, asChild, ...props }, forwardedRef) => {
275
282
  const attentionAttrs = useAttentionAttributes(id);
276
283
  const Comp = asChild ? Slot : Primitive.div;
277
284
  return /* @__PURE__ */ React.createElement(Comp, {
278
285
  role: "none",
279
- ...attentionAttrs,
280
286
  ...props,
287
+ ...attentionAttrs,
281
288
  className: mx("dx-attention-surface", props.tabIndex === 0 && "dx-focus-ring-inset-over-all", classNames),
282
289
  ref: forwardedRef
283
290
  }, children);
@@ -384,15 +391,7 @@ var SelectionManager = class {
384
391
  // TODO(burdon): Disambiguate with getSelection?
385
392
  getSelected(contextId, mode = "multi") {
386
393
  const selection = this.getSelection(contextId, mode);
387
- invariant(selection?.mode === mode, "Selection mode mismatch", {
388
- F: __dxlog_file2,
389
- L: 134,
390
- S: this,
391
- A: [
392
- "selection?.mode === mode",
393
- "'Selection mode mismatch'"
394
- ]
395
- });
394
+ invariant(selection?.mode === mode, "Selection mode mismatch", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 105, S: this, A: ["selection?.mode === mode", "'Selection mode mismatch'"] });
396
395
  return Match.type().pipe(Match.when({
397
396
  mode: "single"
398
397
  }, (s) => s.id), Match.when({
@@ -408,15 +407,7 @@ var SelectionManager = class {
408
407
  }
409
408
  updateSingle(contextId, id) {
410
409
  const selection = this.getSelection(contextId, "single");
411
- invariant(selection?.mode === "single", "Selection mode is not single", {
412
- F: __dxlog_file2,
413
- L: 147,
414
- S: this,
415
- A: [
416
- "selection?.mode === 'single'",
417
- "'Selection mode is not single'"
418
- ]
419
- });
410
+ invariant(selection?.mode === "single", "Selection mode is not single", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 122, S: this, A: ["selection?.mode === 'single'", "'Selection mode is not single'"] });
420
411
  this._registry.update(this._state, (state) => ({
421
412
  selections: {
422
413
  ...state.selections,
@@ -429,15 +420,7 @@ var SelectionManager = class {
429
420
  }
430
421
  updateMulti(contextId, ids) {
431
422
  const selection = this.getSelection(contextId, "multi");
432
- invariant(selection?.mode === "multi", "Selection mode is not multi", {
433
- F: __dxlog_file2,
434
- L: 158,
435
- S: this,
436
- A: [
437
- "selection?.mode === 'multi'",
438
- "'Selection mode is not multi'"
439
- ]
440
- });
423
+ invariant(selection?.mode === "multi", "Selection mode is not multi", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 135, S: this, A: ["selection?.mode === 'multi'", "'Selection mode is not multi'"] });
441
424
  this._registry.update(this._state, (state) => ({
442
425
  selections: {
443
426
  ...state.selections,
@@ -452,15 +435,7 @@ var SelectionManager = class {
452
435
  }
453
436
  updateRange(contextId, from, to) {
454
437
  const selection = this.getSelection(contextId, "range");
455
- invariant(selection?.mode === "range", "Selection mode is not range", {
456
- F: __dxlog_file2,
457
- L: 169,
458
- S: this,
459
- A: [
460
- "selection?.mode === 'range'",
461
- "'Selection mode is not range'"
462
- ]
463
- });
438
+ invariant(selection?.mode === "range", "Selection mode is not range", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 150, S: this, A: ["selection?.mode === 'range'", "'Selection mode is not range'"] });
464
439
  this._registry.update(this._state, (state) => ({
465
440
  selections: {
466
441
  ...state.selections,
@@ -474,15 +449,7 @@ var SelectionManager = class {
474
449
  }
475
450
  updateMultiRange(contextId, ranges) {
476
451
  const selection = this.getSelection(contextId, "multi-range");
477
- invariant(selection?.mode === "multi-range", "Selection mode is not multi-range", {
478
- F: __dxlog_file2,
479
- L: 180,
480
- S: this,
481
- A: [
482
- "selection?.mode === 'multi-range'",
483
- "'Selection mode is not multi-range'"
484
- ]
485
- });
452
+ invariant(selection?.mode === "multi-range", "Selection mode is not multi-range", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 164, S: this, A: ["selection?.mode === 'multi-range'", "'Selection mode is not multi-range'"] });
486
453
  this._registry.update(this._state, (state) => ({
487
454
  selections: {
488
455
  ...state.selections,
@@ -531,15 +498,7 @@ var SelectionManager = class {
531
498
  }
532
499
  toggleSelection(contextId, id) {
533
500
  const selection = this.getSelection(contextId, "multi");
534
- invariant(selection?.mode === "multi", "Selection mode is not multi", {
535
- F: __dxlog_file2,
536
- L: 213,
537
- S: this,
538
- A: [
539
- "selection?.mode === 'multi'",
540
- "'Selection mode is not multi'"
541
- ]
542
- });
501
+ invariant(selection?.mode === "multi", "Selection mode is not multi", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 213, S: this, A: ["selection?.mode === 'multi'", "'Selection mode is not multi'"] });
543
502
  const newIds = selection.ids.includes(id) ? selection.ids.filter((existingId) => existingId !== id) : [
544
503
  ...selection.ids,
545
504
  id
@@ -682,6 +641,12 @@ var useSelectionActions = (contextIds, mode = "multi") => {
682
641
  export {
683
642
  AttentionManager,
684
643
  getAttendables,
644
+ expandAttendableId,
645
+ isLinkedSegment,
646
+ linkedSegment,
647
+ getLinkedVariant,
648
+ getParentId,
649
+ getSegmentId,
685
650
  ATTENTION_NAME,
686
651
  ATTENDABLE_ATTRIBUTE,
687
652
  ATTENTION_SOURCE_ATTRIBUTE,
@@ -689,9 +654,7 @@ export {
689
654
  useAttention,
690
655
  useAttended,
691
656
  useAttentionAttributes,
692
- useAttentionPath,
693
657
  RootAttentionProvider,
694
- AttentionProvider,
695
658
  AttendableContainer,
696
659
  SelectionSchema,
697
660
  defaultSelection,
@@ -702,4 +665,4 @@ export {
702
665
  useSelected,
703
666
  useSelectionActions
704
667
  };
705
- //# sourceMappingURL=chunk-TAZUDNJI.mjs.map
668
+ //# sourceMappingURL=chunk-DAIZNFKL.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/attention.ts", "../../../src/components/AttentionProvider.tsx", "../../../src/selection.ts", "../../../src/components/SelectionProvider.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Atom, type Registry } from '@effect-atom/atom-react';\n\nimport { type Attention } from './types';\n\n/**\n * Manages attention state for an application.\n * Attention keys are slash-qualified graph IDs; ancestry is derived from progressive prefixes.\n */\nexport class AttentionManager {\n private readonly _map = new Map<string, Atom.Writable<Attention>>();\n private readonly _currentAtom: Atom.Writable<string[]>;\n\n constructor(\n private readonly _registry: Registry.Registry,\n initial: string[] = [],\n ) {\n this._currentAtom = Atom.make<string[]>([]).pipe(Atom.keepAlive);\n if (initial.length > 0) {\n this.update(initial);\n }\n }\n\n /**\n * Atom for the currently attended element IDs.\n */\n get current(): Atom.Atom<string[]> {\n return this._currentAtom;\n }\n\n /**\n * Gets the currently attended element IDs.\n */\n getCurrent(): readonly string[] {\n return this._registry.get(this._currentAtom);\n }\n\n /**\n * Subscribe to changes in the current attention IDs.\n */\n subscribeCurrent(cb: (current: readonly string[]) => void): () => void {\n this._registry.get(this._currentAtom);\n return this._registry.subscribe(this._currentAtom, () => {\n cb(this._registry.get(this._currentAtom));\n });\n }\n\n /**\n * All tracked qualified IDs.\n */\n keys(): string[] {\n return Array.from(this._map.keys());\n }\n\n /**\n * Get the attention state for a given qualified ID.\n */\n get(id: string): Attention {\n const atom = this._getAtom(id);\n return this._registry.get(atom);\n }\n\n /**\n * Subscribe to changes in the attention state for a given qualified ID.\n */\n subscribe(id: string, cb: (attention: Attention) => void): () => void {\n const atom = this._getAtom(id);\n this._registry.get(atom);\n return this._registry.subscribe(atom, () => {\n cb(this._registry.get(atom));\n });\n }\n\n private _getAtom(id: string): Atom.Writable<Attention> {\n const existing = this._map.get(id);\n if (existing) {\n return existing;\n }\n\n const newAtom = Atom.make<Attention>({ hasAttention: false, isAncestor: false, isRelated: false }).pipe(\n Atom.keepAlive,\n );\n this._map.set(id, newAtom);\n return newAtom;\n }\n\n /**\n * Update the currently attended element.\n * Takes the array of qualified IDs collected from the DOM; the first element is the primary attended item.\n * Ancestry is derived from the progressive prefixes of the primary ID.\n * Relatedness is derived from the segment ID: any tracked key whose last `/` segment matches the\n * attended ID's segment ID is marked `isRelated`. Additionally, if the primary ID is a linked segment\n * (starts with `~`), its immediate parent gets `isRelated` alongside `isAncestor`.\n *\n * @internal\n */\n update(nextIds: string[]): void {\n const primaryId = nextIds[0];\n if (!primaryId) {\n return;\n }\n\n const currentIds = this.getCurrent();\n const prevPrimaryId = currentIds[0];\n // Clear previous attention state: ancestors, primary, and related keys.\n if (prevPrimaryId) {\n const prevPrefixes = expandAttendableId(prevPrimaryId);\n for (const prefix of prevPrefixes) {\n this._set(prefix, {});\n }\n const prevSegmentId = getSegmentId(prevPrimaryId);\n for (const key of this.keys()) {\n if (getSegmentId(key) === prevSegmentId) {\n this._set(key, {});\n }\n }\n }\n\n this._registry.set(this._currentAtom, nextIds);\n\n // Set ancestors and primary.\n const prefixes = expandAttendableId(primaryId);\n const prefixSet = new Set(prefixes);\n const linkedParent = isLinkedSegment(primaryId) ? getParentId(primaryId) : undefined;\n\n for (const prefix of prefixes) {\n if (prefix === primaryId) {\n this._set(prefix, { hasAttention: true });\n } else if (prefix === linkedParent) {\n this._set(prefix, { isAncestor: true, isRelated: true });\n } else {\n this._set(prefix, { isAncestor: true });\n }\n }\n\n // Set related keys: any tracked key sharing the same segment ID.\n const segmentId = getSegmentId(primaryId);\n for (const key of this.keys()) {\n if (!prefixSet.has(key) && getSegmentId(key) === segmentId) {\n this._set(key, { isRelated: true });\n }\n }\n }\n\n private _set(id: string, attention: Partial<Attention>): void {\n const atom = this._getAtom(id);\n this._registry.set(atom, {\n hasAttention: attention.hasAttention ?? false,\n isAncestor: attention.isAncestor ?? false,\n isRelated: attention.isRelated ?? false,\n });\n }\n}\n\n/**\n * Accumulates all attendable IDs between the element provided and the root, inclusive.\n * Each `data-attendable-id` value is treated as a single qualified ID (no splitting).\n */\nexport const getAttendables = (selector: string, cursor: Element, acc: string[] = []): string[] => {\n // Find the closest element with `data-attendable-id`, if any; start from cursor and move up the DOM tree.\n const closestAttendable = cursor.closest(selector);\n if (closestAttendable) {\n const attendableId = closestAttendable.getAttribute('data-attendable-id');\n if (!attendableId) {\n // This has an id of an aria-controls elsewhere on the page, move cursor to that trigger.\n const trigger = document.querySelector(`[aria-controls=\"${closestAttendable.getAttribute('id')}\"]`);\n if (!trigger) {\n return acc;\n } else {\n return getAttendables(selector, trigger, acc);\n }\n } else {\n acc.push(attendableId);\n return !closestAttendable.parentElement ? acc : getAttendables(selector, closestAttendable.parentElement, acc);\n }\n }\n\n return [...new Set(acc)];\n};\n\nexport type AttendableId = { attendableId?: string };\n\nexport type Related = { related?: boolean };\n\n/**\n * Prefix for linked segments. A linked segment's attention state is shared with its parent:\n * when a linked node has attention, the parent is marked as both ancestor and related.\n */\nconst LINKED_PREFIX = '~';\n\n/**\n * Decompose a qualified graph ID into progressive prefixes for ancestry tracking.\n * e.g. `root/a/b/c` yields `['root', 'root/a', 'root/a/b', 'root/a/b/c']`.\n */\nexport const expandAttendableId = (qualifiedId: string): string[] => {\n const segments = qualifiedId.split('/');\n return segments.map((_, index) => segments.slice(0, index + 1).join('/'));\n};\n\n/**\n * Whether the last segment of a qualified ID is a linked segment (starts with `~`).\n * Linked segments share their attention state with the parent node.\n */\nexport const isLinkedSegment = (qualifiedId: string): boolean => {\n const lastSegment = qualifiedId.split('/').pop() ?? '';\n return lastSegment.startsWith(LINKED_PREFIX);\n};\n\n/**\n * Build a linked segment ID from a variant name (e.g., `'settings'` -> `'~settings'`).\n * Nodes identified by linked segments share their attention state with the parent node.\n */\nexport const linkedSegment = (variant: string): string => `${LINKED_PREFIX}${variant}`;\n\n/**\n * Extract the variant name from the last segment of a qualified ID, stripping the linked prefix.\n * e.g. `'root/space/obj/~settings'` -> `'settings'`.\n * If the segment is not linked (no `~` prefix), returns the segment as-is.\n */\nexport const getLinkedVariant = (qualifiedId: string): string => {\n const lastSegment = qualifiedId.split('/').pop() ?? '';\n return lastSegment.startsWith(LINKED_PREFIX) ? lastSegment.slice(LINKED_PREFIX.length) : lastSegment;\n};\n\n/**\n * Get the parent qualified ID (everything before the last `/` segment).\n */\nexport const getParentId = (qualifiedId: string | undefined): string | undefined => {\n if (!qualifiedId) {\n return undefined;\n }\n\n const lastSlash = qualifiedId.lastIndexOf('/');\n return lastSlash > 0 ? qualifiedId.slice(0, lastSlash) : undefined;\n};\n\n/**\n * Extract the segment ID (last segment) of a qualified ID.\n */\nexport const getSegmentId = (qualifiedId: string): string => {\n return qualifiedId.split('/').pop() ?? qualifiedId;\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { RegistryContext } from '@effect-atom/atom-react';\nimport { createContext } from '@radix-ui/react-context';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { Slot } from '@radix-ui/react-slot';\nimport React, {\n type ComponentPropsWithRef,\n type FocusEvent,\n type PropsWithChildren,\n forwardRef,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nimport { log } from '@dxos/log';\nimport { useDefaultValue } from '@dxos/react-hooks';\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\n\nimport { AttentionManager, getAttendables } from '../attention';\nimport { type Attention } from '../types';\n\nconst ATTENTION_NAME = 'Attention';\nconst ATTENDABLE_ATTRIBUTE = 'data-attendable-id';\nconst ATTENTION_SOURCE_ATTRIBUTE = 'data-w-attention-source';\n\ntype AttentionContextValue = {\n attention: AttentionManager;\n};\n\nconst [AttentionContextProvider, useAttentionContext] = createContext<AttentionContextValue>(ATTENTION_NAME, {\n attention: undefined as unknown as AttentionManager,\n});\n\nconst UNKNOWN_ATTENDABLE = { hasAttention: false, isAncestor: false, isRelated: false } as Attention;\n\n/**\n * Subscribe to the attention state for a qualified graph ID.\n */\nconst useAttention = (attendableId?: string): Attention => {\n const { attention } = useAttentionContext(ATTENTION_NAME);\n const [state, setState] = useState<Attention>(UNKNOWN_ATTENDABLE);\n\n useEffect(() => {\n if (!attendableId || !attention) {\n setState(UNKNOWN_ATTENDABLE);\n return;\n }\n\n const currentState = attention.get(attendableId);\n setState(currentState);\n\n return attention.subscribe(attendableId, (newState) => {\n setState(newState);\n });\n }, [attention, attendableId]);\n\n return state;\n};\n\nconst useAttended = () => {\n const { attention } = useAttentionContext(ATTENTION_NAME);\n const [current, setCurrent] = useState<readonly string[]>([]);\n\n useEffect(() => {\n if (!attention) {\n return;\n }\n\n setCurrent(attention.getCurrent());\n\n return attention.subscribeCurrent((newCurrent) => {\n setCurrent(newCurrent);\n });\n }, [attention]);\n\n return current;\n};\n\n/**\n * Computes HTML element attributes to apply so the attention system can detect changes.\n */\nconst useAttentionAttributes = (attendableId?: string) => {\n const { hasAttention } = useAttention(attendableId);\n return useMemo(() => {\n const attributes: Record<string, string | undefined> = { [ATTENDABLE_ATTRIBUTE]: attendableId };\n if (hasAttention) {\n attributes[ATTENTION_SOURCE_ATTRIBUTE] = 'true';\n }\n\n return attributes;\n }, [attendableId, hasAttention]);\n};\n\nconst RootAttentionProvider = ({\n children,\n attention: propsAttention,\n onChange,\n}: PropsWithChildren<\n Partial<{\n attention: AttentionManager;\n onChange: (nextAttended: string[]) => void;\n }>\n>) => {\n const registry = useContext(RegistryContext);\n const attention = useDefaultValue(propsAttention, () => new AttentionManager(registry));\n\n const handleFocus = (event: FocusEvent) => {\n // NOTE(thure): Use the following to debug focus movement across the app:\n log('focus', { related: event.relatedTarget, target: event.target });\n\n const selector = [\n '[data-attendable-id]',\n ...Array.from(document.querySelectorAll('[aria-controls]')).map(\n (el) => `[id=\"${el.getAttribute('aria-controls')}\"]`,\n ),\n ].join(',');\n const prev = attention.getCurrent();\n const next = getAttendables(selector, event.target);\n // TODO(wittjosiah): Not allowing empty state means that the attended item is not strictly guaranteed to be in the DOM.\n // Currently this depends on the deck in order to ensure that when the attended item is removed something else is attended.\n // Only update state if the result is different and not empty.\n if (next.length > 0 && (prev.length !== next.length || !!prev.find((id, index) => next[index] !== id))) {\n attention.update(next);\n onChange?.(next);\n }\n };\n\n return (\n <AttentionContextProvider attention={attention}>\n <div role='none' className='contents' onFocusCapture={handleFocus}>\n {children}\n </div>\n </AttentionContextProvider>\n );\n};\n\nexport type AttendableContainerProps = ThemedClassName<\n ComponentPropsWithRef<'div'> & { id: string; asChild?: boolean }\n>;\n\n/**\n * Note that DeckPlugin and StackPlugin both handle attention on their own,\n * and when rendering content in those cases it is not necessary to also render an `AttendableContainer`.\n * This component is primarily for Storybook stories and other testing scenarios,\n * or the rare cases where an attendable entity is rendered outside of either of those plugins.\n */\nconst AttendableContainer = forwardRef<HTMLDivElement, AttendableContainerProps>(\n ({ id, classNames, children, asChild, ...props }, forwardedRef) => {\n const attentionAttrs = useAttentionAttributes(id);\n const Comp = asChild ? Slot : Primitive.div;\n return (\n <Comp\n role='none'\n {...props}\n {...attentionAttrs}\n className={mx('dx-attention-surface', props.tabIndex === 0 && 'dx-focus-ring-inset-over-all', classNames)}\n ref={forwardedRef}\n >\n {children}\n </Comp>\n );\n },\n);\n\nexport {\n RootAttentionProvider,\n AttendableContainer,\n useAttentionContext,\n useAttention,\n useAttended,\n useAttentionAttributes,\n ATTENTION_NAME,\n ATTENDABLE_ATTRIBUTE,\n ATTENTION_SOURCE_ATTRIBUTE,\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, type Registry } from '@effect-atom/atom-react';\nimport * as Match from 'effect/Match';\nimport * as Schema from 'effect/Schema';\n\nimport { invariant } from '@dxos/invariant';\n\n// TODO(burdon): Reconcile with @dxos/graph.\n\nexport type SelectionMode = 'single' | 'multi' | 'range' | 'multi-range';\n\nexport const SelectionSchema = Schema.Union(\n Schema.Struct({ mode: Schema.Literal('single'), id: Schema.optional(Schema.String) }).pipe(Schema.mutable),\n Schema.Struct({ mode: Schema.Literal('multi'), ids: Schema.Array(Schema.String).pipe(Schema.mutable) }).pipe(\n Schema.mutable,\n ),\n Schema.Struct({\n mode: Schema.Literal('range'),\n from: Schema.optional(Schema.String),\n to: Schema.optional(Schema.String),\n }).pipe(Schema.mutable),\n Schema.Struct({\n mode: Schema.Literal('multi-range'),\n ranges: Schema.Array(Schema.Struct({ from: Schema.String, to: Schema.String })).pipe(Schema.mutable),\n }).pipe(Schema.mutable),\n).pipe(Schema.mutable);\n\nexport type Selection = Schema.Schema.Type<typeof SelectionSchema>;\n\nexport const defaultSelection = Match.type<SelectionMode>().pipe(\n Match.withReturnType<Selection>(),\n Match.when('single', () => ({ mode: 'single' })),\n Match.when('multi', () => ({ mode: 'multi', ids: [] })),\n Match.when('range', () => ({ mode: 'range' })),\n Match.when('multi-range', () => ({ mode: 'multi-range', ranges: [] })),\n Match.exhaustive,\n);\n\nexport type SelectionResult<T extends SelectionMode> = T extends 'single'\n ? string | undefined\n : T extends 'multi'\n ? string[]\n : T extends 'range'\n ? { from: string; to: string } | undefined\n : T extends 'multi-range'\n ? { from: string; to: string }[]\n : never;\n\n// TODO(burdon): Refactor.\nexport const getSelectionSet = (selectionManager: SelectionManager, contextId?: string) => {\n const ids = new Set<string>(contextId ? [contextId] : []);\n for (const context of selectionManager.getSelectionContexts()) {\n const selection = selectionManager.getSelection(context);\n if (selection?.mode === 'multi') {\n for (const id of selection.ids) {\n ids.add(id);\n }\n }\n }\n\n return ids;\n};\n\n/**\n * Manages selection state for different contexts.\n * Each context maintains its own selection mode and state.\n */\nexport class SelectionManager {\n private readonly _state: Atom.Writable<{ selections: Record<string, Selection> }>;\n\n constructor(\n private readonly _registry: Registry.Registry,\n initial: Record<string, Selection> = {},\n ) {\n this._state = Atom.make<{ selections: Record<string, Selection> }>({\n selections: { ...initial },\n });\n }\n\n /**\n * Get the state atom for reactive access in the graph system.\n */\n get state(): Atom.Atom<{ selections: Record<string, Selection> }> {\n return this._state;\n }\n\n /**\n * Gets the current state.\n */\n getState(): { selections: Record<string, Selection> } {\n return this._registry.get(this._state);\n }\n\n /**\n * Subscribe to changes in the selection state.\n */\n subscribe(cb: (state: { selections: Record<string, Selection> }) => void): () => void {\n this._registry.get(this._state);\n return this._registry.subscribe(this._state, () => {\n cb(this._registry.get(this._state));\n });\n }\n\n getSelectionContexts(): string[] {\n return Object.keys(this._registry.get(this._state).selections);\n }\n\n getSelection(contextId: string): Selection | undefined;\n getSelection<T extends SelectionMode>(contextId: string, mode: T): Selection;\n getSelection<T extends SelectionMode | undefined>(\n contextId: string,\n mode: T = undefined as T,\n ): Selection | undefined {\n const state = this._registry.get(this._state);\n const selection = state.selections[contextId];\n if (!mode || selection) {\n return selection;\n }\n\n // Create new selection for the context.\n const newSelection = defaultSelection(mode);\n this._registry.update(this._state, (state) => ({\n selections: { ...state.selections, [contextId]: newSelection },\n }));\n return newSelection;\n }\n\n // TODO(burdon): Disambiguate with getSelection?\n getSelected<T extends SelectionMode>(contextId: string, mode: T = 'multi' as T): SelectionResult<T> {\n const selection = this.getSelection(contextId, mode);\n invariant(selection?.mode === mode, 'Selection mode mismatch');\n // Cast required because TypeScript can't infer the relationship between T and the matched result.\n return Match.type<Selection>().pipe(\n Match.when({ mode: 'single' }, (s) => s.id),\n Match.when({ mode: 'multi' }, (s) => s.ids),\n Match.when({ mode: 'range' }, (s) => (s.from && s.to ? { from: s.from, to: s.to } : undefined)),\n Match.when({ mode: 'multi-range' }, (s) => s.ranges),\n Match.exhaustive,\n )(selection) as SelectionResult<T>;\n }\n\n updateSingle(contextId: string, id: string): void {\n const selection = this.getSelection(contextId, 'single');\n invariant(selection?.mode === 'single', 'Selection mode is not single');\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: { ...selection, id },\n },\n }));\n }\n\n updateMulti(contextId: string, ids: string[]) {\n const selection = this.getSelection(contextId, 'multi');\n invariant(selection?.mode === 'multi', 'Selection mode is not multi');\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: { ...selection, ids: [...ids] },\n },\n }));\n }\n\n updateRange(contextId: string, from: string, to: string) {\n const selection = this.getSelection(contextId, 'range');\n invariant(selection?.mode === 'range', 'Selection mode is not range');\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: { ...selection, from, to },\n },\n }));\n }\n\n updateMultiRange(contextId: string, ranges: { from: string; to: string }[]) {\n const selection = this.getSelection(contextId, 'multi-range');\n invariant(selection?.mode === 'multi-range', 'Selection mode is not multi-range');\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: { ...selection, ranges: [...ranges] },\n },\n }));\n }\n\n clearSelection(contextId: string): void {\n const selection = this.getSelection(contextId);\n if (!selection) {\n return;\n }\n\n const clearedSelection = Match.type<Selection>().pipe(\n Match.when({ mode: 'single' }, (s) => ({ ...s, id: undefined })),\n Match.when({ mode: 'multi' }, (s) => ({ ...s, ids: [] })),\n Match.when({ mode: 'range' }, (s) => ({ ...s, from: undefined, to: undefined })),\n Match.when({ mode: 'multi-range' }, (s) => ({ ...s, ranges: [] })),\n Match.exhaustive,\n )(selection);\n\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: clearedSelection,\n },\n }));\n }\n\n toggleSelection(contextId: string, id: string): void {\n const selection = this.getSelection(contextId, 'multi');\n invariant(selection?.mode === 'multi', 'Selection mode is not multi');\n\n const newIds = selection.ids.includes(id)\n ? selection.ids.filter((existingId) => existingId !== id)\n : [...selection.ids, id];\n\n this._registry.update(this._state, (state) => ({\n selections: {\n ...state.selections,\n [contextId]: { ...selection, ids: newIds },\n },\n }));\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { RegistryContext } from '@effect-atom/atom-react';\nimport { createContext } from '@radix-ui/react-context';\nimport * as Match from 'effect/Match';\nimport React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useState } from 'react';\n\nimport { useDefaultValue } from '@dxos/react-hooks';\n\nimport {\n type Selection,\n SelectionManager,\n type SelectionMode,\n type SelectionResult,\n defaultSelection,\n} from '../selection';\n\nconst SELECTION_NAME = 'Selection';\n\ntype SelectionContextValue = {\n selection: SelectionManager;\n};\n\nconst [SelectionContextProvider, useSelectionContext] = createContext<SelectionContextValue>(SELECTION_NAME, {\n selection: undefined as unknown as SelectionManager,\n});\n\n/**\n * Manages selection state across the app for multiple contexts.\n */\n// TODO(burdon): When is the selection removed?\nexport const SelectionProvider = ({\n children,\n selection: propsSelection,\n}: PropsWithChildren<{ selection?: SelectionManager }>) => {\n const registry = useContext(RegistryContext);\n const selection = useDefaultValue(propsSelection, () => new SelectionManager(registry));\n return <SelectionContextProvider selection={selection}>{children}</SelectionContextProvider>;\n};\n\n/**\n * Get the selection contexts.\n */\nexport const useSelectionManager = () => {\n const { selection } = useSelectionContext(SELECTION_NAME);\n return selection;\n};\n\nconst getDefaultResult = <T extends SelectionMode>(mode: T): SelectionResult<T> => {\n return Match.type<Selection>().pipe(\n Match.when({ mode: 'single' }, (selection) => selection.id),\n Match.when({ mode: 'multi' }, (selection) => selection.ids),\n Match.when({ mode: 'range' }, (selection) =>\n selection.from && selection.to ? { from: selection.from, to: selection.to } : undefined,\n ),\n Match.when({ mode: 'multi-range' }, (selection) => selection.ranges),\n Match.exhaustive,\n )(defaultSelection(mode)) as SelectionResult<T>;\n};\n\n/**\n * Get the selected objects for a given context.\n */\nexport const useSelected = <T extends SelectionMode>(\n contextId?: string,\n mode: T = 'multi' as T,\n): SelectionResult<T> => {\n const { selection } = useSelectionContext(SELECTION_NAME);\n const [state, setState] = useState<SelectionResult<T>>(() =>\n contextId && selection ? selection.getSelected(contextId, mode) : getDefaultResult(mode),\n );\n\n useEffect(() => {\n if (!contextId || !selection) {\n setState(getDefaultResult(mode));\n return;\n }\n\n // Set initial state.\n setState(selection.getSelected(contextId, mode));\n\n // Subscribe to changes.\n return selection.subscribe(() => {\n setState(selection.getSelected(contextId, mode));\n });\n }, [selection, contextId, mode]);\n\n return state;\n};\n\nexport type UseSelectionActions = {\n singleSelect: (id: string) => void;\n multiSelect: (ids: string[]) => void;\n rangeSelect: (from: string, to: string) => void;\n toggle: (id: string) => void;\n clear: () => void;\n};\n\n/**\n * Provides functions to manage the selection state for multiple contexts.\n */\n// TODO(burdon): Mode not used.\nexport const useSelectionActions = (contextIds: string[], mode: SelectionMode = 'multi'): UseSelectionActions => {\n const stableContextIds = useMemo(() => contextIds, [JSON.stringify(contextIds)]); // TODO(burdon): Avoid stringify.\n const { selection } = useSelectionContext(SELECTION_NAME);\n\n const singleSelect = useCallback(\n (id: string) => {\n if (!selection) {\n return;\n }\n for (const contextId of stableContextIds) {\n selection.updateSingle(contextId, id);\n }\n },\n [selection, stableContextIds],\n );\n\n const multiSelect = useCallback(\n (ids: string[]) => {\n if (!selection) {\n return;\n }\n for (const contextId of stableContextIds) {\n selection.updateMulti(contextId, ids);\n }\n },\n [selection, stableContextIds],\n );\n\n const rangeSelect = useCallback(\n (from: string, to: string) => {\n if (!selection) {\n return;\n }\n for (const contextId of stableContextIds) {\n selection.updateRange(contextId, from, to);\n }\n },\n [selection, stableContextIds],\n );\n\n const toggle = useCallback(\n (id: string) => {\n if (!selection) {\n return;\n }\n for (const contextId of stableContextIds) {\n selection.toggleSelection(contextId, id);\n }\n },\n [selection, stableContextIds],\n );\n\n const clear = useCallback(() => {\n if (!selection) {\n return;\n }\n for (const contextId of stableContextIds) {\n selection.clearSelection(contextId);\n }\n }, [selection, stableContextIds]);\n\n return { singleSelect, multiSelect, rangeSelect, toggle, clear };\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["Atom", "AttentionManager", "_map", "Map", "_currentAtom", "_registry", "initial", "make", "pipe", "keepAlive", "length", "update", "current", "getCurrent", "get", "subscribeCurrent", "cb", "subscribe", "keys", "Array", "from", "id", "atom", "_getAtom", "existing", "newAtom", "hasAttention", "isAncestor", "isRelated", "set", "nextIds", "primaryId", "currentIds", "prevPrimaryId", "prevPrefixes", "expandAttendableId", "prefix", "_set", "prevSegmentId", "getSegmentId", "key", "prefixes", "prefixSet", "Set", "linkedParent", "isLinkedSegment", "getParentId", "undefined", "segmentId", "has", "attention", "getAttendables", "selector", "cursor", "acc", "closestAttendable", "closest", "attendableId", "getAttribute", "trigger", "document", "querySelector", "push", "parentElement", "LINKED_PREFIX", "qualifiedId", "segments", "split", "map", "_", "index", "slice", "join", "lastSegment", "pop", "startsWith", "linkedSegment", "variant", "getLinkedVariant", "lastSlash", "lastIndexOf", "RegistryContext", "createContext", "Primitive", "Slot", "React", "forwardRef", "useContext", "useEffect", "useMemo", "useState", "log", "useDefaultValue", "mx", "ATTENTION_NAME", "ATTENTION_SOURCE_ATTRIBUTE", "AttentionContextProvider", "attention", "undefined", "UNKNOWN_ATTENDABLE", "isAncestor", "isRelated", "setState", "useEffect", "attendableId", "subscribe", "newState", "useAttended", "setCurrent", "newCurrent", "attributes", "ATTENDABLE_ATTRIBUTE", "hasAttention", "useDefaultValue", "propsAttention", "AttentionManager", "registry", "handleFocus", "event", "log", "target", "selector", "join", "prev", "getCurrent", "next", "onChange", "div", "role", "onFocusCapture", "children", "Comp", "attentionAttrs", "className", "ref", "RootAttentionProvider", "Atom", "Match", "Schema", "invariant", "__dxlog_file", "SelectionSchema", "id", "pipe", "mutable", "Struct", "mode", "String", "optional", "to", "Array", "defaultSelection", "when", "ranges", "getSelectionSet", "contextId", "selection", "_state", "make", "selections", "initial", "_registry", "cb", "get", "getSelectionContexts", "getSelection", "undefined", "state", "newSelection", "getSelected", "s", "ids", "from", "exhaustive", "updateSingle", "update", "updateMulti", "updateRange", "updateMultiRange", "clearSelection", "toggleSelection", "newIds", "includes", "RegistryContext", "createContext", "Match", "React", "useCallback", "useContext", "useEffect", "useMemo", "useState", "useDefaultValue", "SELECTION_NAME", "SelectionContextProvider", "useSelectionContext", "createContext", "selection", "undefined", "SelectionProvider", "children", "propsSelection", "registry", "useContext", "RegistryContext", "useDefaultValue", "SelectionManager", "React", "useSelectionManager", "getDefaultResult", "mode", "type", "pipe", "when", "id", "ids", "from", "to", "ranges", "exhaustive", "defaultSelection", "useSelected", "contextId", "state", "setState", "useState", "getSelected", "useEffect", "subscribe", "useSelectionActions", "contextIds", "stableContextIds", "useMemo", "JSON", "stringify", "singleSelect", "useCallback", "updateSingle", "multiSelect", "updateMulti", "rangeSelect", "updateRange", "toggle", "toggleSelection", "clear", "clearSelection"]
7
+ }
@@ -4,32 +4,33 @@ import {
4
4
  ATTENTION_SOURCE_ATTRIBUTE,
5
5
  AttendableContainer,
6
6
  AttentionManager,
7
- AttentionProvider,
8
7
  RootAttentionProvider,
9
8
  SelectionManager,
10
9
  SelectionProvider,
11
10
  SelectionSchema,
12
11
  defaultSelection,
12
+ expandAttendableId,
13
13
  getAttendables,
14
+ getLinkedVariant,
15
+ getParentId,
16
+ getSegmentId,
14
17
  getSelectionSet,
18
+ isLinkedSegment,
19
+ linkedSegment,
15
20
  useAttended,
16
21
  useAttention,
17
22
  useAttentionAttributes,
18
23
  useAttentionContext,
19
- useAttentionPath,
20
24
  useSelected,
21
25
  useSelectionActions,
22
26
  useSelectionManager
23
- } from "./chunk-TAZUDNJI.mjs";
24
- import {
25
- ATTENDABLE_PATH_SEPARATOR
26
- } from "./chunk-PAZBZOO2.mjs";
27
+ } from "./chunk-DAIZNFKL.mjs";
27
28
 
28
29
  // src/components/AttentionGlyph.tsx
29
30
  import React, { forwardRef, useMemo } from "react";
30
31
  import { Icon } from "@dxos/react-ui";
31
32
  import { mx } from "@dxos/ui-theme";
32
- var attentionGlyphStyles = mx("inline-block rounded-xs w-3 h-3 bg-transparent text-accent-text transition-colors", "[[data-contains-attended=true]_&]:bg-attention-surface-surface", "[[data-attention=true]_&]:bg-accent-surface", "[[data-attention=true]_&]:text-accent-surface-text", "[[aria-current][data-attention=true]_&]:bg-accent-surface", "[[aria-current][data-attention=true]_&]:text-accent-surface-text", '[[aria-selected="true"][data-attention=true]_&]:bg-accent-surface', '[[aria-selected="true"][data-attention=true]_&]:text-accent-surface-text');
33
+ var attentionGlyphStyles = mx("inline-block rounded-xs w-3 h-3 bg-transparent text-accent-text transition-colors", "[[data-contains-attended=true]_&]:bg-attention-contains", "[[data-attention=true]_&]:bg-accent-surface", "[[data-attention=true]_&]:text-accent-surface-text", "[[aria-current][data-attention=true]_&]:bg-accent-surface", "[[aria-current][data-attention=true]_&]:text-accent-surface-text", '[[aria-selected="true"][data-attention=true]_&]:bg-accent-surface', '[[aria-selected="true"][data-attention=true]_&]:text-accent-surface-text');
33
34
  var presenceIconStyles = mx("w-3 h-3");
34
35
  var PresenceOne = () => {
35
36
  return /* @__PURE__ */ React.createElement("svg", {
@@ -95,26 +96,29 @@ var AttentionGlyph = /* @__PURE__ */ forwardRef(({ presence, attended, syncing,
95
96
  });
96
97
  export {
97
98
  ATTENDABLE_ATTRIBUTE,
98
- ATTENDABLE_PATH_SEPARATOR,
99
99
  ATTENTION_NAME,
100
100
  ATTENTION_SOURCE_ATTRIBUTE,
101
101
  AttendableContainer,
102
102
  AttentionGlyph,
103
103
  AttentionManager,
104
- AttentionProvider,
105
104
  RootAttentionProvider,
106
105
  SelectionManager,
107
106
  SelectionProvider,
108
107
  SelectionSchema,
109
108
  Syncing,
110
109
  defaultSelection,
110
+ expandAttendableId,
111
111
  getAttendables,
112
+ getLinkedVariant,
113
+ getParentId,
114
+ getSegmentId,
112
115
  getSelectionSet,
116
+ isLinkedSegment,
117
+ linkedSegment,
113
118
  useAttended,
114
119
  useAttention,
115
120
  useAttentionAttributes,
116
121
  useAttentionContext,
117
- useAttentionPath,
118
122
  useSelected,
119
123
  useSelectionActions,
120
124
  useSelectionManager