u2ui 1.5.3 → 1.5.7
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/el/ico/ico.js +5 -5
- package/el/rte/README.md +53 -13
- package/el/rte/manifest.json +19 -4
- package/el/rte/rte.css +31 -6
- package/el/rte/rte.js +174 -44
- package/el/rte0/README.md +37 -0
- package/el/rte0/manifest.json +33 -0
- package/el/rte0/rte0.css +9 -0
- package/el/rte0/rte0.js +56 -0
- package/el/system/styler.js +2 -0
- package/el/tooltip/tooltip.css +2 -2
- package/js/Placer/Placer.js +2 -1
- package/js/rte/AGENTS.md +142 -0
- package/js/rte/PLAN.md +487 -0
- package/js/rte/README.md +319 -25
- package/js/rte/blocks.js +7 -0
- package/js/rte/breaks.js +6 -0
- package/js/rte/classes.js +7 -0
- package/js/rte/docs/usage.md +845 -0
- package/js/rte/images.js +7 -0
- package/js/rte/link.js +8 -0
- package/js/rte/playground/README.md +95 -0
- package/js/rte/playground/hosts.html +553 -0
- package/js/rte/playground/index.html +835 -0
- package/js/rte/rte.js +56 -5
- package/js/rte/run.out +17 -0
- package/js/rte/source.js +12 -0
- package/js/rte/src/browser/README.md +40 -0
- package/js/rte/src/browser/interactive.js +17 -0
- package/js/rte/src/browser/range-rect.js +82 -0
- package/js/rte/src/client/README.md +385 -0
- package/js/rte/src/client/blocks.js +38 -0
- package/js/rte/src/client/breaks.js +212 -0
- package/js/rte/src/client/classes.js +48 -0
- package/js/rte/src/client/editor.js +472 -0
- package/js/rte/src/client/external-input.js +47 -0
- package/js/rte/src/client/history.js +13 -0
- package/js/rte/src/client/images.js +285 -0
- package/js/rte/src/client/link.js +567 -0
- package/js/rte/src/client/marks.js +25 -0
- package/js/rte/src/client/source.js +182 -0
- package/js/rte/src/client/structure.js +27 -0
- package/js/rte/src/client/tables.js +165 -0
- package/js/rte/src/client/unstyle.js +32 -0
- package/js/rte/src/command/README.md +520 -0
- package/js/rte/src/command/block-boundary.js +43 -0
- package/js/rte/src/command/block-style.js +120 -0
- package/js/rte/src/command/commands.js +159 -0
- package/js/rte/src/command/delete.js +119 -0
- package/js/rte/src/command/edit.js +78 -0
- package/js/rte/src/command/element.js +45 -0
- package/js/rte/src/command/enter.js +175 -0
- package/js/rte/src/command/fragment.js +76 -0
- package/js/rte/src/command/insert.js +52 -0
- package/js/rte/src/command/list.js +284 -0
- package/js/rte/src/command/mark.js +583 -0
- package/js/rte/src/command/pending-marks.js +216 -0
- package/js/rte/src/command/table.js +207 -0
- package/js/rte/src/command/unstyle.js +248 -0
- package/js/rte/src/config/README.md +96 -0
- package/js/rte/src/config/config.js +134 -0
- package/js/rte/src/core/README.md +63 -0
- package/js/rte/src/core/core.js +247 -0
- package/js/rte/src/history/README.md +83 -0
- package/js/rte/src/history/history.js +283 -0
- package/js/rte/src/input/README.md +173 -0
- package/js/rte/src/input/external-input.js +130 -0
- package/js/rte/src/input/input-pipeline.js +459 -0
- package/js/rte/src/mark/README.md +219 -0
- package/js/rte/src/mark/dom-adapter.js +100 -0
- package/js/rte/src/mark/mark.js +133 -0
- package/js/rte/src/mark/standard.js +76 -0
- package/js/rte/src/model/README.md +71 -0
- package/js/rte/src/model/content-model.js +213 -0
- package/js/rte/src/model/html/README.md +51 -0
- package/js/rte/src/model/html/html-model.js +90 -0
- package/js/rte/src/normalize/execute/README.md +33 -0
- package/js/rte/src/normalize/execute/repair-executor.js +129 -0
- package/js/rte/src/normalize/normalizer/README.md +48 -0
- package/js/rte/src/normalize/normalizer/normalizer.js +141 -0
- package/js/rte/src/normalize/repair/README.md +70 -0
- package/js/rte/src/normalize/repair/repair-planner.js +208 -0
- package/js/rte/src/sanitize/README.md +108 -0
- package/js/rte/src/sanitize/native.js +43 -0
- package/js/rte/src/sanitize/policy.js +206 -0
- package/js/rte/src/selection/README.md +39 -0
- package/js/rte/src/selection/map/README.md +53 -0
- package/js/rte/src/selection/map/point-map.js +307 -0
- package/js/rte/src/selection/ownership/README.md +32 -0
- package/js/rte/src/selection/ownership/ownership.js +42 -0
- package/js/rte/src/selection/point/README.md +34 -0
- package/js/rte/src/selection/point/point.js +83 -0
- package/js/rte/src/selection/range/README.md +38 -0
- package/js/rte/src/selection/range/edit-range.js +223 -0
- package/js/rte/src/selection/snapshot.js +64 -0
- package/js/rte/src/source/README.md +64 -0
- package/js/rte/src/source/source.js +193 -0
- package/js/rte/src/surface/README.md +36 -0
- package/js/rte/src/surface/content.js +16 -0
- package/js/rte/src/surface/surface.js +87 -0
- package/js/rte/src/transaction/README.md +35 -0
- package/js/rte/src/transaction/transaction.js +56 -0
- package/js/rte/src/ui/README.md +271 -0
- package/js/rte/src/ui/caret.js +17 -0
- package/js/rte/src/ui/chrome.js +214 -0
- package/js/rte/src/ui/handles.js +179 -0
- package/js/rte/src/ui/highlight.js +86 -0
- package/js/rte/src/ui/place.js +25 -0
- package/js/rte/src/ui/toolbar.js +258 -0
- package/js/rte/src/unstyle/README.md +103 -0
- package/js/rte/src/unstyle/unstyle.js +140 -0
- package/js/rte/tables.js +7 -0
- package/js/rte/unstyle.js +8 -0
- package/js/rte0/README.md +37 -0
- package/js/rte0/rte.js +7 -0
- package/js/{rte → rte0}/src/behavior.js +0 -1
- package/js/{rte → rte0}/src/events.js +0 -1
- package/js/{rte → rte0}/src/range.js +0 -2
- package/js/{rte → rte0}/src/ui.items.js +0 -2
- package/js/{rte → rte0}/src/ui.js +0 -1
- package/package.json +1 -1
- package/u2/Element.js +2 -2
- package/u2/plan-scoped-refactoring.md +133 -303
- package/u2/projects.json +18 -2
- package/u2/tools/update.repos.json.js +1 -1
- package/el/qrcode/package.json +0 -22
- /package/js/{rte → rte0}/old/NodeCleaner.js +0 -0
- /package/js/{rte → rte0}/old/Rte/Rte.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/Rte.ui.items.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/Rte.ui.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/crossbrowser.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/font/tinymce.svg +0 -0
- /package/js/{rte → rte0}/old/Rte/font/tinymce.woff +0 -0
- /package/js/{rte → rte0}/old/Rte/helpers.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/htmlparser.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/index.mjs +0 -0
- /package/js/{rte → rte0}/old/Rte/main.css +0 -0
- /package/js/{rte → rte0}/old/old.rte.js +0 -0
- /package/js/{rte → rte0}/old/range-selection.old.js +0 -0
- /package/js/{rte → rte0}/src/fixes.js +0 -0
- /package/js/{rte → rte0}/src/rte.js +0 -0
- /package/js/{rte → rte0}/src/ui/items/ai.js +0 -0
- /package/js/{rte → rte0}/src/ui/items/code.js +0 -0
- /package/js/{rte → rte0}/src/ui/items/undo.js +0 -0
- /package/js/{rte → rte0}/src/util/htmlparser.js +0 -0
- /package/js/{rte → rte0}/src/util/indentHtml.js +0 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {editingHost} from '../selection/ownership/ownership.js';
|
|
2
|
+
|
|
3
|
+
const STYLE = `
|
|
4
|
+
[data-u2-rte-break-layer] {
|
|
5
|
+
background: transparent;
|
|
6
|
+
border: 0;
|
|
7
|
+
inset: 0;
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
pointer-events: none;
|
|
11
|
+
position: fixed;
|
|
12
|
+
}
|
|
13
|
+
[data-u2-rte-break-marker] {
|
|
14
|
+
color: color-mix(in srgb, currentColor 48%, transparent);
|
|
15
|
+
font: 0.88em/1 system-ui, sans-serif;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
position: fixed;
|
|
18
|
+
transform: translate(0.36em, 0.15em);
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const FALSE = new Set(['', '0', 'false', 'none', 'off', 'hide', 'auto']);
|
|
24
|
+
|
|
25
|
+
// Optional view-only extension. Its state never enters editable HTML and its
|
|
26
|
+
// command deliberately runs outside an editing transaction.
|
|
27
|
+
export function breakMarks() {
|
|
28
|
+
const editors = new WeakMap();
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
name: 'breaks',
|
|
31
|
+
setup({editor, root}) {
|
|
32
|
+
const state = {
|
|
33
|
+
root,
|
|
34
|
+
document: root.nodeType === Node.DOCUMENT_NODE ? root : root.ownerDocument,
|
|
35
|
+
views: new Set(),
|
|
36
|
+
surfaces: new WeakMap(),
|
|
37
|
+
style: null,
|
|
38
|
+
layer: null,
|
|
39
|
+
controller: null,
|
|
40
|
+
observer: null,
|
|
41
|
+
frame: 0,
|
|
42
|
+
};
|
|
43
|
+
editors.set(editor, state);
|
|
44
|
+
let connected = true;
|
|
45
|
+
return {dispose() {
|
|
46
|
+
if (!connected) return;
|
|
47
|
+
release(state);
|
|
48
|
+
editors.delete(editor);
|
|
49
|
+
connected = false;
|
|
50
|
+
}};
|
|
51
|
+
},
|
|
52
|
+
commands({editor, surface}) {
|
|
53
|
+
const state = editors.get(editor);
|
|
54
|
+
if (!state) throw new DOMException('The line-break extension is not set up', 'InvalidStateError');
|
|
55
|
+
const view = {surface, visible: configured(surface.element), markers: []};
|
|
56
|
+
state.surfaces.set(surface, view);
|
|
57
|
+
return {showBreaks: {
|
|
58
|
+
transaction: false,
|
|
59
|
+
state: () => view.visible,
|
|
60
|
+
run() {
|
|
61
|
+
view.visible = !view.visible;
|
|
62
|
+
render(surface.element, view.visible);
|
|
63
|
+
sync(state, view);
|
|
64
|
+
return view.visible;
|
|
65
|
+
},
|
|
66
|
+
}};
|
|
67
|
+
},
|
|
68
|
+
attach({editor, surface}) {
|
|
69
|
+
const state = editors.get(editor);
|
|
70
|
+
const view = state?.surfaces.get(surface);
|
|
71
|
+
if (!state || !view) throw new DOMException('The line-break surface is not set up', 'InvalidStateError');
|
|
72
|
+
const original = surface.element.getAttribute('data-u2-rte-breaks');
|
|
73
|
+
const controller = new state.document.defaultView.AbortController();
|
|
74
|
+
const schedule = () => view.visible && scheduleRefresh(state);
|
|
75
|
+
surface.element.addEventListener('input', schedule, {signal: controller.signal});
|
|
76
|
+
surface.addEventListener('u2-rte-change', schedule, {signal: controller.signal});
|
|
77
|
+
surface.addEventListener('u2-rte-activate', schedule, {signal: controller.signal});
|
|
78
|
+
state.views.add(view);
|
|
79
|
+
render(surface.element, view.visible);
|
|
80
|
+
sync(state, view);
|
|
81
|
+
let connected = true;
|
|
82
|
+
return {dispose() {
|
|
83
|
+
if (!connected) return;
|
|
84
|
+
controller.abort();
|
|
85
|
+
original === null
|
|
86
|
+
? surface.element.removeAttribute('data-u2-rte-breaks')
|
|
87
|
+
: surface.element.setAttribute('data-u2-rte-breaks', original);
|
|
88
|
+
state.observer?.unobserve(surface.element);
|
|
89
|
+
removeMarkers(view);
|
|
90
|
+
state.views.delete(view);
|
|
91
|
+
state.surfaces.delete(surface);
|
|
92
|
+
if (![...state.views].some(item => item.visible)) release(state);
|
|
93
|
+
connected = false;
|
|
94
|
+
}};
|
|
95
|
+
},
|
|
96
|
+
toolbar: Object.freeze([Object.freeze({
|
|
97
|
+
name: 'breaks',
|
|
98
|
+
command: 'showBreaks',
|
|
99
|
+
label: 'Show line breaks',
|
|
100
|
+
text: '↵',
|
|
101
|
+
state: true,
|
|
102
|
+
})]),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const breaks = breakMarks();
|
|
107
|
+
|
|
108
|
+
function configured(element) {
|
|
109
|
+
const value = getComputedStyle(element).getPropertyValue('--u2-rte-show-breaks').trim().toLowerCase();
|
|
110
|
+
return !FALSE.has(value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function render(element, visible) {
|
|
114
|
+
element.toggleAttribute('data-u2-rte-breaks', visible);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function sync(state, view) {
|
|
118
|
+
if (!view.visible) {
|
|
119
|
+
state.observer?.unobserve(view.surface.element);
|
|
120
|
+
removeMarkers(view);
|
|
121
|
+
if (![...state.views].some(item => item.visible)) release(state);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
ensure(state);
|
|
125
|
+
state.observer?.observe(view.surface.element);
|
|
126
|
+
refreshView(state, view);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function ensure(state) {
|
|
130
|
+
if (state.layer) return;
|
|
131
|
+
const container = state.root.nodeType === Node.DOCUMENT_NODE
|
|
132
|
+
? state.document.body || state.document.documentElement
|
|
133
|
+
: state.root;
|
|
134
|
+
const styles = state.root.nodeType === Node.DOCUMENT_NODE
|
|
135
|
+
? state.document.head || state.document.documentElement
|
|
136
|
+
: state.root;
|
|
137
|
+
const style = state.document.createElement('style');
|
|
138
|
+
style.dataset.u2RteBreaksStyle = '';
|
|
139
|
+
style.textContent = STYLE;
|
|
140
|
+
const layer = state.document.createElement('div');
|
|
141
|
+
layer.dataset.u2RteBreakLayer = '';
|
|
142
|
+
layer.setAttribute('aria-hidden', 'true');
|
|
143
|
+
styles.append(style);
|
|
144
|
+
container.append(layer);
|
|
145
|
+
if (typeof layer.showPopover === 'function') {
|
|
146
|
+
layer.popover = 'manual';
|
|
147
|
+
layer.showPopover();
|
|
148
|
+
}
|
|
149
|
+
const controller = new state.document.defaultView.AbortController();
|
|
150
|
+
const schedule = () => scheduleRefresh(state);
|
|
151
|
+
state.root.addEventListener('scroll', schedule, {capture: true, signal: controller.signal});
|
|
152
|
+
state.document.defaultView.addEventListener('resize', schedule, {signal: controller.signal});
|
|
153
|
+
const Observer = state.document.defaultView.ResizeObserver;
|
|
154
|
+
state.observer = typeof Observer === 'function' ? new Observer(schedule) : null;
|
|
155
|
+
state.style = style;
|
|
156
|
+
state.layer = layer;
|
|
157
|
+
state.controller = controller;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function scheduleRefresh(state) {
|
|
161
|
+
if (state.frame || !state.layer) return;
|
|
162
|
+
state.frame = state.document.defaultView.requestAnimationFrame(() => {
|
|
163
|
+
state.frame = 0;
|
|
164
|
+
for (const view of state.views) if (view.visible) refreshView(state, view);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function refreshView(state, view) {
|
|
169
|
+
const breaks = [...view.surface.element.querySelectorAll('br')]
|
|
170
|
+
.filter(element => editingHost(element) === view.surface.element);
|
|
171
|
+
while (view.markers.length < breaks.length) {
|
|
172
|
+
const marker = state.document.createElement('span');
|
|
173
|
+
marker.dataset.u2RteBreakMarker = '';
|
|
174
|
+
marker.textContent = '↵';
|
|
175
|
+
state.layer.append(marker);
|
|
176
|
+
view.markers.push(marker);
|
|
177
|
+
}
|
|
178
|
+
while (view.markers.length > breaks.length) view.markers.pop().remove();
|
|
179
|
+
for (let index = 0; index < breaks.length; index++) {
|
|
180
|
+
const marker = view.markers[index];
|
|
181
|
+
const rect = breakRect(breaks[index]);
|
|
182
|
+
marker.hidden = !rect;
|
|
183
|
+
if (!rect) continue;
|
|
184
|
+
marker.style.left = `${rect.left}px`;
|
|
185
|
+
marker.style.top = `${rect.top}px`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function breakRect(element) {
|
|
190
|
+
const range = element.ownerDocument.createRange();
|
|
191
|
+
range.selectNode(element);
|
|
192
|
+
const rect = range.getClientRects()[0] || range.getBoundingClientRect();
|
|
193
|
+
return rect && (rect.width || rect.height || rect.x || rect.y) ? rect : null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function removeMarkers(view) {
|
|
197
|
+
for (const marker of view.markers) marker.remove();
|
|
198
|
+
view.markers = [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function release(state) {
|
|
202
|
+
if (state.frame) state.document.defaultView.cancelAnimationFrame(state.frame);
|
|
203
|
+
state.controller?.abort();
|
|
204
|
+
state.observer?.disconnect();
|
|
205
|
+
state.layer?.remove();
|
|
206
|
+
state.style?.remove();
|
|
207
|
+
state.frame = 0;
|
|
208
|
+
state.controller = null;
|
|
209
|
+
state.observer = null;
|
|
210
|
+
state.layer = null;
|
|
211
|
+
state.style = null;
|
|
212
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {classMark} from '../mark/standard.js';
|
|
2
|
+
import {valueMark} from '../command/mark.js';
|
|
3
|
+
|
|
4
|
+
// Optional content-class control. The choices come from the host's
|
|
5
|
+
// `--u2-rte-classes`, so one declaration decides what the control offers, what
|
|
6
|
+
// the sanitizer keeps, and what presentation cleanup leaves alone.
|
|
7
|
+
//
|
|
8
|
+
// The group is one mark type and therefore mutually exclusive. An application
|
|
9
|
+
// that needs independent axes registers a second module with its own adapter.
|
|
10
|
+
export function classStyles({label = 'Style', name = 'style', command = 'classStyle'} = {}) {
|
|
11
|
+
for (const value of [label, name, command]) {
|
|
12
|
+
if (typeof value !== 'string' || !value.trim()) throw new TypeError('A class control needs names');
|
|
13
|
+
}
|
|
14
|
+
const adapters = new Map();
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
name: 'classes',
|
|
17
|
+
commands: ({surface}) => ({[command]: styleCommand(adapters, surface)}),
|
|
18
|
+
toolbar: Object.freeze([Object.freeze({
|
|
19
|
+
type: 'select',
|
|
20
|
+
name,
|
|
21
|
+
command,
|
|
22
|
+
label,
|
|
23
|
+
options: surface => surface.config.classes.map(value => ({value, label: value})),
|
|
24
|
+
})]),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const classes = classStyles();
|
|
29
|
+
|
|
30
|
+
// One adapter per configured group, so the same host keeps one mark identity
|
|
31
|
+
// across refreshes and two hosts with the same classes share it.
|
|
32
|
+
function styleCommand(adapters, surface) {
|
|
33
|
+
const resolve = () => {
|
|
34
|
+
const names = surface.config.classes;
|
|
35
|
+
if (!names.length) return null;
|
|
36
|
+
const key = names.join(' ');
|
|
37
|
+
if (!adapters.has(key)) adapters.set(key, valueMark(classMark(names)));
|
|
38
|
+
return adapters.get(key);
|
|
39
|
+
};
|
|
40
|
+
// The group is closed, so a value outside it is simply unavailable rather
|
|
41
|
+
// than an error the adapter has to raise.
|
|
42
|
+
const known = edit => edit.value == null || surface.config.classes.includes(edit.value);
|
|
43
|
+
return {
|
|
44
|
+
enabled: edit => known(edit) && !!resolve()?.enabled(edit),
|
|
45
|
+
state: edit => resolve()?.state(edit) ?? null,
|
|
46
|
+
run: edit => known(edit) ? resolve()?.run(edit) : undefined,
|
|
47
|
+
};
|
|
48
|
+
}
|