@dxos/react-ui-attention 0.10.0 → 0.11.0
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/chunk-ViewStateProvider.mjs +308 -0
- package/dist/lib/chunk-ViewStateProvider.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +351 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/index.mjs +149 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/testing.mjs +20 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/components/AttentionProvider/AttentionProvider.d.ts +2 -15
- package/dist/types/src/components/AttentionProvider/AttentionProvider.d.ts.map +1 -1
- package/dist/types/src/components/AttentionProvider/attention-context.d.ts +20 -0
- package/dist/types/src/components/AttentionProvider/attention-context.d.ts.map +1 -0
- package/dist/types/src/components/AttentionProvider/index.d.ts +1 -0
- package/dist/types/src/components/AttentionProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/ViewStateProvider/ViewStateProvider.d.ts +2 -26
- package/dist/types/src/components/ViewStateProvider/ViewStateProvider.d.ts.map +1 -1
- package/dist/types/src/components/ViewStateProvider/index.d.ts +1 -0
- package/dist/types/src/components/ViewStateProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/ViewStateProvider/view-state-hooks.d.ts +32 -0
- package/dist/types/src/components/ViewStateProvider/view-state-hooks.d.ts.map +1 -0
- package/dist/types/src/core/backends.d.ts +24 -0
- package/dist/types/src/core/backends.d.ts.map +1 -0
- package/dist/types/src/core/backends.test.d.ts.map +1 -0
- package/dist/types/src/core/index.d.ts +2 -0
- package/dist/types/src/core/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useArticleKeyboardNavigation.d.ts.map +1 -0
- package/dist/types/src/hooks/useArticleKeyboardNavigation.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/{attention.d.ts → types/Attention.d.ts} +13 -2
- package/dist/types/src/types/Attention.d.ts.map +1 -0
- package/dist/types/src/types/Attention.test.d.ts +2 -0
- package/dist/types/src/types/Attention.test.d.ts.map +1 -0
- package/dist/types/src/{selection.d.ts → types/Selection.d.ts} +12 -10
- package/dist/types/src/types/Selection.d.ts.map +1 -0
- package/dist/types/src/types/Selection.test.d.ts +2 -0
- package/dist/types/src/types/Selection.test.d.ts.map +1 -0
- package/dist/types/src/types/ViewState.d.ts +66 -0
- package/dist/types/src/types/ViewState.d.ts.map +1 -0
- package/dist/types/src/types/ViewState.test.d.ts +2 -0
- package/dist/types/src/types/ViewState.test.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +3 -3
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -20
- package/src/components/AttentionProvider/AttentionProvider.stories.tsx +1 -1
- package/src/components/AttentionProvider/AttentionProvider.tsx +4 -86
- package/src/components/AttentionProvider/attention-context.ts +81 -0
- package/src/components/AttentionProvider/index.ts +2 -0
- package/src/components/ViewStateProvider/ViewStateProvider.test.tsx +7 -5
- package/src/components/ViewStateProvider/ViewStateProvider.tsx +6 -110
- package/src/components/ViewStateProvider/index.ts +9 -0
- package/src/components/ViewStateProvider/view-state-hooks.ts +115 -0
- package/src/{view-state → core}/backends.test.ts +5 -5
- package/src/{view-state → core}/backends.ts +24 -17
- package/src/{view-state → core}/index.ts +0 -1
- package/src/hooks/index.ts +5 -0
- package/src/{useArticleKeyboardNavigation.ts → hooks/useArticleKeyboardNavigation.ts} +1 -1
- package/src/index.ts +3 -4
- package/src/testing/decorators/withAttention.ts +2 -2
- package/src/{attention.test.ts → types/Attention.test.ts} +2 -2
- package/src/{attention.ts → types/Attention.ts} +17 -2
- package/src/types/Selection.test.ts +100 -0
- package/src/{selection.ts → types/Selection.ts} +27 -17
- package/src/{view-state/view-state.test.ts → types/ViewState.test.ts} +6 -6
- package/src/types/ViewState.ts +101 -0
- package/src/types/index.ts +8 -7
- package/dist/lib/browser/chunk-4HYAJ4IO.mjs +0 -434
- package/dist/lib/browser/chunk-4HYAJ4IO.mjs.map +0 -7
- package/dist/lib/browser/chunk-I4FDY4AZ.mjs +0 -236
- package/dist/lib/browser/chunk-I4FDY4AZ.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -218
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs +0 -30
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/browser/types/index.mjs +0 -43
- package/dist/lib/browser/types/index.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-DLBZMHST.mjs +0 -237
- package/dist/lib/node-esm/chunk-DLBZMHST.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HWN7KJDX.mjs +0 -436
- package/dist/lib/node-esm/chunk-HWN7KJDX.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -219
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -31
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -44
- package/dist/lib/node-esm/types/index.mjs.map +0 -7
- package/dist/types/src/attention.d.ts.map +0 -1
- package/dist/types/src/attention.test.d.ts +0 -2
- package/dist/types/src/attention.test.d.ts.map +0 -1
- package/dist/types/src/selection.d.ts.map +0 -1
- package/dist/types/src/selection.test.d.ts +0 -2
- package/dist/types/src/selection.test.d.ts.map +0 -1
- package/dist/types/src/useArticleKeyboardNavigation.d.ts.map +0 -1
- package/dist/types/src/useArticleKeyboardNavigation.test.d.ts.map +0 -1
- package/dist/types/src/view-state/backends.d.ts +0 -24
- package/dist/types/src/view-state/backends.d.ts.map +0 -1
- package/dist/types/src/view-state/backends.test.d.ts.map +0 -1
- package/dist/types/src/view-state/index.d.ts +0 -3
- package/dist/types/src/view-state/index.d.ts.map +0 -1
- package/dist/types/src/view-state/view-state.d.ts +0 -54
- package/dist/types/src/view-state/view-state.d.ts.map +0 -1
- package/dist/types/src/view-state/view-state.test.d.ts +0 -2
- package/dist/types/src/view-state/view-state.test.d.ts.map +0 -1
- package/src/selection.test.ts +0 -67
- package/src/view-state/view-state.ts +0 -91
- /package/dist/types/src/{view-state → core}/backends.test.d.ts +0 -0
- /package/dist/types/src/{useArticleKeyboardNavigation.d.ts → hooks/useArticleKeyboardNavigation.d.ts} +0 -0
- /package/dist/types/src/{useArticleKeyboardNavigation.test.d.ts → hooks/useArticleKeyboardNavigation.test.d.ts} +0 -0
- /package/src/{useArticleKeyboardNavigation.test.ts → hooks/useArticleKeyboardNavigation.test.ts} +0 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { a as Manager, c as ATTENDABLE_SELECTOR, d as getAttendables, i as toggle, l as AttentionManager, n as aspect, r as resolve, s as ATTENDABLE_ATTRIBUTE } from "./chunk-types.mjs";
|
|
2
|
+
import { forwardRef, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { mx } from "@dxos/ui-theme";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { createContext } from "@radix-ui/react-context";
|
|
6
|
+
import { Atom } from "@effect-atom/atom";
|
|
7
|
+
import { RegistryContext } from "@effect-atom/atom-react";
|
|
8
|
+
import { Primitive } from "@radix-ui/react-primitive";
|
|
9
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
10
|
+
import { log } from "@dxos/log";
|
|
11
|
+
import { useDefaultValue } from "@dxos/react-hooks";
|
|
12
|
+
import { invariant } from "@dxos/invariant";
|
|
13
|
+
import * as Schema from "effect/Schema";
|
|
14
|
+
//#region src/components/AttentionProvider/attention-context.ts
|
|
15
|
+
var ATTENTION_NAME = "Attention";
|
|
16
|
+
var ATTENTION_SOURCE_ATTRIBUTE = "data-w-attention-source";
|
|
17
|
+
var [AttentionContextProvider, useAttentionContext] = createContext(ATTENTION_NAME, { attention: void 0 });
|
|
18
|
+
var UNKNOWN_ATTENDABLE = {
|
|
19
|
+
hasAttention: false,
|
|
20
|
+
isAncestor: false,
|
|
21
|
+
isRelated: false
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Subscribe to the attention state for a qualified graph ID.
|
|
25
|
+
*/
|
|
26
|
+
var useAttention = (attendableId) => {
|
|
27
|
+
const { attention } = useAttentionContext(ATTENTION_NAME);
|
|
28
|
+
const [state, setState] = useState(UNKNOWN_ATTENDABLE);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!attendableId || !attention) {
|
|
31
|
+
setState(UNKNOWN_ATTENDABLE);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const currentState = attention.get(attendableId);
|
|
35
|
+
setState(currentState);
|
|
36
|
+
return attention.subscribe(attendableId, (newState) => {
|
|
37
|
+
setState(newState);
|
|
38
|
+
});
|
|
39
|
+
}, [attention, attendableId]);
|
|
40
|
+
return state;
|
|
41
|
+
};
|
|
42
|
+
var useAttended = () => {
|
|
43
|
+
const { attention } = useAttentionContext(ATTENTION_NAME);
|
|
44
|
+
const [current, setCurrent] = useState([]);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!attention) return;
|
|
47
|
+
setCurrent(attention.getCurrent());
|
|
48
|
+
return attention.subscribeCurrent((newCurrent) => {
|
|
49
|
+
setCurrent(newCurrent);
|
|
50
|
+
});
|
|
51
|
+
}, [attention]);
|
|
52
|
+
return current;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Computes HTML element attributes to apply so the attention system can detect changes.
|
|
56
|
+
*/
|
|
57
|
+
var useAttentionAttributes = (attendableId) => {
|
|
58
|
+
const { hasAttention } = useAttention(attendableId);
|
|
59
|
+
return useMemo(() => {
|
|
60
|
+
const attributes = { [ATTENDABLE_ATTRIBUTE]: attendableId };
|
|
61
|
+
if (hasAttention) attributes[ATTENTION_SOURCE_ATTRIBUTE] = "true";
|
|
62
|
+
return attributes;
|
|
63
|
+
}, [attendableId, hasAttention]);
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/components/AttentionProvider/AttentionProvider.tsx
|
|
67
|
+
var __dxlog_file$1 = "/__w/dxos/dxos/packages/ui/react-ui-attention/src/components/AttentionProvider/AttentionProvider.tsx";
|
|
68
|
+
var RootAttentionProvider = ({ children, attention: propsAttention, onChange }) => {
|
|
69
|
+
const registry = useContext(RegistryContext);
|
|
70
|
+
const attention = useDefaultValue(propsAttention, () => new AttentionManager(registry));
|
|
71
|
+
return /* @__PURE__ */ jsx(AttentionContextProvider, {
|
|
72
|
+
attention,
|
|
73
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
74
|
+
className: "contents",
|
|
75
|
+
onFocusCapture: useCallback((event) => {
|
|
76
|
+
log("focus", {
|
|
77
|
+
related: event.relatedTarget,
|
|
78
|
+
target: event.target
|
|
79
|
+
}, {
|
|
80
|
+
"~LogMeta": "~LogMeta",
|
|
81
|
+
F: __dxlog_file$1,
|
|
82
|
+
L: 37,
|
|
83
|
+
S: void 0
|
|
84
|
+
});
|
|
85
|
+
const selector = [ATTENDABLE_SELECTOR, ...Array.from(document.querySelectorAll("[aria-controls]")).map((el) => `[id="${el.getAttribute("aria-controls")}"]`)].join(",");
|
|
86
|
+
const prev = attention.getCurrent();
|
|
87
|
+
const next = getAttendables(selector, event.target);
|
|
88
|
+
if (next.length > 0 && (prev.length !== next.length || !!prev.find((id, index) => next[index] !== id))) {
|
|
89
|
+
attention.update(next);
|
|
90
|
+
onChange?.(next);
|
|
91
|
+
}
|
|
92
|
+
}, [attention, onChange]),
|
|
93
|
+
children
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Note that DeckPlugin and StackPlugin both handle attention on their own,
|
|
99
|
+
* and when rendering content in those cases it is not necessary to also render an `AttendableContainer`.
|
|
100
|
+
* This component is primarily for Storybook stories and other testing scenarios,
|
|
101
|
+
* or the rare cases where an attendable entity is rendered outside of either of those plugins.
|
|
102
|
+
*/
|
|
103
|
+
var AttendableContainer = forwardRef(({ id, classNames, children, asChild, ...props }, forwardedRef) => {
|
|
104
|
+
const attentionAttrs = useAttentionAttributes(id);
|
|
105
|
+
return /* @__PURE__ */ jsx(asChild ? Slot : Primitive.div, {
|
|
106
|
+
...props,
|
|
107
|
+
...attentionAttrs,
|
|
108
|
+
className: mx("dx-attention-surface", props.tabIndex === 0 && "dx-focus-ring-inset-over-all", classNames),
|
|
109
|
+
ref: forwardedRef,
|
|
110
|
+
children
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/components/ViewStateProvider/view-state-hooks.ts
|
|
115
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-attention/src/components/ViewStateProvider/view-state-hooks.ts";
|
|
116
|
+
var VIEW_STATE_NAME = "ViewState";
|
|
117
|
+
var [ViewStateContextProvider, useViewStateContext] = createContext(VIEW_STATE_NAME, { manager: void 0 });
|
|
118
|
+
/** Access the underlying Manager from context. Throws when used outside a `ViewStateProvider`. */
|
|
119
|
+
var useManager = () => {
|
|
120
|
+
const { manager } = useViewStateContext(VIEW_STATE_NAME);
|
|
121
|
+
invariant(manager, "useManager() requires a ViewStateProvider ancestor.", {
|
|
122
|
+
"~LogMeta": "~LogMeta",
|
|
123
|
+
F: __dxlog_file,
|
|
124
|
+
L: 28,
|
|
125
|
+
S: void 0,
|
|
126
|
+
A: ["manager", "'useManager() requires a ViewStateProvider ancestor.'"]
|
|
127
|
+
});
|
|
128
|
+
return manager;
|
|
129
|
+
};
|
|
130
|
+
/** Access the Manager if a provider is present; `undefined` otherwise (e.g. isolated stories/tests). */
|
|
131
|
+
var useManagerOptional = () => {
|
|
132
|
+
const { manager } = useViewStateContext(VIEW_STATE_NAME);
|
|
133
|
+
return manager;
|
|
134
|
+
};
|
|
135
|
+
/** Reactive read of an aspect value for a context; yields the aspect default when unset or unprovided. */
|
|
136
|
+
var useViewState = (aspect, contextId) => {
|
|
137
|
+
const { manager } = useViewStateContext(VIEW_STATE_NAME);
|
|
138
|
+
const [value, setValue] = useState(() => contextId && manager ? manager.get(aspect, contextId) : aspect.defaultValue());
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (!contextId || !manager) {
|
|
141
|
+
setValue(aspect.defaultValue());
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
setValue(manager.get(aspect, contextId));
|
|
145
|
+
return manager.subscribe(aspect, contextId, setValue);
|
|
146
|
+
}, [
|
|
147
|
+
manager,
|
|
148
|
+
aspect,
|
|
149
|
+
contextId
|
|
150
|
+
]);
|
|
151
|
+
return value;
|
|
152
|
+
};
|
|
153
|
+
var useViewStateActions = (aspect, contextId) => {
|
|
154
|
+
const { manager } = useViewStateContext(VIEW_STATE_NAME);
|
|
155
|
+
return useMemo(() => ({
|
|
156
|
+
set: (value) => {
|
|
157
|
+
if (contextId) manager?.set(aspect, contextId, value);
|
|
158
|
+
},
|
|
159
|
+
update: (fn) => {
|
|
160
|
+
if (contextId) manager?.update(aspect, contextId, fn);
|
|
161
|
+
},
|
|
162
|
+
clear: () => {
|
|
163
|
+
if (contextId) manager?.set(aspect, contextId, aspect.defaultValue());
|
|
164
|
+
}
|
|
165
|
+
}), [
|
|
166
|
+
manager,
|
|
167
|
+
aspect,
|
|
168
|
+
contextId
|
|
169
|
+
]);
|
|
170
|
+
};
|
|
171
|
+
/** Resolved selection value for `contextId` in the requested `mode` (default `multi`). */
|
|
172
|
+
var useSelection = (contextId, mode = "multi") => resolve(useViewState(aspect, contextId), mode);
|
|
173
|
+
/** Selection mutators for a single context, built on the generic ViewState actions. */
|
|
174
|
+
var useSelectionActions = (contextId) => {
|
|
175
|
+
const { update, clear } = useViewStateActions(aspect, contextId);
|
|
176
|
+
return useMemo(() => ({
|
|
177
|
+
single: (id) => update(() => ({
|
|
178
|
+
mode: "single",
|
|
179
|
+
id
|
|
180
|
+
})),
|
|
181
|
+
multi: (ids) => update(() => ({
|
|
182
|
+
mode: "multi",
|
|
183
|
+
ids: [...ids]
|
|
184
|
+
})),
|
|
185
|
+
range: (from, to) => update(() => ({
|
|
186
|
+
mode: "range",
|
|
187
|
+
from,
|
|
188
|
+
to
|
|
189
|
+
})),
|
|
190
|
+
toggle: (id) => update((prev) => toggle(prev, id)),
|
|
191
|
+
clear
|
|
192
|
+
}), [update, clear]);
|
|
193
|
+
};
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/core/backends.ts
|
|
196
|
+
var cacheKey = (aspect, contextId) => `${aspect.key}:${contextId}`;
|
|
197
|
+
/** In-memory backend: state is ephemeral and scoped to the session (never persisted). */
|
|
198
|
+
var MemoryBackend = class {
|
|
199
|
+
#atoms = /* @__PURE__ */ new Map();
|
|
200
|
+
atom(aspect, contextId) {
|
|
201
|
+
const key = cacheKey(aspect, contextId);
|
|
202
|
+
let atom = this.#atoms.get(key);
|
|
203
|
+
if (!atom) {
|
|
204
|
+
atom = Atom.make(aspect.defaultValue()).pipe(Atom.keepAlive);
|
|
205
|
+
this.#atoms.set(key, atom);
|
|
206
|
+
}
|
|
207
|
+
return atom;
|
|
208
|
+
}
|
|
209
|
+
contexts(aspect) {
|
|
210
|
+
const prefix = `${aspect.key}:`;
|
|
211
|
+
return [...this.#atoms.keys()].filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length));
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var STORAGE_PREFIX = "dxos:view-state:";
|
|
215
|
+
var storageKeyFor = (aspect, contextId) => `${STORAGE_PREFIX}${aspect.key}:${contextId}`;
|
|
216
|
+
var safeLocalStorage = () => {
|
|
217
|
+
try {
|
|
218
|
+
return globalThis.localStorage;
|
|
219
|
+
} catch {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
/** localStorage-backed backend: seeds atoms from storage, persists on set, syncs across tabs. */
|
|
224
|
+
var LocalBackend = class {
|
|
225
|
+
#registry;
|
|
226
|
+
#storage;
|
|
227
|
+
#atoms = /* @__PURE__ */ new Map();
|
|
228
|
+
#byStorageKey = /* @__PURE__ */ new Map();
|
|
229
|
+
#storageListener;
|
|
230
|
+
constructor({ registry, storage }) {
|
|
231
|
+
this.#registry = registry;
|
|
232
|
+
this.#storage = storage ?? safeLocalStorage();
|
|
233
|
+
if (this.#storage && typeof globalThis.addEventListener === "function") {
|
|
234
|
+
this.#storageListener = (event) => {
|
|
235
|
+
if (!event.key || !event.key.startsWith(STORAGE_PREFIX)) return;
|
|
236
|
+
const entry = this.#byStorageKey.get(event.key);
|
|
237
|
+
const atom = entry && this.#atoms.get(cacheKey(entry.aspect, entry.contextId));
|
|
238
|
+
if (entry && atom) this.#registry.set(atom, this.#read(entry.aspect, event.key));
|
|
239
|
+
};
|
|
240
|
+
globalThis.addEventListener("storage", this.#storageListener);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
atom(aspect, contextId) {
|
|
244
|
+
const key = cacheKey(aspect, contextId);
|
|
245
|
+
let atom = this.#atoms.get(key);
|
|
246
|
+
if (!atom) {
|
|
247
|
+
const storageKey = storageKeyFor(aspect, contextId);
|
|
248
|
+
atom = Atom.make(this.#read(aspect, storageKey)).pipe(Atom.keepAlive);
|
|
249
|
+
this.#atoms.set(key, atom);
|
|
250
|
+
this.#byStorageKey.set(storageKey, {
|
|
251
|
+
aspect,
|
|
252
|
+
contextId
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return atom;
|
|
256
|
+
}
|
|
257
|
+
persist(aspect, contextId, value) {
|
|
258
|
+
this.#storage?.setItem(storageKeyFor(aspect, contextId), JSON.stringify(Schema.encodeSync(aspect.schema)(value)));
|
|
259
|
+
}
|
|
260
|
+
contexts(aspect) {
|
|
261
|
+
if (!this.#storage) {
|
|
262
|
+
const prefix = `${aspect.key}:`;
|
|
263
|
+
return [...this.#atoms.keys()].filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length));
|
|
264
|
+
}
|
|
265
|
+
const prefix = storageKeyFor(aspect, "");
|
|
266
|
+
const ids = [];
|
|
267
|
+
for (let index = 0; index < this.#storage.length; index++) {
|
|
268
|
+
const key = this.#storage.key(index);
|
|
269
|
+
if (key?.startsWith(prefix)) ids.push(key.slice(prefix.length));
|
|
270
|
+
}
|
|
271
|
+
return ids;
|
|
272
|
+
}
|
|
273
|
+
dispose() {
|
|
274
|
+
if (this.#storageListener && typeof globalThis.removeEventListener === "function") globalThis.removeEventListener("storage", this.#storageListener);
|
|
275
|
+
this.#atoms.clear();
|
|
276
|
+
this.#byStorageKey.clear();
|
|
277
|
+
}
|
|
278
|
+
#read(aspect, storageKey) {
|
|
279
|
+
const raw = this.#storage?.getItem(storageKey);
|
|
280
|
+
if (raw == null) return aspect.defaultValue();
|
|
281
|
+
try {
|
|
282
|
+
return Schema.decodeUnknownSync(aspect.schema)(JSON.parse(raw));
|
|
283
|
+
} catch {
|
|
284
|
+
return aspect.defaultValue();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
var createDefaultBackends = (registry) => ({
|
|
289
|
+
memory: new MemoryBackend(),
|
|
290
|
+
local: new LocalBackend({ registry })
|
|
291
|
+
});
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/components/ViewStateProvider/ViewStateProvider.tsx
|
|
294
|
+
/** Provides the per-context UI state manager. Replaces the former `SelectionProvider`. */
|
|
295
|
+
var ViewStateProvider = ({ children, manager: managerProp }) => {
|
|
296
|
+
const registry = useContext(RegistryContext);
|
|
297
|
+
return /* @__PURE__ */ jsx(ViewStateContextProvider, {
|
|
298
|
+
manager: useDefaultValue(managerProp, () => new Manager({
|
|
299
|
+
registry,
|
|
300
|
+
backends: createDefaultBackends(registry)
|
|
301
|
+
})),
|
|
302
|
+
children
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
//#endregion
|
|
306
|
+
export { useManager as a, useSelectionActions as c, AttendableContainer as d, RootAttentionProvider as f, useAttentionContext as g, useAttentionAttributes as h, createDefaultBackends as i, useViewState as l, useAttention as m, LocalBackend as n, useManagerOptional as o, useAttended as p, MemoryBackend as r, useSelection as s, ViewStateProvider as t, useViewStateActions as u };
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=chunk-ViewStateProvider.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-ViewStateProvider.mjs","names":[],"sources":["../../src/components/AttentionProvider/attention-context.ts","../../src/components/AttentionProvider/AttentionProvider.tsx","../../src/components/ViewStateProvider/view-state-hooks.ts","../../src/core/backends.ts","../../src/components/ViewStateProvider/ViewStateProvider.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { ATTENDABLE_ATTRIBUTE, type Attention, AttentionManager } from '../../types/Attention';\n\n// Kept out of `AttentionProvider.tsx`: react-refresh only fast-refreshes a module whose exports are\n// all components, so the context and hooks exported beside them force a full page reload on every edit.\n\nexport const ATTENTION_NAME = 'Attention';\nexport const ATTENTION_SOURCE_ATTRIBUTE = 'data-w-attention-source';\n\nexport type AttentionContextValue = {\n attention: AttentionManager;\n};\n\nexport const [AttentionContextProvider, useAttentionContext] = createContext<AttentionContextValue>(ATTENTION_NAME, {\n attention: undefined as unknown as AttentionManager,\n});\n\nexport const UNKNOWN_ATTENDABLE = { hasAttention: false, isAncestor: false, isRelated: false } as Attention;\n\n/**\n * Subscribe to the attention state for a qualified graph ID.\n */\n// TODO(burdon): Unify with selection state and change to contextId?\nexport const useAttention = (attendableId?: string): Attention => {\n const { attention } = useAttentionContext(ATTENTION_NAME);\n const [state, setState] = useState<Attention>(UNKNOWN_ATTENDABLE);\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\nexport const useAttended = () => {\n const { attention } = useAttentionContext(ATTENTION_NAME);\n const [current, setCurrent] = useState<readonly string[]>([]);\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 */\nexport const 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","//\n// Copyright 2024 DXOS.org\n//\n\nimport { RegistryContext } from '@effect-atom/atom-react';\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 useCallback,\n useContext,\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 { ATTENDABLE_SELECTOR, AttentionManager, getAttendables } from '../../types/Attention';\nimport { AttentionContextProvider, useAttentionAttributes } from './attention-context';\n\ntype RootAttentionProviderProps = PropsWithChildren<{\n attention?: AttentionManager;\n onChange?: (nextAttended: string[]) => void;\n}>;\n\nconst RootAttentionProvider = ({ children, attention: propsAttention, onChange }: RootAttentionProviderProps) => {\n const registry = useContext(RegistryContext);\n const attention = useDefaultValue(propsAttention, () => new AttentionManager(registry));\n\n const handleFocus = useCallback(\n (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 ATTENDABLE_SELECTOR,\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 [attention, onChange],\n );\n\n return (\n <AttentionContextProvider attention={attention}>\n <div 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 {...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 { AttendableContainer, RootAttentionProvider };\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { invariant } from '@dxos/invariant';\n\nimport { Selection, ViewState } from '../../types';\n\n// Kept out of `ViewStateProvider.tsx`: react-refresh only fast-refreshes a module whose exports are\n// all components, so the context and hooks exported beside it force a full page reload on every edit.\n\nexport const VIEW_STATE_NAME = 'ViewState';\n\nexport type ViewStateContextValue = { manager?: ViewState.Manager };\n\n// Default value lets consumers render outside a provider (isolated stories/tests) without throwing;\n// `manager` reads as `undefined` and hooks fall back to aspect defaults / no-op actions.\nexport const [ViewStateContextProvider, useViewStateContext] = createContext<ViewStateContextValue>(VIEW_STATE_NAME, {\n manager: undefined,\n});\n\n/** Access the underlying Manager from context. Throws when used outside a `ViewStateProvider`. */\nexport const useManager = (): ViewState.Manager => {\n const { manager } = useViewStateContext(VIEW_STATE_NAME);\n invariant(manager, 'useManager() requires a ViewStateProvider ancestor.');\n return manager;\n};\n\n/** Access the Manager if a provider is present; `undefined` otherwise (e.g. isolated stories/tests). */\nexport const useManagerOptional = (): ViewState.Manager | undefined => {\n const { manager } = useViewStateContext(VIEW_STATE_NAME);\n return manager;\n};\n\n/** Reactive read of an aspect value for a context; yields the aspect default when unset or unprovided. */\nexport const useViewState = <T, Encoded = T>(aspect: ViewState.Aspect<T, Encoded>, contextId?: string): T => {\n const { manager } = useViewStateContext(VIEW_STATE_NAME);\n const [value, setValue] = useState<T>(() =>\n contextId && manager ? manager.get(aspect, contextId) : aspect.defaultValue(),\n );\n useEffect(() => {\n if (!contextId || !manager) {\n setValue(aspect.defaultValue());\n return;\n }\n setValue(manager.get(aspect, contextId));\n return manager.subscribe(aspect, contextId, setValue);\n }, [manager, aspect, contextId]);\n return value;\n};\n\nexport type UseViewStateActions<T> = {\n set: (value: T) => void;\n update: (fn: (prev: T) => T) => void;\n clear: () => void;\n};\n\nexport const useViewStateActions = <T, Encoded = T>(\n aspect: ViewState.Aspect<T, Encoded>,\n contextId?: string,\n): UseViewStateActions<T> => {\n const { manager } = useViewStateContext(VIEW_STATE_NAME);\n return useMemo<UseViewStateActions<T>>(\n () => ({\n set: (value) => {\n if (contextId) {\n manager?.set(aspect, contextId, value);\n }\n },\n update: (fn) => {\n if (contextId) {\n manager?.update(aspect, contextId, fn);\n }\n },\n clear: () => {\n if (contextId) {\n manager?.set(aspect, contextId, aspect.defaultValue());\n }\n },\n }),\n [manager, aspect, contextId],\n );\n};\n\n/** Resolved selection value for `contextId` in the requested `mode` (default `multi`). */\nexport const useSelection = <T extends Selection.SelectionMode>(\n contextId?: string,\n mode: T = 'multi' as T,\n): Selection.Result<T> => Selection.resolve(useViewState(Selection.aspect, contextId), mode);\n\nexport type UseSelectionActions = {\n single: (id: string) => void;\n multi: (ids: string[]) => void;\n range: (from: string, to: string) => void;\n toggle: (id: string) => void;\n clear: () => void;\n};\n\n/** Selection mutators for a single context, built on the generic ViewState actions. */\nexport const useSelectionActions = (contextId?: string): UseSelectionActions => {\n const { update, clear } = useViewStateActions(Selection.aspect, contextId);\n return useMemo<UseSelectionActions>(\n () => ({\n single: (id) => update(() => ({ mode: 'single', id })),\n multi: (ids) => update(() => ({ mode: 'multi', ids: [...ids] })),\n range: (from, to) => update(() => ({ mode: 'range', from, to })),\n toggle: (id) => update((prev) => Selection.toggle(prev, id)),\n clear,\n }),\n [update, clear],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { Atom, type Registry } from '@effect-atom/atom';\nimport * as Schema from 'effect/Schema';\n\nimport { ViewState } from '../types';\n\n// Only the stable `key` string is needed to form the map key; avoids variance issues with Aspect<T>.\nconst cacheKey = (aspect: { key: string }, contextId: string) => `${aspect.key}:${contextId}`;\n\n/** In-memory backend: state is ephemeral and scoped to the session (never persisted). */\nexport class MemoryBackend implements ViewState.Backend {\n readonly #atoms = new Map<string, Atom.Writable<unknown>>();\n\n atom<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>, contextId: string): Atom.Writable<T> {\n const key = cacheKey(aspect, contextId);\n let atom = this.#atoms.get(key);\n if (!atom) {\n // `keepAlive` pins the node so a written value survives for the session; without it the registry\n // sweeps the unsubscribed atom back to its default, dropping state that no UI happens to observe\n // (e.g. a selection read on-demand by an agent tool rather than a live subscriber).\n atom = Atom.make<unknown>(aspect.defaultValue()).pipe(Atom.keepAlive);\n this.#atoms.set(key, atom);\n }\n // Cast bridges the per-aspect value type erased by the shared atom map; safe by construction.\n return atom as Atom.Writable<T>;\n }\n\n contexts<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>): string[] {\n const prefix = `${aspect.key}:`;\n return [...this.#atoms.keys()].filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length));\n }\n}\n\nconst STORAGE_PREFIX = 'dxos:view-state:';\n\nconst storageKeyFor = (aspect: { key: string }, contextId: string) => `${STORAGE_PREFIX}${aspect.key}:${contextId}`;\n\n// Accessing `globalThis.localStorage` can throw a SecurityError in sandboxed iframes or when\n// storage is blocked; degrade to in-memory behaviour instead of crashing.\nconst safeLocalStorage = (): Storage | undefined => {\n try {\n return globalThis.localStorage;\n } catch {\n return undefined;\n }\n};\n\nexport interface LocalBackendOptions {\n readonly registry: Registry.Registry;\n /** Injectable for tests; defaults to `window.localStorage`. */\n readonly storage?: Storage;\n}\n\n/** localStorage-backed backend: seeds atoms from storage, persists on set, syncs across tabs. */\nexport class LocalBackend implements ViewState.Backend {\n readonly #registry: Registry.Registry;\n // Absent in non-browser contexts (SSR/tests without injection); the backend then degrades to\n // ephemeral, in-memory behaviour rather than crashing on a missing `localStorage`.\n readonly #storage: Storage | undefined;\n readonly #atoms = new Map<string, Atom.Writable<unknown>>();\n // Reverse map: storage key -> (aspect, contextId) so `storage` events can target the right atom.\n readonly #byStorageKey = new Map<string, { aspect: ViewState.Aspect<unknown, unknown>; contextId: string }>();\n #storageListener?: (event: StorageEvent) => void;\n\n constructor({ registry, storage }: LocalBackendOptions) {\n this.#registry = registry;\n this.#storage = storage ?? safeLocalStorage();\n if (this.#storage && typeof globalThis.addEventListener === 'function') {\n this.#storageListener = (event) => {\n if (!event.key || !event.key.startsWith(STORAGE_PREFIX)) {\n return;\n }\n const entry = this.#byStorageKey.get(event.key);\n const atom = entry && this.#atoms.get(cacheKey(entry.aspect, entry.contextId));\n if (entry && atom) {\n this.#registry.set(atom, this.#read(entry.aspect, event.key));\n }\n };\n globalThis.addEventListener('storage', this.#storageListener);\n }\n }\n\n atom<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>, contextId: string): Atom.Writable<T> {\n const key = cacheKey(aspect, contextId);\n let atom = this.#atoms.get(key);\n if (!atom) {\n const storageKey = storageKeyFor(aspect, contextId);\n // `keepAlive` pins the node so the in-memory value stays consistent with storage without a live\n // subscriber; otherwise the registry sweeps the unsubscribed atom back to its creation-time seed.\n atom = Atom.make<unknown>(this.#read(aspect, storageKey)).pipe(Atom.keepAlive);\n this.#atoms.set(key, atom);\n // Cast erases the per-aspect value type so the reverse map can hold aspects of any `T`; the\n // stored aspect is only used to re-read/decode its own value, so the erasure is safe.\n this.#byStorageKey.set(storageKey, { aspect: aspect as ViewState.Aspect<unknown, unknown>, contextId });\n }\n // Cast bridges the per-aspect value type erased by the shared atom map; safe by construction.\n return atom as Atom.Writable<T>;\n }\n\n persist<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>, contextId: string, value: T): void {\n this.#storage?.setItem(storageKeyFor(aspect, contextId), JSON.stringify(Schema.encodeSync(aspect.schema)(value)));\n }\n\n contexts<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>): string[] {\n if (!this.#storage) {\n // No persistent storage: fall back to the in-memory atoms (mirrors `atom()`'s ephemeral path).\n const prefix = `${aspect.key}:`;\n return [...this.#atoms.keys()].filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length));\n }\n const prefix = storageKeyFor(aspect, '');\n const ids: string[] = [];\n for (let index = 0; index < this.#storage.length; index++) {\n const key = this.#storage.key(index);\n if (key?.startsWith(prefix)) {\n ids.push(key.slice(prefix.length));\n }\n }\n return ids;\n }\n\n dispose(): void {\n if (this.#storageListener && typeof globalThis.removeEventListener === 'function') {\n globalThis.removeEventListener('storage', this.#storageListener);\n }\n // Allow safe reuse after disposal: drop cached atoms and their reverse-key entries.\n this.#atoms.clear();\n this.#byStorageKey.clear();\n }\n\n #read<T, Encoded>(aspect: ViewState.Aspect<T, Encoded>, storageKey: string): T {\n const raw = this.#storage?.getItem(storageKey);\n if (raw == null) {\n return aspect.defaultValue();\n }\n try {\n return Schema.decodeUnknownSync(aspect.schema)(JSON.parse(raw));\n } catch {\n // Tolerate stale/corrupt entries (e.g., a prior schema shape) by falling back to the default.\n return aspect.defaultValue();\n }\n }\n}\n\nexport const createDefaultBackends = (\n registry: Registry.Registry,\n): Record<ViewState.BackendName, ViewState.Backend> => ({\n memory: new MemoryBackend(),\n local: new LocalBackend({ registry }),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { RegistryContext } from '@effect-atom/atom-react';\nimport React, { type PropsWithChildren, useContext } from 'react';\n\nimport { useDefaultValue } from '@dxos/react-hooks';\n\nimport { createDefaultBackends } from '../../core';\nimport { ViewState } from '../../types';\nimport { ViewStateContextProvider } from './view-state-hooks';\n\n/** Provides the per-context UI state manager. Replaces the former `SelectionProvider`. */\nexport const ViewStateProvider = ({\n children,\n manager: managerProp,\n}: PropsWithChildren<{ manager?: ViewState.Manager }>) => {\n const registry = useContext(RegistryContext);\n const manager = useDefaultValue(\n managerProp,\n () => new ViewState.Manager({ registry, backends: createDefaultBackends(registry) }),\n );\n return <ViewStateContextProvider manager={manager}>{children}</ViewStateContextProvider>;\n};\n"],"mappings":"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"}
|