@dxos/react-ui-attention 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6
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/dist/lib/browser/{chunk-HJRZWOEX.mjs → chunk-4SEURHOL.mjs} +122 -106
- package/dist/lib/browser/chunk-4SEURHOL.mjs.map +7 -0
- package/dist/lib/browser/chunk-GMKHOVJ5.mjs +1 -0
- package/dist/lib/browser/chunk-GMKHOVJ5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +17 -12
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +16 -7
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/types.mjs +1 -6
- package/dist/lib/node-esm/{chunk-7TQWDE4M.mjs → chunk-6PQ4P7AL.mjs} +122 -105
- package/dist/lib/node-esm/chunk-6PQ4P7AL.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-UHVMYYIB.mjs +2 -0
- package/dist/lib/node-esm/chunk-UHVMYYIB.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +17 -12
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +16 -7
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/types.mjs +1 -6
- package/dist/types/src/attention.d.ts +41 -10
- package/dist/types/src/attention.d.ts.map +1 -1
- package/dist/types/src/components/AttentionGlyph.d.ts.map +1 -1
- package/dist/types/src/components/AttentionProvider.d.ts +9 -11
- package/dist/types/src/components/AttentionProvider.d.ts.map +1 -1
- package/dist/types/src/components/SelectionProvider.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withAttention.d.ts +5 -1
- package/dist/types/src/testing/decorators/withAttention.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +0 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/attention.test.ts +179 -23
- package/src/attention.ts +132 -54
- package/src/components/AttentionGlyph.stories.tsx +3 -3
- package/src/components/AttentionGlyph.tsx +12 -5
- package/src/components/AttentionProvider.stories.tsx +2 -2
- package/src/components/AttentionProvider.tsx +21 -48
- package/src/components/SelectionProvider.tsx +6 -4
- package/src/testing/decorators/withAttention.ts +18 -7
- package/src/types.ts +0 -3
- package/dist/lib/browser/chunk-HJRZWOEX.mjs.map +0 -7
- package/dist/lib/browser/chunk-PAZBZOO2.mjs +0 -7
- package/dist/lib/browser/chunk-PAZBZOO2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-7TQWDE4M.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-PMGNPL4M.mjs +0 -9
- 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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
42
|
+
* Get the attention state for a given qualified ID.
|
|
51
43
|
*/
|
|
52
|
-
get(
|
|
53
|
-
const atom = this._getAtom(
|
|
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
|
|
49
|
+
* Subscribe to changes in the attention state for a given qualified ID.
|
|
58
50
|
*/
|
|
59
|
-
subscribe(
|
|
60
|
-
const atom = this._getAtom(
|
|
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(
|
|
67
|
-
const existing = this._map.get(
|
|
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(
|
|
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(
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
]
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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(
|
|
111
|
-
const atom = this._getAtom(
|
|
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(
|
|
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";
|
|
@@ -149,10 +192,9 @@ import { mx } from "@dxos/ui-theme";
|
|
|
149
192
|
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-attention/src/components/AttentionProvider.tsx";
|
|
150
193
|
var ATTENTION_NAME = "Attention";
|
|
151
194
|
var ATTENDABLE_ATTRIBUTE = "data-attendable-id";
|
|
152
|
-
var ATTENTION_SOURCE_ATTRIBUTE = "data-
|
|
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
|
|
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 (!
|
|
208
|
+
if (!attendableId || !attention) {
|
|
179
209
|
setState(UNKNOWN_ATTENDABLE);
|
|
180
210
|
return;
|
|
181
211
|
}
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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));
|
|
@@ -233,7 +260,7 @@ var RootAttentionProvider = ({ children, attention: propsAttention, onChange })
|
|
|
233
260
|
target: event.target
|
|
234
261
|
}, {
|
|
235
262
|
F: __dxlog_file,
|
|
236
|
-
L:
|
|
263
|
+
L: 115,
|
|
237
264
|
S: void 0,
|
|
238
265
|
C: (f, a) => f(...a)
|
|
239
266
|
});
|
|
@@ -249,36 +276,21 @@ var RootAttentionProvider = ({ children, attention: propsAttention, onChange })
|
|
|
249
276
|
}
|
|
250
277
|
};
|
|
251
278
|
return /* @__PURE__ */ React.createElement(AttentionContextProvider, {
|
|
252
|
-
attention
|
|
253
|
-
path: []
|
|
279
|
+
attention
|
|
254
280
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
255
281
|
role: "none",
|
|
256
282
|
className: "contents",
|
|
257
283
|
onFocusCapture: handleFocus
|
|
258
284
|
}, children));
|
|
259
285
|
};
|
|
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
286
|
var AttendableContainer = /* @__PURE__ */ forwardRef(({ id, classNames, children, asChild, ...props }, forwardedRef) => {
|
|
275
287
|
const attentionAttrs = useAttentionAttributes(id);
|
|
276
|
-
const
|
|
277
|
-
return /* @__PURE__ */ React.createElement(
|
|
288
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
289
|
+
return /* @__PURE__ */ React.createElement(Comp, {
|
|
278
290
|
role: "none",
|
|
279
|
-
...attentionAttrs,
|
|
280
291
|
...props,
|
|
281
|
-
|
|
292
|
+
...attentionAttrs,
|
|
293
|
+
className: mx("dx-attention-surface", props.tabIndex === 0 && "dx-focus-ring-inset-over-all", classNames),
|
|
282
294
|
ref: forwardedRef
|
|
283
295
|
}, children);
|
|
284
296
|
});
|
|
@@ -580,16 +592,16 @@ var useSelectionManager = () => {
|
|
|
580
592
|
var getDefaultResult = (mode) => {
|
|
581
593
|
return Match2.type().pipe(Match2.when({
|
|
582
594
|
mode: "single"
|
|
583
|
-
}, (
|
|
595
|
+
}, (selection) => selection.id), Match2.when({
|
|
584
596
|
mode: "multi"
|
|
585
|
-
}, (
|
|
597
|
+
}, (selection) => selection.ids), Match2.when({
|
|
586
598
|
mode: "range"
|
|
587
|
-
}, (
|
|
588
|
-
from:
|
|
589
|
-
to:
|
|
599
|
+
}, (selection) => selection.from && selection.to ? {
|
|
600
|
+
from: selection.from,
|
|
601
|
+
to: selection.to
|
|
590
602
|
} : void 0), Match2.when({
|
|
591
603
|
mode: "multi-range"
|
|
592
|
-
}, (
|
|
604
|
+
}, (selection) => selection.ranges), Match2.exhaustive)(defaultSelection(mode));
|
|
593
605
|
};
|
|
594
606
|
var useSelected = (contextId, mode = "multi") => {
|
|
595
607
|
const { selection } = useSelectionContext(SELECTION_NAME);
|
|
@@ -682,6 +694,12 @@ var useSelectionActions = (contextIds, mode = "multi") => {
|
|
|
682
694
|
export {
|
|
683
695
|
AttentionManager,
|
|
684
696
|
getAttendables,
|
|
697
|
+
expandAttendableId,
|
|
698
|
+
isLinkedSegment,
|
|
699
|
+
linkedSegment,
|
|
700
|
+
getLinkedVariant,
|
|
701
|
+
getParentId,
|
|
702
|
+
getSegmentId,
|
|
685
703
|
ATTENTION_NAME,
|
|
686
704
|
ATTENDABLE_ATTRIBUTE,
|
|
687
705
|
ATTENTION_SOURCE_ATTRIBUTE,
|
|
@@ -689,9 +707,7 @@ export {
|
|
|
689
707
|
useAttention,
|
|
690
708
|
useAttended,
|
|
691
709
|
useAttentionAttributes,
|
|
692
|
-
useAttentionPath,
|
|
693
710
|
RootAttentionProvider,
|
|
694
|
-
AttentionProvider,
|
|
695
711
|
AttendableContainer,
|
|
696
712
|
SelectionSchema,
|
|
697
713
|
defaultSelection,
|
|
@@ -702,4 +718,4 @@ export {
|
|
|
702
718
|
useSelected,
|
|
703
719
|
useSelectionActions
|
|
704
720
|
};
|
|
705
|
-
//# sourceMappingURL=chunk-
|
|
721
|
+
//# sourceMappingURL=chunk-4SEURHOL.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", "Atom", "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", "ATTENDABLE_ATTRIBUTE", "ATTENTION_SOURCE_ATTRIBUTE", "AttentionContextProvider", "useAttentionContext", "createContext", "attention", "undefined", "UNKNOWN_ATTENDABLE", "hasAttention", "isAncestor", "isRelated", "useAttention", "attendableId", "state", "setState", "useState", "useEffect", "currentState", "get", "subscribe", "newState", "useAttended", "current", "setCurrent", "getCurrent", "subscribeCurrent", "newCurrent", "useAttentionAttributes", "useMemo", "attributes", "RootAttentionProvider", "children", "propsAttention", "onChange", "registry", "useContext", "RegistryContext", "useDefaultValue", "AttentionManager", "handleFocus", "event", "log", "related", "relatedTarget", "target", "selector", "Array", "from", "document", "querySelectorAll", "map", "el", "getAttribute", "join", "prev", "next", "getAttendables", "length", "find", "id", "index", "update", "div", "role", "className", "onFocusCapture", "AttendableContainer", "forwardRef", "classNames", "asChild", "props", "forwardedRef", "attentionAttrs", "Comp", "Slot", "Primitive", "mx", "tabIndex", "ref", "Atom", "Match", "Schema", "invariant", "SelectionSchema", "Union", "Struct", "mode", "Literal", "id", "optional", "String", "pipe", "mutable", "ids", "Array", "from", "to", "ranges", "defaultSelection", "type", "withReturnType", "when", "exhaustive", "getSelectionSet", "selectionManager", "contextId", "Set", "context", "getSelectionContexts", "selection", "getSelection", "add", "SelectionManager", "_state", "_registry", "initial", "make", "selections", "state", "getState", "get", "subscribe", "cb", "Object", "keys", "undefined", "newSelection", "update", "getSelected", "s", "updateSingle", "updateMulti", "updateRange", "updateMultiRange", "clearSelection", "clearedSelection", "toggleSelection", "newIds", "includes", "filter", "existingId", "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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-GMKHOVJ5.mjs.map
|
|
@@ -1,36 +1,38 @@
|
|
|
1
|
+
import "./chunk-GMKHOVJ5.mjs";
|
|
1
2
|
import {
|
|
2
3
|
ATTENDABLE_ATTRIBUTE,
|
|
3
4
|
ATTENTION_NAME,
|
|
4
5
|
ATTENTION_SOURCE_ATTRIBUTE,
|
|
5
6
|
AttendableContainer,
|
|
6
7
|
AttentionManager,
|
|
7
|
-
AttentionProvider,
|
|
8
8
|
RootAttentionProvider,
|
|
9
9
|
SelectionManager,
|
|
10
10
|
SelectionProvider,
|
|
11
11
|
SelectionSchema,
|
|
12
12
|
defaultSelection,
|
|
13
|
+
expandAttendableId,
|
|
13
14
|
getAttendables,
|
|
15
|
+
getLinkedVariant,
|
|
16
|
+
getParentId,
|
|
17
|
+
getSegmentId,
|
|
14
18
|
getSelectionSet,
|
|
19
|
+
isLinkedSegment,
|
|
20
|
+
linkedSegment,
|
|
15
21
|
useAttended,
|
|
16
22
|
useAttention,
|
|
17
23
|
useAttentionAttributes,
|
|
18
24
|
useAttentionContext,
|
|
19
|
-
useAttentionPath,
|
|
20
25
|
useSelected,
|
|
21
26
|
useSelectionActions,
|
|
22
27
|
useSelectionManager
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
ATTENDABLE_PATH_SEPARATOR
|
|
26
|
-
} from "./chunk-PAZBZOO2.mjs";
|
|
28
|
+
} from "./chunk-4SEURHOL.mjs";
|
|
27
29
|
|
|
28
30
|
// src/components/AttentionGlyph.tsx
|
|
29
31
|
import React, { forwardRef, useMemo } from "react";
|
|
30
32
|
import { Icon } from "@dxos/react-ui";
|
|
31
33
|
import { mx } from "@dxos/ui-theme";
|
|
32
|
-
var attentionGlyphStyles = "inline-block rounded-
|
|
33
|
-
var presenceIconStyles = "
|
|
34
|
+
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');
|
|
35
|
+
var presenceIconStyles = mx("w-3 h-3");
|
|
34
36
|
var PresenceOne = () => {
|
|
35
37
|
return /* @__PURE__ */ React.createElement("svg", {
|
|
36
38
|
width: "12",
|
|
@@ -83,7 +85,7 @@ var AttentionGlyph = /* @__PURE__ */ forwardRef(({ presence, attended, syncing,
|
|
|
83
85
|
const icon = syncing ? /* @__PURE__ */ React.createElement(Syncing, null) : presence === "many" ? /* @__PURE__ */ React.createElement(PresenceMany, null) : presence === "one" ? /* @__PURE__ */ React.createElement(PresenceOne, null) : null;
|
|
84
86
|
return /* @__PURE__ */ React.createElement("div", {
|
|
85
87
|
role: "none",
|
|
86
|
-
className: "flex",
|
|
88
|
+
className: "flex group",
|
|
87
89
|
"data-attention": attended,
|
|
88
90
|
"data-contains-attended": containsAttended
|
|
89
91
|
}, /* @__PURE__ */ React.createElement("span", {
|
|
@@ -95,26 +97,29 @@ var AttentionGlyph = /* @__PURE__ */ forwardRef(({ presence, attended, syncing,
|
|
|
95
97
|
});
|
|
96
98
|
export {
|
|
97
99
|
ATTENDABLE_ATTRIBUTE,
|
|
98
|
-
ATTENDABLE_PATH_SEPARATOR,
|
|
99
100
|
ATTENTION_NAME,
|
|
100
101
|
ATTENTION_SOURCE_ATTRIBUTE,
|
|
101
102
|
AttendableContainer,
|
|
102
103
|
AttentionGlyph,
|
|
103
104
|
AttentionManager,
|
|
104
|
-
AttentionProvider,
|
|
105
105
|
RootAttentionProvider,
|
|
106
106
|
SelectionManager,
|
|
107
107
|
SelectionProvider,
|
|
108
108
|
SelectionSchema,
|
|
109
109
|
Syncing,
|
|
110
110
|
defaultSelection,
|
|
111
|
+
expandAttendableId,
|
|
111
112
|
getAttendables,
|
|
113
|
+
getLinkedVariant,
|
|
114
|
+
getParentId,
|
|
115
|
+
getSegmentId,
|
|
112
116
|
getSelectionSet,
|
|
117
|
+
isLinkedSegment,
|
|
118
|
+
linkedSegment,
|
|
113
119
|
useAttended,
|
|
114
120
|
useAttention,
|
|
115
121
|
useAttentionAttributes,
|
|
116
122
|
useAttentionContext,
|
|
117
|
-
useAttentionPath,
|
|
118
123
|
useSelected,
|
|
119
124
|
useSelectionActions,
|
|
120
125
|
useSelectionManager
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/AttentionGlyph.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Primitive } from '@radix-ui/react-primitive';\nimport React, { type CSSProperties, type ComponentPropsWithRef, forwardRef, useMemo } from 'react';\n\nimport { Icon, type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\n\nconst attentionGlyphStyles
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["React", "forwardRef", "useMemo", "Icon", "mx", "attentionGlyphStyles", "presenceIconStyles", "PresenceOne", "svg", "width", "height", "viewBox", "className", "fill", "xmlns", "circle", "cx", "cy", "r", "PresenceMany", "path", "d", "Syncing", "animationProps", "useMemo", "animationDelay", "Date", "now", "div", "role", "Icon", "icon", "size", "style", "classNames", "AttentionGlyph", "forwardRef", "presence", "attended", "syncing", "containsAttended", "props", "forwardedRef", "data-attention", "data-contains-attended", "span", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Primitive } from '@radix-ui/react-primitive';\nimport React, { type CSSProperties, type ComponentPropsWithRef, forwardRef, useMemo } from 'react';\n\nimport { Icon, type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\n\nconst attentionGlyphStyles = mx(\n 'inline-block rounded-xs w-3 h-3 bg-transparent text-accent-text transition-colors',\n '[[data-contains-attended=true]_&]:bg-attention-contains',\n '[[data-attention=true]_&]:bg-accent-surface',\n '[[data-attention=true]_&]:text-accent-surface-text',\n '[[aria-current][data-attention=true]_&]:bg-accent-surface',\n '[[aria-current][data-attention=true]_&]:text-accent-surface-text',\n '[[aria-selected=\"true\"][data-attention=true]_&]:bg-accent-surface',\n '[[aria-selected=\"true\"][data-attention=true]_&]:text-accent-surface-text',\n);\n\nconst presenceIconStyles = mx('w-3 h-3');\n\nconst PresenceOne = () => {\n return (\n <svg\n width='12'\n height='12'\n viewBox='0 0 12 12'\n className={presenceIconStyles}\n fill='none'\n xmlns='http://www.w3.org/2000/svg'\n >\n <circle cx='6' cy='6' r='2.5' fill='currentColor' />\n </svg>\n );\n};\n\nconst PresenceMany = () => {\n return (\n <svg\n width='12'\n height='12'\n viewBox='0 0 12 12'\n className={presenceIconStyles}\n fill='none'\n xmlns='http://www.w3.org/2000/svg'\n >\n <path\n d='M6.75 8.27311C7.38815 7.72296 7.79212 6.90866 7.79212 6C7.79212 5.09134 7.38815 4.27704 6.75 3.72689C7.06722 3.58122 7.42019 3.5 7.79212 3.5C9.17283 3.5 10.2921 4.61929 10.2921 6C10.2921 7.38071 9.17283 8.5 7.79212 8.5C7.42019 8.5 7.06723 8.41878 6.75 8.27311Z'\n fill='currentColor'\n />\n <circle cx='4.25' cy='6' r='2.5' fill='currentColor' />\n </svg>\n );\n};\n\nexport const Syncing = () => {\n const animationProps = useMemo<CSSProperties>(\n () => ({\n // Synchronize animations.\n animationDelay: `-${Date.now() % 2_000}ms`,\n }),\n [],\n );\n\n return (\n <div role='status' className='flex items-center'>\n <Icon\n icon='ph--circle-notch--bold'\n size={3}\n style={animationProps}\n classNames='text-subdued animate-[spin_2s_linear_infinite]'\n />\n </div>\n );\n};\n\nexport type AttentionGlyphProps = {\n attended?: boolean;\n containsAttended?: boolean;\n syncing?: boolean;\n presence?: 'none' | 'one' | 'many';\n} & ThemedClassName<Omit<ComponentPropsWithRef<typeof Primitive.span>, 'children'>>;\n\nexport const AttentionGlyph = forwardRef<HTMLSpanElement, AttentionGlyphProps>(\n ({ presence, attended, syncing, containsAttended, classNames, ...props }, forwardedRef) => {\n const icon = syncing ? (\n <Syncing />\n ) : presence === 'many' ? (\n <PresenceMany />\n ) : presence === 'one' ? (\n <PresenceOne />\n ) : null;\n\n return (\n <div role='none' className='flex group' data-attention={attended} data-contains-attended={containsAttended}>\n <span role='none' {...props} className={mx(attentionGlyphStyles, classNames)} ref={forwardedRef}>\n {icon}\n </span>\n </div>\n );\n },\n);\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,OAAOA,SAAyDC,YAAYC,eAAe;AAE3F,SAASC,YAAkC;AAC3C,SAASC,UAAU;AAEnB,IAAMC,uBAAuBC,GAC3B,qFACA,2DACA,+CACA,sDACA,6DACA,oEACA,qEACA,0EAAA;AAGF,IAAMC,qBAAqBD,GAAG,SAAA;AAE9B,IAAME,cAAc,MAAA;AAClB,SACE,sBAAA,cAACC,OAAAA;IACCC,OAAM;IACNC,QAAO;IACPC,SAAQ;IACRC,WAAWN;IACXO,MAAK;IACLC,OAAM;KAEN,sBAAA,cAACC,UAAAA;IAAOC,IAAG;IAAIC,IAAG;IAAIC,GAAE;IAAML,MAAK;;AAGzC;AAEA,IAAMM,eAAe,MAAA;AACnB,SACE,sBAAA,cAACX,OAAAA;IACCC,OAAM;IACNC,QAAO;IACPC,SAAQ;IACRC,WAAWN;IACXO,MAAK;IACLC,OAAM;KAEN,sBAAA,cAACM,QAAAA;IACCC,GAAE;IACFR,MAAK;MAEP,sBAAA,cAACE,UAAAA;IAAOC,IAAG;IAAOC,IAAG;IAAIC,GAAE;IAAML,MAAK;;AAG5C;AAEO,IAAMS,UAAU,MAAA;AACrB,QAAMC,iBAAiBC,QACrB,OAAO;;IAELC,gBAAgB,IAAIC,KAAKC,IAAG,IAAK,GAAA;EACnC,IACA,CAAA,CAAE;AAGJ,SACE,sBAAA,cAACC,OAAAA;IAAIC,MAAK;IAASjB,WAAU;KAC3B,sBAAA,cAACkB,MAAAA;IACCC,MAAK;IACLC,MAAM;IACNC,OAAOV;IACPW,YAAW;;AAInB;AASO,IAAMC,iBAAiBC,2BAC5B,CAAC,EAAEC,UAAUC,UAAUC,SAASC,kBAAkBN,YAAY,GAAGO,MAAAA,GAASC,iBAAAA;AACxE,QAAMX,OAAOQ,UACX,sBAAA,cAACjB,SAAAA,IAAAA,IACCe,aAAa,SACf,sBAAA,cAAClB,cAAAA,IAAAA,IACCkB,aAAa,QACf,sBAAA,cAAC9B,aAAAA,IAAAA,IACC;AAEJ,SACE,sBAAA,cAACqB,OAAAA;IAAIC,MAAK;IAAOjB,WAAU;IAAa+B,kBAAgBL;IAAUM,0BAAwBJ;KACxF,sBAAA,cAACK,QAAAA;IAAKhB,MAAK;IAAQ,GAAGY;IAAO7B,WAAWP,GAAGD,sBAAsB8B,UAAAA;IAAaY,KAAKJ;KAChFX,IAAAA,CAAAA;AAIT,CAAA;",
|
|
6
|
+
"names": ["React", "forwardRef", "useMemo", "Icon", "mx", "attentionGlyphStyles", "mx", "presenceIconStyles", "PresenceOne", "svg", "width", "height", "viewBox", "className", "fill", "xmlns", "circle", "cx", "cy", "r", "PresenceMany", "path", "d", "Syncing", "animationProps", "useMemo", "animationDelay", "Date", "now", "div", "role", "Icon", "icon", "size", "style", "classNames", "AttentionGlyph", "forwardRef", "presence", "attended", "syncing", "containsAttended", "props", "forwardedRef", "data-attention", "data-contains-attended", "span", "ref"]
|
|
7
7
|
}
|