@dxos/react-ui-attention 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/lib/chunk-ViewStateProvider.mjs +308 -0
  2. package/dist/lib/chunk-ViewStateProvider.mjs.map +1 -0
  3. package/dist/lib/chunk-types.mjs +351 -0
  4. package/dist/lib/chunk-types.mjs.map +1 -0
  5. package/dist/lib/index.mjs +149 -0
  6. package/dist/lib/index.mjs.map +1 -0
  7. package/dist/lib/testing.mjs +20 -0
  8. package/dist/lib/testing.mjs.map +1 -0
  9. package/dist/lib/types.mjs +2 -0
  10. package/dist/types/src/components/AttentionProvider/AttentionProvider.d.ts +2 -15
  11. package/dist/types/src/components/AttentionProvider/AttentionProvider.d.ts.map +1 -1
  12. package/dist/types/src/components/AttentionProvider/attention-context.d.ts +20 -0
  13. package/dist/types/src/components/AttentionProvider/attention-context.d.ts.map +1 -0
  14. package/dist/types/src/components/AttentionProvider/index.d.ts +1 -0
  15. package/dist/types/src/components/AttentionProvider/index.d.ts.map +1 -1
  16. package/dist/types/src/components/ViewStateProvider/ViewStateProvider.d.ts +2 -26
  17. package/dist/types/src/components/ViewStateProvider/ViewStateProvider.d.ts.map +1 -1
  18. package/dist/types/src/components/ViewStateProvider/index.d.ts +1 -0
  19. package/dist/types/src/components/ViewStateProvider/index.d.ts.map +1 -1
  20. package/dist/types/src/components/ViewStateProvider/view-state-hooks.d.ts +32 -0
  21. package/dist/types/src/components/ViewStateProvider/view-state-hooks.d.ts.map +1 -0
  22. package/dist/types/src/core/backends.d.ts +24 -0
  23. package/dist/types/src/core/backends.d.ts.map +1 -0
  24. package/dist/types/src/core/backends.test.d.ts.map +1 -0
  25. package/dist/types/src/core/index.d.ts +2 -0
  26. package/dist/types/src/core/index.d.ts.map +1 -0
  27. package/dist/types/src/hooks/index.d.ts +2 -0
  28. package/dist/types/src/hooks/index.d.ts.map +1 -0
  29. package/dist/types/src/hooks/useArticleKeyboardNavigation.d.ts.map +1 -0
  30. package/dist/types/src/hooks/useArticleKeyboardNavigation.test.d.ts.map +1 -0
  31. package/dist/types/src/index.d.ts +3 -4
  32. package/dist/types/src/index.d.ts.map +1 -1
  33. package/dist/types/src/{attention.d.ts → types/Attention.d.ts} +13 -2
  34. package/dist/types/src/types/Attention.d.ts.map +1 -0
  35. package/dist/types/src/types/Attention.test.d.ts +2 -0
  36. package/dist/types/src/types/Attention.test.d.ts.map +1 -0
  37. package/dist/types/src/{selection.d.ts → types/Selection.d.ts} +12 -10
  38. package/dist/types/src/types/Selection.d.ts.map +1 -0
  39. package/dist/types/src/types/Selection.test.d.ts +2 -0
  40. package/dist/types/src/types/Selection.test.d.ts.map +1 -0
  41. package/dist/types/src/types/ViewState.d.ts +66 -0
  42. package/dist/types/src/types/ViewState.d.ts.map +1 -0
  43. package/dist/types/src/types/ViewState.test.d.ts +2 -0
  44. package/dist/types/src/types/ViewState.test.d.ts.map +1 -0
  45. package/dist/types/src/types/index.d.ts +3 -3
  46. package/dist/types/src/types/index.d.ts.map +1 -1
  47. package/dist/types/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +18 -20
  49. package/src/components/AttentionProvider/AttentionProvider.stories.tsx +1 -1
  50. package/src/components/AttentionProvider/AttentionProvider.tsx +4 -86
  51. package/src/components/AttentionProvider/attention-context.ts +81 -0
  52. package/src/components/AttentionProvider/index.ts +2 -0
  53. package/src/components/ViewStateProvider/ViewStateProvider.test.tsx +7 -5
  54. package/src/components/ViewStateProvider/ViewStateProvider.tsx +6 -110
  55. package/src/components/ViewStateProvider/index.ts +9 -0
  56. package/src/components/ViewStateProvider/view-state-hooks.ts +115 -0
  57. package/src/{view-state → core}/backends.test.ts +5 -5
  58. package/src/{view-state → core}/backends.ts +24 -17
  59. package/src/{view-state → core}/index.ts +0 -1
  60. package/src/hooks/index.ts +5 -0
  61. package/src/{useArticleKeyboardNavigation.ts → hooks/useArticleKeyboardNavigation.ts} +1 -1
  62. package/src/index.ts +3 -4
  63. package/src/testing/decorators/withAttention.ts +2 -2
  64. package/src/{attention.test.ts → types/Attention.test.ts} +2 -2
  65. package/src/{attention.ts → types/Attention.ts} +17 -2
  66. package/src/types/Selection.test.ts +100 -0
  67. package/src/{selection.ts → types/Selection.ts} +27 -17
  68. package/src/{view-state/view-state.test.ts → types/ViewState.test.ts} +6 -6
  69. package/src/types/ViewState.ts +101 -0
  70. package/src/types/index.ts +8 -7
  71. package/dist/lib/browser/chunk-4HYAJ4IO.mjs +0 -434
  72. package/dist/lib/browser/chunk-4HYAJ4IO.mjs.map +0 -7
  73. package/dist/lib/browser/chunk-I4FDY4AZ.mjs +0 -236
  74. package/dist/lib/browser/chunk-I4FDY4AZ.mjs.map +0 -7
  75. package/dist/lib/browser/index.mjs +0 -218
  76. package/dist/lib/browser/index.mjs.map +0 -7
  77. package/dist/lib/browser/meta.json +0 -1
  78. package/dist/lib/browser/testing/index.mjs +0 -30
  79. package/dist/lib/browser/testing/index.mjs.map +0 -7
  80. package/dist/lib/browser/types/index.mjs +0 -43
  81. package/dist/lib/browser/types/index.mjs.map +0 -7
  82. package/dist/lib/node-esm/chunk-DLBZMHST.mjs +0 -237
  83. package/dist/lib/node-esm/chunk-DLBZMHST.mjs.map +0 -7
  84. package/dist/lib/node-esm/chunk-HWN7KJDX.mjs +0 -436
  85. package/dist/lib/node-esm/chunk-HWN7KJDX.mjs.map +0 -7
  86. package/dist/lib/node-esm/index.mjs +0 -219
  87. package/dist/lib/node-esm/index.mjs.map +0 -7
  88. package/dist/lib/node-esm/meta.json +0 -1
  89. package/dist/lib/node-esm/testing/index.mjs +0 -31
  90. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  91. package/dist/lib/node-esm/types/index.mjs +0 -44
  92. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  93. package/dist/types/src/attention.d.ts.map +0 -1
  94. package/dist/types/src/attention.test.d.ts +0 -2
  95. package/dist/types/src/attention.test.d.ts.map +0 -1
  96. package/dist/types/src/selection.d.ts.map +0 -1
  97. package/dist/types/src/selection.test.d.ts +0 -2
  98. package/dist/types/src/selection.test.d.ts.map +0 -1
  99. package/dist/types/src/useArticleKeyboardNavigation.d.ts.map +0 -1
  100. package/dist/types/src/useArticleKeyboardNavigation.test.d.ts.map +0 -1
  101. package/dist/types/src/view-state/backends.d.ts +0 -24
  102. package/dist/types/src/view-state/backends.d.ts.map +0 -1
  103. package/dist/types/src/view-state/backends.test.d.ts.map +0 -1
  104. package/dist/types/src/view-state/index.d.ts +0 -3
  105. package/dist/types/src/view-state/index.d.ts.map +0 -1
  106. package/dist/types/src/view-state/view-state.d.ts +0 -54
  107. package/dist/types/src/view-state/view-state.d.ts.map +0 -1
  108. package/dist/types/src/view-state/view-state.test.d.ts +0 -2
  109. package/dist/types/src/view-state/view-state.test.d.ts.map +0 -1
  110. package/src/selection.test.ts +0 -67
  111. package/src/view-state/view-state.ts +0 -91
  112. /package/dist/types/src/{view-state → core}/backends.test.d.ts +0 -0
  113. /package/dist/types/src/{useArticleKeyboardNavigation.d.ts → hooks/useArticleKeyboardNavigation.d.ts} +0 -0
  114. /package/dist/types/src/{useArticleKeyboardNavigation.test.d.ts → hooks/useArticleKeyboardNavigation.test.d.ts} +0 -0
  115. /package/src/{useArticleKeyboardNavigation.test.ts → hooks/useArticleKeyboardNavigation.test.ts} +0 -0
