@stesura/react-wordgard 0.0.0-stage → 0.2.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.
Files changed (111) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE.txt +21 -0
  3. package/README.md +912 -2
  4. package/THIRD_PARTY_LICENSES.txt +93 -0
  5. package/dist/ReactWordgard.d.ts +13 -0
  6. package/dist/ReactWordgard.js +94 -0
  7. package/dist/changes.d.ts +14 -0
  8. package/dist/changes.js +163 -0
  9. package/dist/components/ChildNodeViews.d.ts +8 -0
  10. package/dist/components/ChildNodeViews.js +36 -0
  11. package/dist/components/DecorationRoot.d.ts +13 -0
  12. package/dist/components/DecorationRoot.js +31 -0
  13. package/dist/components/ErrorBoundary.d.ts +18 -0
  14. package/dist/components/ErrorBoundary.js +14 -0
  15. package/dist/components/SeparatorHackView.d.ts +2 -0
  16. package/dist/components/SeparatorHackView.js +4 -0
  17. package/dist/components/ShapeView.d.ts +12 -0
  18. package/dist/components/ShapeView.js +24 -0
  19. package/dist/components/TextNodeView.d.ts +5 -0
  20. package/dist/components/TextNodeView.js +4 -0
  21. package/dist/components/TrailingHackView.d.ts +2 -0
  22. package/dist/components/TrailingHackView.js +4 -0
  23. package/dist/components/WidgetView.d.ts +10 -0
  24. package/dist/components/WidgetView.js +32 -0
  25. package/dist/components/WordgardDoc.d.ts +9 -0
  26. package/dist/components/WordgardDoc.js +36 -0
  27. package/dist/components/WordgardEditor.d.ts +15 -0
  28. package/dist/components/WordgardEditor.js +17 -0
  29. package/dist/components/WordgardScope.d.ts +14 -0
  30. package/dist/components/WordgardScope.js +14 -0
  31. package/dist/components/WrapperView.d.ts +12 -0
  32. package/dist/components/WrapperView.js +23 -0
  33. package/dist/components/marks/MarkView.d.ts +11 -0
  34. package/dist/components/marks/MarkView.js +10 -0
  35. package/dist/components/marks/ReactMarkView.d.ts +10 -0
  36. package/dist/components/marks/ReactMarkView.js +30 -0
  37. package/dist/components/nodes/DefaultNodeView.d.ts +16 -0
  38. package/dist/components/nodes/DefaultNodeView.js +112 -0
  39. package/dist/components/nodes/DocNodeView.d.ts +7 -0
  40. package/dist/components/nodes/DocNodeView.js +5 -0
  41. package/dist/composition.d.ts +23 -0
  42. package/dist/composition.js +95 -0
  43. package/dist/contexts/DecorationContext.d.ts +15 -0
  44. package/dist/contexts/DecorationContext.js +35 -0
  45. package/dist/contexts/DecorationRootContext.d.ts +6 -0
  46. package/dist/contexts/DecorationRootContext.js +4 -0
  47. package/dist/contexts/EditorContext.d.ts +27 -0
  48. package/dist/contexts/EditorContext.js +87 -0
  49. package/dist/contexts/RenderStoreContext.d.ts +15 -0
  50. package/dist/contexts/RenderStoreContext.js +41 -0
  51. package/dist/contexts/editorEvents.d.ts +12 -0
  52. package/dist/contexts/editorEvents.js +92 -0
  53. package/dist/decorations/DecoIterator.d.ts +43 -0
  54. package/dist/decorations/DecoIterator.js +462 -0
  55. package/dist/decorations/ReactMarkType.d.ts +41 -0
  56. package/dist/decorations/ReactMarkType.js +47 -0
  57. package/dist/decorations/ReactShapeType.d.ts +65 -0
  58. package/dist/decorations/ReactShapeType.js +202 -0
  59. package/dist/decorations/ReactWidgetType.d.ts +29 -0
  60. package/dist/decorations/ReactWidgetType.js +67 -0
  61. package/dist/decorations/ReactWrapperType.d.ts +31 -0
  62. package/dist/decorations/ReactWrapperType.js +41 -0
  63. package/dist/decorations/iterDeco.d.ts +82 -0
  64. package/dist/decorations/iterDeco.js +406 -0
  65. package/dist/helpers/attributes.d.ts +2 -0
  66. package/dist/helpers/attributes.js +11 -0
  67. package/dist/helpers/index.d.ts +2 -0
  68. package/dist/helpers/index.js +2 -0
  69. package/dist/helpers/props.d.ts +8 -0
  70. package/dist/helpers/props.js +248 -0
  71. package/dist/helpers/refs.d.ts +6 -0
  72. package/dist/helpers/refs.js +20 -0
  73. package/dist/hooks/useEditorEffect.d.ts +10 -0
  74. package/dist/hooks/useEditorEffect.js +28 -0
  75. package/dist/hooks/useEditorEventCallback.d.ts +8 -0
  76. package/dist/hooks/useEditorEventCallback.js +17 -0
  77. package/dist/hooks/useEditorEventListener.d.ts +10 -0
  78. package/dist/hooks/useEditorEventListener.js +26 -0
  79. package/dist/hooks/useEditorLayoutEffect.d.ts +15 -0
  80. package/dist/hooks/useEditorLayoutEffect.js +34 -0
  81. package/dist/hooks/useEditorState.d.ts +6 -0
  82. package/dist/hooks/useEditorState.js +12 -0
  83. package/dist/hooks/useEditorStateSelector.d.ts +7 -0
  84. package/dist/hooks/useEditorStateSelector.js +11 -0
  85. package/dist/hooks/useIgnoreMutation.d.ts +6 -0
  86. package/dist/hooks/useIgnoreMutation.js +19 -0
  87. package/dist/hooks/useIsNodeSelected.d.ts +2 -0
  88. package/dist/hooks/useIsNodeSelected.js +5 -0
  89. package/dist/hooks/useMergedDOMRefs.d.ts +6 -0
  90. package/dist/hooks/useMergedDOMRefs.js +18 -0
  91. package/dist/hooks/useNodePos.d.ts +4 -0
  92. package/dist/hooks/useNodePos.js +7 -0
  93. package/dist/hooks/useSelectNode.d.ts +6 -0
  94. package/dist/hooks/useSelectNode.js +25 -0
  95. package/dist/hooks/useStopEvent.d.ts +8 -0
  96. package/dist/hooks/useStopEvent.js +21 -0
  97. package/dist/hooks/useWordgard.d.ts +2 -0
  98. package/dist/hooks/useWordgard.js +3 -0
  99. package/dist/index.d.ts +21 -0
  100. package/dist/index.js +21 -0
  101. package/dist/reactKeys.d.ts +39 -0
  102. package/dist/reactKeys.js +188 -0
  103. package/dist/tile.d.ts +32 -0
  104. package/dist/tile.js +1319 -0
  105. package/dist/viewRoots.d.ts +2 -0
  106. package/dist/viewRoots.js +7 -0
  107. package/dist/wordgardInternals.d.ts +211 -0
  108. package/dist/wordgardInternals.js +82 -0
  109. package/package.json +119 -4
  110. package/skills/react-wordgard/SKILL.md +525 -0
  111. package/skills/react-wordgard/references/wordgard.md +189 -0
@@ -0,0 +1,188 @@
1
+ import { mapNodePos, unchangedEnds } from "./changes.js";
2
+ export const createNodeKey = () => Math.floor(Math.random() * 0xffffffffffff).toString(16);
3
+ // Gives keys to `plot` and everything in it that has none yet.
4
+ export const addFreshKeys = (keys, plot) => {
5
+ if (keys.has(plot))
6
+ return;
7
+ keys.set(plot, plot.content.map((child) => (child.isText ? "" : createNodeKey())));
8
+ for (const child of plot.content)
9
+ if (child.isPlot)
10
+ addFreshKeys(keys, child);
11
+ };
12
+ // Carries keys from `oldDoc` to `newDoc` through `changes` (the sections
13
+ // DocTile.update receives), as react-prosemirror maps them through a
14
+ // transaction's steps: a node whose start survives keeps its key, as does a
15
+ // node moved within its parent (the same object); others get fresh ones. Only
16
+ // plots that changed identity are visited. Returns, for each
17
+ // of those, the plot it replaces.
18
+ export const mapKeys = (keys, oldDoc, newDoc, changes) => {
19
+ const replaced = new WeakMap();
20
+ const mapChildren = (oldPlot, oldStart, newPlot, newStart) => {
21
+ if (keys.has(newPlot))
22
+ return;
23
+ replaced.set(newPlot, oldPlot);
24
+ const oldKeys = keys.get(oldPlot) ?? [];
25
+ // The children at both ends are the same nodes at the same places: they
26
+ // keep their keys, and only the middle is mapped.
27
+ const { head, tail } = unchangedEnds(changes, oldPlot, oldStart, newPlot);
28
+ const before = oldPlot.content;
29
+ const after = newPlot.content;
30
+ const oldTail = before.length - tail;
31
+ const newTail = after.length - tail;
32
+ // Only the middle is walked node by node: typing in one of 5,000 blocks
33
+ // mustn't allocate per block.
34
+ let headSize = 0;
35
+ for (let i = 0; i < head; i++)
36
+ headSize += before[i]?.length ?? 0;
37
+ const found = new Map();
38
+ const byNode = new Map();
39
+ const retagged = new Map();
40
+ for (let i = head, pos = oldStart + headSize; i < oldTail; i++) {
41
+ const node = before[i];
42
+ if (!node)
43
+ continue;
44
+ const key = oldKeys[i];
45
+ if (key && !node.isText) {
46
+ const old = { key, node, start: pos };
47
+ const mapped = mapNodePos(changes, pos, node.isLeaf);
48
+ if (mapped && !mapped.retagged)
49
+ found.set(mapped.pos, old);
50
+ else {
51
+ byNode.set(node, [...(byNode.get(node) ?? []), old]);
52
+ if (mapped)
53
+ retagged.set(mapped.pos, old);
54
+ }
55
+ }
56
+ pos += node.length;
57
+ }
58
+ // Each old key goes once: to its node where it's still there (moved),
59
+ // else to what a retag put in its place, if of its type.
60
+ const claimed = new Set();
61
+ const moved = [];
62
+ for (let i = head; i < newTail; i++) {
63
+ const child = after[i];
64
+ const old = child && !child.isText ? byNode.get(child)?.find((old) => !claimed.has(old)) : undefined;
65
+ if (old)
66
+ claimed.add(old);
67
+ moved.push(old);
68
+ }
69
+ const same = (child, key) => {
70
+ if (key !== undefined)
71
+ return key;
72
+ if (child.isPlot)
73
+ addFreshKeys(keys, child);
74
+ return child.isText ? "" : createNodeKey();
75
+ };
76
+ const newKeys = [];
77
+ for (let i = 0; i < head; i++) {
78
+ const child = after[i];
79
+ if (child)
80
+ newKeys.push(same(child, oldKeys[i]));
81
+ }
82
+ for (let i = head, pos = newStart + headSize; i < newTail; i++) {
83
+ const child = after[i];
84
+ if (!child)
85
+ continue;
86
+ const start = pos;
87
+ pos += child.length;
88
+ if (child.isText) {
89
+ newKeys.push("");
90
+ continue;
91
+ }
92
+ let kept = found.get(start) ?? moved[i - head];
93
+ const retag = kept ? undefined : retagged.get(start);
94
+ if (retag && !claimed.has(retag) && retag.node.type == child.type) {
95
+ claimed.add(retag);
96
+ kept = retag;
97
+ }
98
+ // A moved plot is the same object: its content keeps its keys.
99
+ if (child.isPlot && kept?.node.isPlot && kept.node != child)
100
+ mapChildren(kept.node, kept.start + 1, child, start + 1);
101
+ else if (child.isPlot)
102
+ addFreshKeys(keys, child);
103
+ newKeys.push(kept ? kept.key : createNodeKey());
104
+ }
105
+ for (let i = newTail; i < after.length; i++) {
106
+ const child = after[i];
107
+ if (child)
108
+ newKeys.push(same(child, oldKeys[i - newTail + oldTail]));
109
+ }
110
+ keys.set(newPlot, newKeys);
111
+ };
112
+ mapChildren(oldDoc, 0, newDoc, 0);
113
+ return replaced;
114
+ };
115
+ const typeIds = new WeakMap();
116
+ let lastTypeId = 0;
117
+ const typeId = (type) => {
118
+ let id = typeIds.get(type);
119
+ if (id === undefined)
120
+ typeIds.set(type, (id = ++lastTypeId));
121
+ return id;
122
+ };
123
+ // The keys of a list of sibling views (ChildNodeViews renders them, ReactDocTile
124
+ // records them), paired with them. A node's key comes from ReactKeys, through
125
+ // its view (iterDeco); other
126
+ // views are keyed after their previous sibling, so a text run keeps its text
127
+ // node while its start changes. Widgets don't count as that sibling: one
128
+ // coming or going leaves the next text node alone. React point widgets come
129
+ // with keys (iterDeco); other widgets are keyed after the sibling on their
130
+ // side (the next one for a positive side, as a `before` widget sticks to its
131
+ // node) and their type, so a React tag widget keeps its instance while its
132
+ // node does.
133
+ // A composition, and the wrappers around it, keep the keys of the nodes React
134
+ // committed there, and nothing else in their list may take those.
135
+ export const childViewKeys = (views) => {
136
+ const fixed = (view) => view.type == "composition" || view.type == "wrapper" ? view.key : undefined;
137
+ const taken = new Set();
138
+ for (const view of views) {
139
+ const key = fixed(view);
140
+ if (key !== undefined)
141
+ taken.add(key);
142
+ }
143
+ let previous = "";
144
+ let widgets = false;
145
+ // Widgets first get the key before them, and their own key below.
146
+ const keyed = views.map((view) => {
147
+ if (view.type == "widget") {
148
+ if (view.key !== undefined)
149
+ return { view, key: view.key };
150
+ widgets = true;
151
+ return { view, key: previous };
152
+ }
153
+ let key = fixed(view);
154
+ if (key === undefined) {
155
+ key =
156
+ view.type == "node"
157
+ ? view.key
158
+ : `${previous}>${view.type == "buffer" ? `buffer${view.side}` : view.type}`;
159
+ while (taken.has(key))
160
+ key += "+";
161
+ }
162
+ previous = key;
163
+ return { view, key };
164
+ });
165
+ if (!widgets)
166
+ return keyed;
167
+ let next = "";
168
+ const used = new Set();
169
+ for (let i = keyed.length - 1; i >= 0; i--) {
170
+ const entry = keyed[i];
171
+ if (!entry)
172
+ continue;
173
+ const { view } = entry;
174
+ if (view.type != "widget") {
175
+ next = entry.key;
176
+ continue;
177
+ }
178
+ if (view.key !== undefined)
179
+ continue;
180
+ const id = typeId(view.widget.type);
181
+ let key = view.side > 0 ? `${next}<w${id}` : `${entry.key}>w${id}`;
182
+ while (used.has(key))
183
+ key += "+";
184
+ used.add(key);
185
+ entry.key = key;
186
+ }
187
+ return keyed;
188
+ };
package/dist/tile.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { type ReactElement } from "react";
2
+ import { type Wordgard } from "wordgard/editor";
3
+ import type { GardState } from "wordgard/state";
4
+ import { type NodeView } from "./decorations/iterDeco.js";
5
+ import { type CompositionInfo, type DecoSet, DocTile, type Tile } from "./wordgardInternals.js";
6
+ export type DocPortal = {
7
+ readonly get: () => ReactElement;
8
+ readonly subscribe: (listener: () => void) => () => void;
9
+ readonly committed: (element: ReactElement) => void;
10
+ readonly claim: () => () => void;
11
+ readonly mount: () => void;
12
+ };
13
+ export declare const nodeViewOf: (tile: Tile) => NodeView | undefined;
14
+ export declare class RefusedUpdate extends Error {
15
+ }
16
+ export declare const docPortal: (dom: Element) => DocPortal;
17
+ export declare class ReactDocTile extends DocTile {
18
+ widgets: boolean;
19
+ static create: (state: GardState, dom: Element, wg: Wordgard) => ReactDocTile;
20
+ static host: (state: GardState, dom: Element, wg: Wordgard, mount: () => void) => ReactDocTile;
21
+ static mount: (dom: Element, wg: Wordgard, old: DocTile) => ReactDocTile;
22
+ private static render;
23
+ private static build;
24
+ updateRanges(state: GardState, decoSet: DecoSet, changes: readonly number[], wg: Wordgard, info?: CompositionInfo | null): ReactDocTile;
25
+ }
26
+ export declare const observeShapes: (wg: Wordgard, queue: (records: MutationRecord[]) => void) => {
27
+ takeRecords(): MutationRecord[];
28
+ discard(): void;
29
+ disconnect(): void;
30
+ observe(target: Node, options?: MutationObserverInit): void;
31
+ };
32
+ export declare const rebuildShapes: (wg: Wordgard) => void;