@@ -1,219 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
- import {
3
- AttendableContainer,
4
- RootAttentionProvider,
5
- ViewStateProvider,
6
- useAttended,
7
- useAttention,
8
- useAttentionAttributes,
9
- useAttentionContext,
10
- useSelection,
11
- useSelectionActions,
12
- useViewState,
13
- useViewStateActions,
14
- useViewStateManager,
15
- useViewStateManagerOptional
16
- } from "./chunk-DLBZMHST.mjs";
17
- import {
18
- AttentionManager,
19
- LocalBackend,
20
- MemoryBackend,
21
- SelectionSchema,
22
- ViewStateManager,
23
- createDefaultBackends,
24
- defaultSelection,
25
- defineViewState,
26
- expandAttendableId,
27
- getAttendables,
28
- getLinkedVariant,
29
- getParentId,
30
- getSegmentId,
31
- getSelectionSet,
32
- isLinkedSegment,
33
- linkedSegment,
34
- resolveSelection,
35
- selectionAspect,
36
- toggleSelection
37
- } from "./chunk-HWN7KJDX.mjs";
38
-
39
- // src/components/AttentionGlyph/AttentionGlyph.tsx
40
- import React, { forwardRef, useMemo } from "react";
41
- import { Icon } from "@dxos/react-ui";
42
- import { mx } from "@dxos/ui-theme";
43
- 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-bg", "[[data-attention=true]_&]:text-accent-fg", "[[aria-current][data-attention=true]_&]:bg-accent-bg", "[[aria-current][data-attention=true]_&]:text-accent-fg", '[[aria-selected="true"][data-attention=true]_&]:bg-accent-bg', '[[aria-selected="true"][data-attention=true]_&]:text-accent-fg');
44
- var presenceIconStyles = mx("w-3 h-3");
45
- var PresenceOne = () => {
46
- return /* @__PURE__ */ React.createElement("svg", {
47
- width: "12",
48
- height: "12",
49
- viewBox: "0 0 12 12",
50
- className: presenceIconStyles,
51
- fill: "none",
52
- xmlns: "http://www.w3.org/2000/svg"
53
- }, /* @__PURE__ */ React.createElement("circle", {
54
- cx: "6",
55
- cy: "6",
56
- r: "2.5",
57
- fill: "currentColor"
58
- }));
59
- };
60
- var PresenceMany = () => {
61
- return /* @__PURE__ */ React.createElement("svg", {
62
- width: "12",
63
- height: "12",
64
- viewBox: "0 0 12 12",
65
- className: presenceIconStyles,
66
- fill: "none",
67
- xmlns: "http://www.w3.org/2000/svg"
68
- }, /* @__PURE__ */ React.createElement("path", {
69
- 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",
70
- fill: "currentColor"
71
- }), /* @__PURE__ */ React.createElement("circle", {
72
- cx: "4.25",
73
- cy: "6",
74
- r: "2.5",
75
- fill: "currentColor"
76
- }));
77
- };
78
- var Syncing = () => {
79
- const animationProps = useMemo(() => ({
80
- // Synchronize animations.
81
- animationDelay: `-${Date.now() % 2e3}ms`
82
- }), []);
83
- return /* @__PURE__ */ React.createElement("div", {
84
- role: "status",
85
- className: "flex items-center"
86
- }, /* @__PURE__ */ React.createElement(Icon, {
87
- icon: "ph--circle-notch--bold",
88
- size: 3,
89
- style: animationProps,
90
- classNames: "text-subdued animate-[spin_2s_linear_infinite]"
91
- }));
92
- };
93
- var AttentionGlyph = /* @__PURE__ */ forwardRef(({ presence, attended, syncing, containsAttended, classNames, ...props }, forwardedRef) => {
94
- const icon = syncing ? /* @__PURE__ */ React.createElement(Syncing, null) : presence === "many" ? /* @__PURE__ */ React.createElement(PresenceMany, null) : presence === "one" ? /* @__PURE__ */ React.createElement(PresenceOne, null) : null;
95
- return /* @__PURE__ */ React.createElement("div", {
96
- className: "flex group",
97
- "data-attention": attended,
98
- "data-contains-attended": containsAttended
99
- }, /* @__PURE__ */ React.createElement("span", {
100
- ...props,
101
- className: mx(attentionGlyphStyles, classNames),
102
- ref: forwardedRef
103
- }, icon));
104
- });
105
-
106
- // src/useArticleKeyboardNavigation.ts
107
- import { useEffect, useMemo as useMemo2 } from "react";
108
- import { Keyboard, nestKeyboardContext } from "@dxos/keyboard";
109
- var advance = ({ ids, currentId, delta }) => {
110
- if (ids.length === 0) {
111
- return void 0;
112
- }
113
- const idx = currentId ? ids.indexOf(currentId) : -1;
114
- if (idx === -1) {
115
- return delta === 1 ? ids[0] : ids[ids.length - 1];
116
- }
117
- const next = Math.max(0, Math.min(ids.length - 1, idx + delta));
118
- return ids[next];
119
- };
120
- var useArticleKeyboardNavigation = ({ articleId, items, currentId, getId, onSelect }) => {
121
- const { hasAttention } = useAttention(articleId);
122
- const ids = useMemo2(() => items.map((item) => getId ? getId(item) : item.id), [
123
- items,
124
- getId
125
- ]);
126
- useEffect(() => {
127
- if (!hasAttention) {
128
- return;
129
- }
130
- const contextPath = nestKeyboardContext(articleId);
131
- const context = Keyboard.singleton.getContext(contextPath);
132
- const prevContext = Keyboard.singleton.getCurrentContext();
133
- Keyboard.singleton.setCurrentContext(contextPath);
134
- const nextBinding = {
135
- shortcut: "j",
136
- handler: () => {
137
- const target = advance({
138
- ids,
139
- currentId,
140
- delta: 1
141
- });
142
- if (target !== void 0) {
143
- onSelect(target);
144
- }
145
- },
146
- data: "Next item",
147
- disableInput: true
148
- };
149
- const prevBinding = {
150
- shortcut: "k",
151
- handler: () => {
152
- const target = advance({
153
- ids,
154
- currentId,
155
- delta: -1
156
- });
157
- if (target !== void 0) {
158
- onSelect(target);
159
- }
160
- },
161
- data: "Previous item",
162
- disableInput: true
163
- };
164
- context.bind(nextBinding);
165
- context.bind(prevBinding);
166
- return () => {
167
- context.unbind("j");
168
- context.unbind("k");
169
- if (Keyboard.singleton.getCurrentContext() === contextPath) {
170
- Keyboard.singleton.setCurrentContext(prevContext);
171
- }
172
- };
173
- }, [
174
- articleId,
175
- ids,
176
- currentId,
177
- onSelect,
178
- hasAttention
179
- ]);
180
- };
181
- export {
182
- AttendableContainer,
183
- AttentionGlyph,
184
- AttentionManager,
185
- LocalBackend,
186
- MemoryBackend,
187
- RootAttentionProvider,
188
- SelectionSchema,
189
- Syncing,
190
- ViewStateManager,
191
- ViewStateProvider,
192
- advance,
193
- createDefaultBackends,
194
- defaultSelection,
195
- defineViewState,
196
- expandAttendableId,
197
- getAttendables,
198
- getLinkedVariant,
199
- getParentId,
200
- getSegmentId,
201
- getSelectionSet,
202
- isLinkedSegment,
203
- linkedSegment,
204
- resolveSelection,
205
- selectionAspect,
206
- toggleSelection,
207
- useArticleKeyboardNavigation,
208
- useAttended,
209
- useAttention,
210
- useAttentionAttributes,
211
- useAttentionContext,
212
- useSelection,
213
- useSelectionActions,
214
- useViewState,
215
- useViewStateActions,
216
- useViewStateManager,
217
- useViewStateManagerOptional
218
- };
219
- //# sourceMappingURL=index.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/AttentionGlyph/AttentionGlyph.tsx", "../../../src/useArticleKeyboardNavigation.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Primitive } from '@radix-ui/react-primitive';\nimport React, { type ComponentPropsWithRef, type CSSProperties, 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-bg',\n '[[data-attention=true]_&]:text-accent-fg',\n '[[aria-current][data-attention=true]_&]:bg-accent-bg',\n '[[aria-current][data-attention=true]_&]:text-accent-fg',\n '[[aria-selected=\"true\"][data-attention=true]_&]:bg-accent-bg',\n '[[aria-selected=\"true\"][data-attention=true]_&]:text-accent-fg',\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 className='flex group' data-attention={attended} data-contains-attended={containsAttended}>\n <span {...props} className={mx(attentionGlyphStyles, classNames)} ref={forwardedRef}>\n {icon}\n </span>\n </div>\n );\n },\n);\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect, useMemo } from 'react';\n\nimport { Keyboard, nestKeyboardContext } from '@dxos/keyboard';\n\nimport { useAttention } from './components';\n\n/**\n * Compute the id to select after pressing 'j' (delta = 1) or 'k' (delta = -1).\n * Clamps at the list ends — pressing 'j' on the last item keeps the last item\n * selected (vim-style), and 'k' on the first item keeps the first.\n *\n * When no current selection exists, returns the first id (for delta = 1) or the\n * last id (for delta = -1) so the user can enter the list with either key.\n */\nexport const advance = ({\n ids,\n currentId,\n delta,\n}: {\n ids: readonly string[];\n currentId: string | undefined;\n delta: 1 | -1;\n}): string | undefined => {\n if (ids.length === 0) {\n return undefined;\n }\n\n const idx = currentId ? ids.indexOf(currentId) : -1;\n if (idx === -1) {\n return delta === 1 ? ids[0] : ids[ids.length - 1];\n }\n\n const next = Math.max(0, Math.min(ids.length - 1, idx + delta));\n return ids[next];\n};\n\nexport type UseArticleKeyboardNavigationOptions<T> = {\n /** Stable id for the article (used as the keyboard context path). */\n articleId: string;\n /** Ordered list of selectable items as they appear in the article. */\n items: readonly T[];\n /** Currently-selected id, if any. */\n currentId: string | undefined;\n /** Extracts the id from an item. Defaults to `item.id`. */\n getId?: (item: T) => string;\n /** Called with the id to select when the user presses 'j' or 'k'. */\n onSelect: (id: string) => void;\n};\n\n/**\n * Wire 'j' (next) and 'k' (previous) keyboard shortcuts for an article that\n * navigates a list of items (e.g., messages, events). Bindings are scoped to\n * the article's keyboard context so they only fire while the article has attention.\n *\n * Pass the items directly; ids are derived via `getId` (defaults to `item.id`).\n * Clamps at list boundaries. Active only when the article is attended.\n */\nexport const useArticleKeyboardNavigation: {\n <T extends { id: string }>(options: UseArticleKeyboardNavigationOptions<T>): void;\n <T>(options: UseArticleKeyboardNavigationOptions<T> & { getId: (item: T) => string }): void;\n} = <T>({ articleId, items, currentId, getId, onSelect }: UseArticleKeyboardNavigationOptions<T>): void => {\n const { hasAttention } = useAttention(articleId);\n\n // `getId` is optional only when `T extends { id: string }` (enforced by the overloads above),\n // so the fallback is sound; the cast bridges the generic erased by the implementation signature.\n const ids = useMemo(() => items.map((item) => (getId ? getId(item) : (item as { id: string }).id)), [items, getId]);\n\n useEffect(() => {\n if (!hasAttention) {\n return;\n }\n\n const contextPath = nestKeyboardContext(articleId);\n const context = Keyboard.singleton.getContext(contextPath);\n const prevContext = Keyboard.singleton.getCurrentContext();\n Keyboard.singleton.setCurrentContext(contextPath);\n\n const nextBinding = {\n shortcut: 'j',\n handler: () => {\n const target = advance({ ids, currentId, delta: 1 });\n if (target !== undefined) {\n onSelect(target);\n }\n },\n data: 'Next item',\n disableInput: true,\n };\n const prevBinding = {\n shortcut: 'k',\n handler: () => {\n const target = advance({ ids, currentId, delta: -1 });\n if (target !== undefined) {\n onSelect(target);\n }\n },\n data: 'Previous item',\n disableInput: true,\n };\n\n context.bind(nextBinding);\n context.bind(prevBinding);\n\n return () => {\n context.unbind('j');\n context.unbind('k');\n // Restore the prior context if we were the ones who set it.\n if (Keyboard.singleton.getCurrentContext() === contextPath) {\n Keyboard.singleton.setCurrentContext(prevContext);\n }\n };\n }, [articleId, ids, currentId, onSelect, hasAttention]);\n};\n"],
5
- "mappings": "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",
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", "animationDelay", "Date", "now", "div", "role", "icon", "size", "style", "classNames", "AttentionGlyph", "presence", "attended", "syncing", "containsAttended", "props", "forwardedRef", "data-attention", "data-contains-attended", "span", "ref", "useEffect", "useMemo", "Keyboard", "nestKeyboardContext", "advance", "ids", "currentId", "delta", "length", "undefined", "idx", "indexOf", "next", "Math", "max", "min", "useArticleKeyboardNavigation", "articleId", "items", "getId", "onSelect", "hasAttention", "useAttention", "useMemo", "map", "item", "id", "useEffect", "contextPath", "nestKeyboardContext", "context", "Keyboard", "singleton", "getContext", "prevContext", "getCurrentContext", "setCurrentContext", "nextBinding", "shortcut", "handler", "target", "data", "disableInput", "prevBinding", "bind", "unbind"]
7
- }
@@ -1 +0,0 @@
1
- {"inputs":{"src/attention.ts":{"bytes":25933,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true}],"format":"esm"},"src/components/AttentionGlyph/AttentionGlyph.tsx":{"bytes":9775,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"format":"esm"},"src/components/AttentionGlyph/index.ts":{"bytes":394,"imports":[{"path":"src/components/AttentionGlyph/AttentionGlyph.tsx","kind":"import-statement","original":"./AttentionGlyph"}],"format":"esm"},"src/components/AttentionProvider/AttentionProvider.tsx":{"bytes":18161,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"src/attention.ts","kind":"import-statement","original":"../../attention"}],"format":"esm"},"src/components/AttentionProvider/index.ts":{"bytes":401,"imports":[{"path":"src/components/AttentionProvider/AttentionProvider.tsx","kind":"import-statement","original":"./AttentionProvider"}],"format":"esm"},"src/view-state/view-state.ts":{"bytes":8199,"imports":[],"format":"esm"},"src/view-state/backends.ts":{"bytes":19210,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true}],"format":"esm"},"src/view-state/index.ts":{"bytes":470,"imports":[{"path":"src/view-state/view-state.ts","kind":"import-statement","original":"./view-state"},{"path":"src/view-state/backends.ts","kind":"import-statement","original":"./backends"}],"format":"esm"},"src/selection.ts":{"bytes":12380,"imports":[{"path":"effect/Match","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"src/view-state/index.ts","kind":"import-statement","original":"./view-state"}],"format":"esm"},"src/components/ViewStateProvider/ViewStateProvider.tsx":{"bytes":15088,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true},{"path":"src/selection.ts","kind":"import-statement","original":"../../selection"},{"path":"src/view-state/index.ts","kind":"import-statement","original":"../../view-state"}],"format":"esm"},"src/components/ViewStateProvider/index.ts":{"bytes":401,"imports":[{"path":"src/components/ViewStateProvider/ViewStateProvider.tsx","kind":"import-statement","original":"./ViewStateProvider"}],"format":"esm"},"src/components/index.ts":{"bytes":616,"imports":[{"path":"src/components/AttentionGlyph/index.ts","kind":"import-statement","original":"./AttentionGlyph"},{"path":"src/components/AttentionProvider/index.ts","kind":"import-statement","original":"./AttentionProvider"},{"path":"src/components/ViewStateProvider/index.ts","kind":"import-statement","original":"./ViewStateProvider"}],"format":"esm"},"src/useArticleKeyboardNavigation.ts":{"bytes":11909,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true},{"path":"src/components/index.ts","kind":"import-statement","original":"./components"}],"format":"esm"},"src/index.ts":{"bytes":790,"imports":[{"path":"src/attention.ts","kind":"import-statement","original":"./attention"},{"path":"src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"src/selection.ts","kind":"import-statement","original":"./selection"},{"path":"src/useArticleKeyboardNavigation.ts","kind":"import-statement","original":"./useArticleKeyboardNavigation"},{"path":"src/view-state/index.ts","kind":"import-statement","original":"./view-state"}],"format":"esm"},"src/testing/decorators/withAttention.ts":{"bytes":3505,"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/attention.ts","kind":"import-statement","original":"../../attention"},{"path":"src/components/index.ts","kind":"import-statement","original":"../../components"}],"format":"esm"},"src/testing/decorators/index.ts":{"bytes":389,"imports":[{"path":"src/testing/decorators/withAttention.ts","kind":"import-statement","original":"./withAttention"}],"format":"esm"},"src/testing/index.ts":{"bytes":382,"imports":[{"path":"src/testing/decorators/index.ts","kind":"import-statement","original":"./decorators"}],"format":"esm"},"src/types/index.ts":{"bytes":1166,"imports":[{"path":"src/attention.ts","kind":"import-statement","original":"../attention"},{"path":"src/selection.ts","kind":"import-statement","original":"../selection"},{"path":"src/view-state/index.ts","kind":"import-statement","original":"../view-state"}],"format":"esm"}},"outputs":{"dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":11208},"dist/lib/node-esm/index.mjs":{"imports":[{"path":"dist/lib/node-esm/chunk-DLBZMHST.mjs","kind":"import-statement"},{"path":"dist/lib/node-esm/chunk-HWN7KJDX.mjs","kind":"import-statement"},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/keyboard","kind":"import-statement","external":true}],"exports":["AttendableContainer","AttentionGlyph","AttentionManager","LocalBackend","MemoryBackend","RootAttentionProvider","SelectionSchema","Syncing","ViewStateManager","ViewStateProvider","advance","createDefaultBackends","defaultSelection","defineViewState","expandAttendableId","getAttendables","getLinkedVariant","getParentId","getSegmentId","getSelectionSet","isLinkedSegment","linkedSegment","resolveSelection","selectionAspect","toggleSelection","useArticleKeyboardNavigation","useAttended","useAttention","useAttentionAttributes","useAttentionContext","useSelection","useSelectionActions","useViewState","useViewStateActions","useViewStateManager","useViewStateManagerOptional"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/components/AttentionGlyph/AttentionGlyph.tsx":{"bytesInOutput":2911},"src/useArticleKeyboardNavigation.ts":{"bytesInOutput":1979}},"bytes":6553},"dist/lib/node-esm/testing/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":1876},"dist/lib/node-esm/testing/index.mjs":{"imports":[{"path":"dist/lib/node-esm/chunk-DLBZMHST.mjs","kind":"import-statement"},{"path":"dist/lib/node-esm/chunk-HWN7KJDX.mjs","kind":"import-statement"},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"exports":["withAttention"],"entryPoint":"src/testing/index.ts","inputs":{"src/testing/decorators/withAttention.ts":{"bytesInOutput":610},"src/testing/index.ts":{"bytesInOutput":0}},"bytes":955},"dist/lib/node-esm/chunk-DLBZMHST.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15952},"dist/lib/node-esm/chunk-DLBZMHST.mjs":{"imports":[{"path":"dist/lib/node-esm/chunk-HWN7KJDX.mjs","kind":"import-statement"},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true}],"exports":["AttendableContainer","RootAttentionProvider","ViewStateProvider","useAttended","useAttention","useAttentionAttributes","useAttentionContext","useSelection","useSelectionActions","useViewState","useViewStateActions","useViewStateManager","useViewStateManagerOptional"],"inputs":{"src/components/AttentionProvider/AttentionProvider.tsx":{"bytesInOutput":3786},"src/components/ViewStateProvider/ViewStateProvider.tsx":{"bytesInOutput":3199}},"bytes":7712},"dist/lib/node-esm/types/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":93},"dist/lib/node-esm/types/index.mjs":{"imports":[{"path":"dist/lib/node-esm/chunk-HWN7KJDX.mjs","kind":"import-statement"}],"exports":["AttentionManager","LocalBackend","MemoryBackend","SelectionSchema","ViewStateManager","createDefaultBackends","defaultSelection","defineViewState","expandAttendableId","getAttendables","getLinkedVariant","getParentId","getSegmentId","getSelectionSet","isLinkedSegment","linkedSegment","resolveSelection","selectionAspect","toggleSelection"],"entryPoint":"src/types/index.ts","inputs":{"src/types/index.ts":{"bytesInOutput":0}},"bytes":898},"dist/lib/node-esm/chunk-HWN7KJDX.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":33378},"dist/lib/node-esm/chunk-HWN7KJDX.mjs":{"imports":[{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"@effect-atom/atom-react","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true},{"path":"effect/Match","kind":"import-statement","external":true},{"path":"effect/Schema","kind":"import-statement","external":true}],"exports":["AttentionManager","LocalBackend","MemoryBackend","SelectionSchema","ViewStateManager","createDefaultBackends","defaultSelection","defineViewState","expandAttendableId","getAttendables","getLinkedVariant","getParentId","getSegmentId","getSelectionSet","isLinkedSegment","linkedSegment","resolveSelection","selectionAspect","toggleSelection"],"inputs":{"src/attention.ts":{"bytesInOutput":5433},"src/view-state/view-state.ts":{"bytesInOutput":1053},"src/view-state/backends.ts":{"bytesInOutput":3752},"src/selection.ts":{"bytesInOutput":2312}},"bytes":13164}}}
@@ -1,31 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
- import {
3
- RootAttentionProvider,
4
- ViewStateProvider
5
- } from "../chunk-DLBZMHST.mjs";
6
- import {
7
- AttentionManager
8
- } from "../chunk-HWN7KJDX.mjs";
9
-
10
- // src/testing/decorators/withAttention.ts
11
- import { Registry, RegistryContext } from "@effect-atom/atom-react";
12
- import { createElement, useMemo } from "react";
13
- var withAttention = (initialAttendedId) => {
14
- return (Story) => {
15
- const registry = useMemo(() => Registry.make(), []);
16
- const attention = useMemo(() => initialAttendedId ? new AttentionManager(registry, [
17
- initialAttendedId
18
- ]) : void 0, [
19
- registry
20
- ]);
21
- return createElement(RegistryContext.Provider, {
22
- value: registry
23
- }, createElement(RootAttentionProvider, {
24
- attention
25
- }, createElement(ViewStateProvider, {}, createElement(Story))));
26
- };
27
- };
28
- export {
29
- withAttention
30
- };
31
- //# sourceMappingURL=index.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/testing/decorators/withAttention.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Registry, RegistryContext } from '@effect-atom/atom-react';\nimport { type Decorator } from '@storybook/react';\nimport { createElement, useMemo } from 'react';\n\nimport { AttentionManager } from '../../attention';\nimport { RootAttentionProvider, ViewStateProvider } from '../../components';\n\n/**\n * Storybook decorator that provides attention context.\n * @param initialAttendedId Optional ID to set as initially attended.\n */\nexport const withAttention = (initialAttendedId?: string): Decorator => {\n return (Story) => {\n const registry = useMemo(() => Registry.make(), []);\n const attention = useMemo(\n () => (initialAttendedId ? new AttentionManager(registry, [initialAttendedId]) : undefined),\n [registry],\n );\n\n return createElement(\n RegistryContext.Provider,\n { value: registry },\n createElement(RootAttentionProvider, { attention }, createElement(ViewStateProvider, {}, createElement(Story))),\n );\n };\n};\n"],
5
- "mappings": ";;;;;;;;;;AAIA,SAASA,UAAUC,uBAAuB;AAE1C,SAASC,eAAeC,eAAe;AAShC,IAAMC,gBAAgB,CAACC,sBAAAA;AAC5B,SAAO,CAACC,UAAAA;AACN,UAAMC,WAAWC,QAAQ,MAAMC,SAASC,KAAI,GAAI,CAAA,CAAE;AAClD,UAAMC,YAAYH,QAChB,MAAOH,oBAAoB,IAAIO,iBAAiBL,UAAU;MAACF;KAAkB,IAAIQ,QACjF;MAACN;KAAS;AAGZ,WAAOO,cACLC,gBAAgBC,UAChB;MAAEC,OAAOV;IAAS,GAClBO,cAAcI,uBAAuB;MAAEP;IAAU,GAAGG,cAAcK,mBAAmB,CAAC,GAAGL,cAAcR,KAAAA,CAAAA,CAAAA,CAAAA;EAE3G;AACF;",
6
- "names": ["Registry", "RegistryContext", "createElement", "useMemo", "withAttention", "initialAttendedId", "Story", "registry", "useMemo", "Registry", "make", "attention", "AttentionManager", "undefined", "createElement", "RegistryContext", "Provider", "value", "RootAttentionProvider", "ViewStateProvider"]
7
- }
@@ -1,44 +0,0 @@
1
- import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
- import {
3
- AttentionManager,
4
- LocalBackend,
5
- MemoryBackend,
6
- SelectionSchema,
7
- ViewStateManager,
8
- createDefaultBackends,
9
- defaultSelection,
10
- defineViewState,
11
- expandAttendableId,
12
- getAttendables,
13
- getLinkedVariant,
14
- getParentId,
15
- getSegmentId,
16
- getSelectionSet,
17
- isLinkedSegment,
18
- linkedSegment,
19
- resolveSelection,
20
- selectionAspect,
21
- toggleSelection
22
- } from "../chunk-HWN7KJDX.mjs";
23
- export {
24
- AttentionManager,
25
- LocalBackend,
26
- MemoryBackend,
27
- SelectionSchema,
28
- ViewStateManager,
29
- createDefaultBackends,
30
- defaultSelection,
31
- defineViewState,
32
- expandAttendableId,
33
- getAttendables,
34
- getLinkedVariant,
35
- getParentId,
36
- getSegmentId,
37
- getSelectionSet,
38
- isLinkedSegment,
39
- linkedSegment,
40
- resolveSelection,
41
- selectionAspect,
42
- toggleSelection
43
- };
44
- //# sourceMappingURL=index.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"attention.d.ts","sourceRoot":"","sources":["../../../src/attention.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,MAAM,SAAS,GAAG;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,qBAAa,gBAAgB;IAKzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+C;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;IAEvD,YACmB,SAAS,EAAE,QAAQ,CAAC,QAAQ,EAC7C,OAAO,GAAE,MAAM,EAAO,EAMvB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAEjC;IAED;;OAEG;IACH,UAAU,IAAI,SAAS,MAAM,EAAE,CAE9B;IAED;;OAEG;IACH,gBAAgB,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAKrE;IAED;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE,CAEf;IAED;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAGzB;IAED;;OAEG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI,CAMpE;IAED,OAAO,CAAC,QAAQ;IAuEhB,OAAO,CAAC,IAAI;CAQb;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,aAAc,MAAM,UAAU,OAAO,QAAO,MAAM,EAAE,KAAQ,MAAM,EAoB5F,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,MAAM,OAAO,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAQ5C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,gBAAiB,MAAM,KAAG,MAAM,EAG9D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,gBAAiB,MAAM,KAAG,OAGrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,KAAG,MAAsC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gBAAiB,MAAM,KAAG,MAGtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,gBAAiB,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAOtE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,gBAAiB,MAAM,KAAG,MAElD,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=attention.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attention.test.d.ts","sourceRoot":"","sources":["../../../src/attention.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAmB,MAAM,cAAc,CAAC;AAEtF,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;MAkBN,CAAC;AAEvB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,CAAC,CAAC;AAEnE,eAAO,MAAM,gBAAgB;;;;;;;;;;CAO5B,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,aAAa,IAAI,CAAC,SAAS,QAAQ,GACrE,MAAM,GAAG,SAAS,GAClB,CAAC,SAAS,OAAO,GACf,MAAM,EAAE,GACR,CAAC,SAAS,OAAO,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACxC,CAAC,SAAS,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,GAC9B,KAAK,CAAC;AAEhB,uFAAuF;AACvF,eAAO,MAAM,eAAe,EAAE,SAAS,CAAC,SAAS,CAK/C,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,aAAa,aAC3C,SAAS,GAAG,SAAS,QAC1B,CAAC,KACN,eAAe,CAAC,CAAC,CAUnB,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,eAAe,cAAe,SAAS,GAAG,SAAS,MAAM,MAAM,KAAG,SAG9E,CAAC;AAEF,oGAAoG;AACpG,eAAO,MAAM,eAAe,YAAa,gBAAgB,cAAc,MAAM,KAAG,GAAG,CAAC,MAAM,CAWzF,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=selection.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"selection.test.d.ts","sourceRoot":"","sources":["../../../src/selection.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useArticleKeyboardNavigation.d.ts","sourceRoot":"","sources":["../../../src/useArticleKeyboardNavigation.ts"],"names":[],"mappings":"AAUA;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,+BAIjB;IACD,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACf,KAAG,MAAM,GAAG,SAYZ,CAAC;AAEF,MAAM,MAAM,mCAAmC,CAAC,CAAC,IAAI;IACnD,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IACpB,qCAAqC;IACrC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,EAAE;IACzC,CAAC,CAAC,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAClF,CAAC,CAAC,EAAE,OAAO,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAAG;QAAE,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAqD7F,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useArticleKeyboardNavigation.test.d.ts","sourceRoot":"","sources":["../../../src/useArticleKeyboardNavigation.test.ts"],"names":[],"mappings":""}
@@ -1,24 +0,0 @@
1
- import { Atom, type Registry } from '@effect-atom/atom-react';
2
- import { type AspectDef, type BackendName, type ViewStateBackend } from './view-state';
3
- /** In-memory backend: state is ephemeral and scoped to the session (never persisted). */
4
- export declare class MemoryBackend implements ViewStateBackend {
5
- #private;
6
- atom<T>(aspect: AspectDef<T>, contextId: string): Atom.Writable<T>;
7
- contexts<T>(aspect: AspectDef<T>): string[];
8
- }
9
- export interface LocalBackendOptions {
10
- readonly registry: Registry.Registry;
11
- /** Injectable for tests; defaults to `window.localStorage`. */
12
- readonly storage?: Storage;
13
- }
14
- /** localStorage-backed backend: seeds atoms from storage, persists on set, syncs across tabs. */
15
- export declare class LocalBackend implements ViewStateBackend {
16
- #private;
17
- constructor({ registry, storage }: LocalBackendOptions);
18
- atom<T>(aspect: AspectDef<T>, contextId: string): Atom.Writable<T>;
19
- persist<T>(aspect: AspectDef<T>, contextId: string, value: T): void;
20
- contexts<T>(aspect: AspectDef<T>): string[];
21
- dispose(): void;
22
- }
23
- export declare const createDefaultBackends: (registry: Registry.Registry) => Record<BackendName, ViewStateBackend>;
24
- //# sourceMappingURL=backends.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"backends.d.ts","sourceRoot":"","sources":["../../../../src/view-state/backends.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG9D,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKvF,yFAAyF;AACzF,qBAAa,aAAc,YAAW,gBAAgB;;IAGpD,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CASjE;IAED,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAG1C;CACF;AAgBD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,iGAAiG;AACjG,qBAAa,YAAa,YAAW,gBAAgB;;IAUnD,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,mBAAmB,EAgBrD;IAED,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAajE;IAED,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAElE;IAED,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAe1C;IAED,OAAO,IAAI,IAAI,CAOd;CAcF;AAED,eAAO,MAAM,qBAAqB,aAAc,QAAQ,CAAC,QAAQ,KAAG,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAGtG,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"backends.test.d.ts","sourceRoot":"","sources":["../../../../src/view-state/backends.test.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- export * from './view-state';
2
- export * from './backends';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/view-state/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -1,54 +0,0 @@
1
- import { type Atom, type Registry } from '@effect-atom/atom-react';
2
- import type * as Schema from 'effect/Schema';
3
- /**
4
- * Persistence backend identifier. `personal` (ECHO/personal-space) is reserved for a future backend.
5
- */
6
- export type BackendName = 'memory' | 'local';
7
- /**
8
- * Declares a kind of per-context UI state. The value type `T` is inferred from the schema.
9
- */
10
- export interface AspectDef<T> {
11
- readonly key: string;
12
- readonly backend: BackendName;
13
- readonly schema: Schema.Schema<T, any>;
14
- readonly defaultValue: () => T;
15
- }
16
- /**
17
- * Identity helper that pins the value type from the schema while keeping the literal `key`/`backend`.
18
- */
19
- export declare const defineViewState: <T>(def: AspectDef<T>) => AspectDef<T>;
20
- /**
21
- * A backend produces a reactive, writable atom for each `(aspect, contextId)` pair. Backends may
22
- * hydrate asynchronously (an ECHO backend would), yielding `aspect.defaultValue()` until loaded;
23
- * the memory and local backends resolve synchronously.
24
- */
25
- export interface ViewStateBackend {
26
- /** Stable atom for the pair; created (and seeded) on first access, cached thereafter. */
27
- atom: <T>(aspect: AspectDef<T>, contextId: string) => Atom.Writable<T>;
28
- /** Persist a value after the atom is updated. No-op for in-memory backends. */
29
- persist?: <T>(aspect: AspectDef<T>, contextId: string, value: T) => void;
30
- /** Context ids that currently hold a value for the aspect. */
31
- contexts: <T>(aspect: AspectDef<T>) => string[];
32
- /** Release listeners/timers (used by tests; app-lifetime managers do not call this). */
33
- dispose?: () => void;
34
- }
35
- export interface ViewStateManagerOptions {
36
- readonly registry: Registry.Registry;
37
- readonly backends: Record<BackendName, ViewStateBackend>;
38
- }
39
- /**
40
- * Routes per-context UI state to the backend declared by each aspect. Reads/writes go through the
41
- * effect-atom registry so React hooks and graph atoms observe changes uniformly.
42
- */
43
- export declare class ViewStateManager {
44
- #private;
45
- constructor({ registry, backends }: ViewStateManagerOptions);
46
- /** Reactive atom for `(aspect, contextId)`; pass to `registry.get` inside derived atoms/hooks. */
47
- atom<T>(aspect: AspectDef<T>, contextId: string): Atom.Writable<T>;
48
- get<T>(aspect: AspectDef<T>, contextId: string): T;
49
- set<T>(aspect: AspectDef<T>, contextId: string, value: T): void;
50
- update<T>(aspect: AspectDef<T>, contextId: string, fn: (prev: T) => T): void;
51
- subscribe<T>(aspect: AspectDef<T>, contextId: string, cb: (value: T) => void): () => void;
52
- contexts<T>(aspect: AspectDef<T>): string[];
53
- }
54
- //# sourceMappingURL=view-state.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"view-state.d.ts","sourceRoot":"","sources":["../../../../src/view-state/view-state.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAG9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,KAAG,SAAS,CAAC,CAAC,CAAQ,CAAC;AAE3E;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACvE,+EAA+E;IAC/E,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IACzE,8DAA8D;IAC9D,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;IAChD,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;CAC1D;AAED;;;GAGG;AACH,qBAAa,gBAAgB;;IAI3B,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,uBAAuB,EAG1D;IAED,kGAAkG;IAClG,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAEjE;IAED,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,CAEjD;IAED,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAI9D;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAE3E;IAED,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAGxF;IAED,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAE1C;CACF"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=view-state.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"view-state.test.d.ts","sourceRoot":"","sources":["../../../../src/view-state/view-state.test.ts"],"names":[],"mappings":""}
@@ -1,67 +0,0 @@
1
- //
2
- // Copyright 2026 DXOS.org
3
- //
4
-
5
- import { Registry } from '@effect-atom/atom-react';
6
- import { describe, test } from 'vitest';
7
-
8
- import { getSelectionSet, resolveSelection, selectionAspect, toggleSelection } from './selection';
9
- import { ViewStateManager, createDefaultBackends } from './view-state';
10
-
11
- describe('selection helpers', () => {
12
- test('selectionAspect declares a memory-backed aspect', ({ expect }) => {
13
- expect(selectionAspect.key).toEqual('selection');
14
- expect(selectionAspect.backend).toEqual('memory');
15
- expect(selectionAspect.defaultValue()).toEqual({ mode: 'multi', ids: [] });
16
- });
17
-
18
- test('resolveSelection extracts the value for the requested mode', ({ expect }) => {
19
- expect(resolveSelection({ mode: 'single', id: 'x' }, 'single')).toEqual('x');
20
- expect(resolveSelection({ mode: 'multi', ids: ['a', 'b'] }, 'multi')).toEqual(['a', 'b']);
21
- expect(resolveSelection({ mode: 'range', from: 'a', to: 'b' }, 'range')).toEqual({ from: 'a', to: 'b' });
22
- expect(resolveSelection({ mode: 'multi-range', ranges: [{ from: 'a', to: 'b' }] }, 'multi-range')).toEqual([
23
- { from: 'a', to: 'b' },
24
- ]);
25
- });
26
-
27
- test('resolveSelection returns the requested-mode default on mismatch or undefined', ({ expect }) => {
28
- expect(resolveSelection(undefined, 'single')).toBeUndefined();
29
- expect(resolveSelection(undefined, 'multi')).toEqual([]);
30
- // Stored value is the default multi but a single reader asks — yields the single default.
31
- expect(resolveSelection({ mode: 'multi', ids: [] }, 'single')).toBeUndefined();
32
- expect(resolveSelection({ mode: 'range' }, 'range')).toBeUndefined();
33
- });
34
-
35
- test('toggleSelection adds/removes within a multi selection', ({ expect }) => {
36
- expect(toggleSelection({ mode: 'multi', ids: ['a'] }, 'b')).toEqual({ mode: 'multi', ids: ['a', 'b'] });
37
- expect(toggleSelection({ mode: 'multi', ids: ['a', 'b'] }, 'b')).toEqual({ mode: 'multi', ids: ['a'] });
38
- // Tolerate a non-multi current value by starting fresh.
39
- expect(toggleSelection({ mode: 'single', id: 'x' }, 'b')).toEqual({ mode: 'multi', ids: ['b'] });
40
- });
41
- });
42
-
43
- describe('getSelectionSet', () => {
44
- const makeManager = () => {
45
- const registry = Registry.make();
46
- return new ViewStateManager({ registry, backends: createDefaultBackends(registry) });
47
- };
48
-
49
- test('unions multi-selected ids across every context', ({ expect }) => {
50
- const manager = makeManager();
51
- manager.set(selectionAspect, 'ctx-a', { mode: 'multi', ids: ['a1', 'a2'] });
52
- manager.set(selectionAspect, 'ctx-b', { mode: 'multi', ids: ['a2', 'b1'] });
53
- // Single-mode contexts contribute nothing to the set.
54
- manager.set(selectionAspect, 'ctx-c', { mode: 'single', id: 'c1' });
55
- expect(getSelectionSet(manager)).toEqual(new Set(['a1', 'a2', 'b1']));
56
- });
57
-
58
- test('seeds the set with the optional explicit contextId', ({ expect }) => {
59
- const manager = makeManager();
60
- manager.set(selectionAspect, 'ctx-a', { mode: 'multi', ids: ['a1'] });
61
- expect(getSelectionSet(manager, 'explicit')).toEqual(new Set(['explicit', 'a1']));
62
- });
63
-
64
- test('returns an empty set when nothing is selected', ({ expect }) => {
65
- expect(getSelectionSet(makeManager())).toEqual(new Set());
66
- });
67
- });