@openleaf-editor/ui 0.1.0-beta.1 → 0.1.0-beta.3

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 (82) hide show
  1. package/README.md +85 -0
  2. package/dist/block-type.d.ts +5 -0
  3. package/dist/block-type.d.ts.map +1 -0
  4. package/dist/block-type.js +133 -0
  5. package/dist/block-type.js.map +1 -0
  6. package/dist/content-css.d.ts +31 -0
  7. package/dist/content-css.d.ts.map +1 -0
  8. package/dist/content-css.js +272 -0
  9. package/dist/content-css.js.map +1 -0
  10. package/dist/css.d.ts +23 -0
  11. package/dist/css.d.ts.map +1 -0
  12. package/dist/css.js +813 -0
  13. package/dist/css.js.map +1 -0
  14. package/dist/dialog.d.ts +158 -18
  15. package/dist/dialog.d.ts.map +1 -1
  16. package/dist/dialog.js +605 -130
  17. package/dist/dialog.js.map +1 -1
  18. package/dist/floating.d.ts +29 -0
  19. package/dist/floating.d.ts.map +1 -0
  20. package/dist/floating.js +130 -0
  21. package/dist/floating.js.map +1 -0
  22. package/dist/help.d.ts +9 -0
  23. package/dist/help.d.ts.map +1 -0
  24. package/dist/help.js +97 -0
  25. package/dist/help.js.map +1 -0
  26. package/dist/i18n.d.ts +39 -0
  27. package/dist/i18n.d.ts.map +1 -0
  28. package/dist/i18n.js +114 -0
  29. package/dist/i18n.js.map +1 -0
  30. package/dist/icons.d.ts +7 -1
  31. package/dist/icons.d.ts.map +1 -1
  32. package/dist/icons.js +10 -2
  33. package/dist/icons.js.map +1 -1
  34. package/dist/index.d.ts +15 -7
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +14 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/items.d.ts +2 -1
  39. package/dist/items.d.ts.map +1 -1
  40. package/dist/items.js +263 -17
  41. package/dist/items.js.map +1 -1
  42. package/dist/live.d.ts +42 -0
  43. package/dist/live.d.ts.map +1 -0
  44. package/dist/live.js +83 -0
  45. package/dist/live.js.map +1 -0
  46. package/dist/menu.d.ts +85 -0
  47. package/dist/menu.d.ts.map +1 -0
  48. package/dist/menu.js +500 -0
  49. package/dist/menu.js.map +1 -0
  50. package/dist/openleaf.css +325 -7
  51. package/dist/overflow.d.ts +44 -0
  52. package/dist/overflow.d.ts.map +1 -0
  53. package/dist/overflow.js +323 -0
  54. package/dist/overflow.js.map +1 -0
  55. package/dist/pickers.d.ts +43 -0
  56. package/dist/pickers.d.ts.map +1 -0
  57. package/dist/pickers.js +52 -0
  58. package/dist/pickers.js.map +1 -0
  59. package/dist/registry.d.ts +72 -18
  60. package/dist/registry.d.ts.map +1 -1
  61. package/dist/registry.js +7 -6
  62. package/dist/registry.js.map +1 -1
  63. package/dist/skins.d.ts.map +1 -1
  64. package/dist/skins.js +48 -14
  65. package/dist/skins.js.map +1 -1
  66. package/dist/styles.d.ts +61 -1
  67. package/dist/styles.d.ts.map +1 -1
  68. package/dist/styles.js +77 -421
  69. package/dist/styles.js.map +1 -1
  70. package/dist/testing.d.ts +3 -0
  71. package/dist/testing.d.ts.map +1 -0
  72. package/dist/testing.js +3 -0
  73. package/dist/testing.js.map +1 -0
  74. package/dist/toolbar.d.ts +91 -12
  75. package/dist/toolbar.d.ts.map +1 -1
  76. package/dist/toolbar.js +459 -127
  77. package/dist/toolbar.js.map +1 -1
  78. package/dist/upload.d.ts +11 -0
  79. package/dist/upload.d.ts.map +1 -1
  80. package/dist/upload.js +15 -1
  81. package/dist/upload.js.map +1 -1
  82. package/package.json +17 -3
package/dist/styles.js CHANGED
@@ -26,6 +26,9 @@
26
26
  * 1. A constructable `CSSStyleSheet` added to `document.adoptedStyleSheets`.
27
27
  * CSP gates resources *parsed as style*; a CSSOM object attached this way
28
28
  * never passes through that gate, by design rather than by loophole.
29
+ * Constructed through the TARGET document's window, never this module's:
30
+ * a constructed sheet belongs to the document it was built for, and
31
+ * adopting it elsewhere throws NotAllowedError.
29
32
  * 2. The integrator links `@openleaf-editor/ui/openleaf.css` themselves and calls
30
33
  * `markStylesExternal()`.
31
34
  *
@@ -34,426 +37,66 @@
34
37
  * would need it, and it fails *silently* -- an unstyled toolbar with no signal
35
38
  * an integrator can act on. A console warning naming the stylesheet is more
36
39
  * useful than a mechanism that quietly does nothing.
37
- */
38
- /**
39
- * The dark palette, as fallbacks for the same public tokens the light one uses.
40
40
  *
41
- * Written once and applied from three selectors below rather than pasted three
42
- * times, because the failure mode of a pasted palette is one selector quietly
43
- * missing a line -- and the line it is missing is a colour nobody looks at until
44
- * it is the wrong one.
41
+ * ## Why the accessibility reasoning lives out here
42
+ *
43
+ * The bundles are minified, which strips these comments but NOT the contents of
44
+ * the template literal below -- a CSS comment is string data and ships to every
45
+ * user. So the long-form arguments sit here and the rules carry a short marker
46
+ * pointing back. Ratios below are computed with the WCAG 2.x sRGB formula
47
+ * against all four built-in palettes: default light, midnight, paper, contrast.
48
+ *
49
+ * ### Two border tokens
50
+ *
51
+ * `--ol-border` is 1.43:1 against the default surface (1.92 midnight, 1.47
52
+ * paper). That is right for a table rule or a group divider and wrong for the
53
+ * only thing delimiting a `<select>`, where WCAG 1.4.11 wants 3:1 for the parts
54
+ * of a control that identify it. Rather than darken every hairline in the
55
+ * editor, the two jobs are split: `--ol-border-strong` takes the control
56
+ * boundaries -- toolbar, menubar, content frame, source view, select, menu --
57
+ * and the decorative one stays quiet. The fallback clears 3:1 on a white
58
+ * surface (4.55:1) and a dark one (4.16:1) alike, so a third-party skin that
59
+ * sets only `--openleaf-color-border` still gets a legible control boundary.
60
+ *
61
+ * ### Menu focus
62
+ *
63
+ * `.ol-menu-item` had `outline: none` and a background swap standing in for the
64
+ * ring. That swap is 1.13:1 on the default palette, 1.24 midnight, 1.13 paper,
65
+ * and 1.23 in the skin named "High contrast"; 1.4.11 requires 3:1. A menu item
66
+ * is reachable only by ArrowDown, so that swap was the author's sole position
67
+ * marker. The ring is back and the swap stays as hover affordance. It is inset
68
+ * two pixels rather than outset so it is drawn inside the item rather than over
69
+ * the menu's padding and its neighbour, and it lands at 4.59:1 against the
70
+ * item's own hovered background (7.82 midnight, 4.88 paper, 9.73 contrast).
71
+ *
72
+ * ### Disabled is not invisible
73
+ *
74
+ * `opacity: 0.4` put a 16px glyph at 2.41:1 (2.34 paper, 2.85 contrast), which
75
+ * is not a dimmed icon but an absent one -- and `undo`, `redo` and `link` are
76
+ * disabled at rest. 0.55 stays plainly quieter than an enabled control while
77
+ * clearing 3:1 as non-text content. A disabled control is exempt from 1.4.3
78
+ * either way; being exempt from a rule is not a reason to be unreadable.
79
+ *
80
+ * ### Cell selection
81
+ *
82
+ * The `.selectedCell` tint alone measured 1.06-1.18:1 depending on the palette,
83
+ * and a selection you cannot see is one you will destroy by typing. The ring
84
+ * carries the information now and the tint is the nicety. The ring goes on the
85
+ * cell rather than on the `::after` overlay because the overlay's own `opacity`
86
+ * would fade it to the same invisibility -- a 40% accent lands near 2:1. Per
87
+ * CSS 2.1 Appendix E an element's outline paints in step 10, after all its
88
+ * descendants, so the tint does not cover it.
89
+ *
90
+ * ### Forced colours
91
+ *
92
+ * The block at the end of the sheet previously stopped at `.ol-btn`. Everything
93
+ * added to it depends on a palette this mode discards outright, so each of them
94
+ * had no indicator at all: which menu is open, which menu item has focus, which
95
+ * cells are selected, and every one of the visual aids -- whose entire output
96
+ * is a colour.
45
97
  */
46
- const DARK_TOKENS = `
47
- --ol-text: var(--openleaf-color-text, #e6edf3);
48
- --ol-text-muted: var(--openleaf-color-text-muted, #9198a1);
49
- --ol-surface: var(--openleaf-color-surface, #0d1117);
50
- --ol-surface-hover: var(--openleaf-color-surface-hover, #21262d);
51
- --ol-surface-active: var(--openleaf-color-surface-active, #1f3a5f);
52
- --ol-border: var(--openleaf-color-border, #3d444d);
53
- --ol-accent: var(--openleaf-color-accent, #79c0ff);
54
- --ol-focus: var(--openleaf-color-focus, #79c0ff);
55
- `;
56
- export const CSS = `
57
- .ol-editor {
58
- /* Two families, named before either is public API. A singular
59
- \`--openleaf-font\` implies "the" font, and source view already has a
60
- monospace surface -- bolting a mono token on beside a singular name later
61
- is the awkward outcome worth avoiding now. \`--openleaf-font\` is still
62
- honoured as a fallback. */
63
- --ol-font: var(--openleaf-font-ui, var(--openleaf-font, system-ui, -apple-system, "Segoe UI", sans-serif));
64
- --ol-font-mono: var(--openleaf-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
65
- --ol-font-size: var(--openleaf-font-size, 14px);
66
- --ol-radius: var(--openleaf-radius, 4px);
67
- --ol-text: var(--openleaf-color-text, #1f2328);
68
- --ol-text-muted: var(--openleaf-color-text-muted, #59636e);
69
- --ol-surface: var(--openleaf-color-surface, #ffffff);
70
- --ol-surface-hover: var(--openleaf-color-surface-hover, #f0f1f3);
71
- --ol-surface-active: var(--openleaf-color-surface-active, #dbe9ff);
72
- --ol-border: var(--openleaf-color-border, #d1d9e0);
73
- --ol-accent: var(--openleaf-color-accent, #0550ae);
74
- --ol-focus: var(--openleaf-color-focus, #0969da);
75
- --ol-button-size: var(--openleaf-button-size, 32px);
76
- --ol-icon-size: var(--openleaf-icon-size, 16px);
77
- --ol-gap: var(--openleaf-gap, 2px);
78
- /* A 2009 WordPress admin bar sits at z-index 99999 and Drupal's toolbar plays
79
- similar games. Without a sanctioned escape hatch integrators fix a toolbar
80
- rendered behind a sticky host header with !important -- the exact thing the
81
- token API exists to prevent. */
82
- --ol-z: var(--openleaf-z-index, 1);
83
- /* Thickness and offset, not just colour: "you can change the colour but not
84
- the thickness" is a poor answer to a Section 508 team citing WCAG 2.2
85
- Focus Appearance. */
86
- --ol-focus-width: var(--openleaf-focus-width, 2px);
87
- --ol-focus-offset: var(--openleaf-focus-offset, 1px);
88
-
89
- display: block;
90
- color: var(--ol-text);
91
- }
92
-
93
- /* Three ways into the dark palette, and one way out of it.
94
- \`data-ol-scheme\` is set from the applied skin's declared scheme, and a skin
95
- that declares one outranks both the attribute and the system -- it has to,
96
- because its tokens have already replaced the palette outright. Without the
97
- \`:not()\` guards a light skin on a dark machine would take these fallbacks for
98
- every token it did not itself set, which is a light surface carrying dark-mode
99
- muted text. */
100
- @media (prefers-color-scheme: dark) {
101
- .ol-editor:not([data-ol-theme="light"]):not([data-ol-scheme]) {${DARK_TOKENS}}
102
- }
103
-
104
- .ol-editor[data-ol-theme="dark"]:not([data-ol-scheme]) {${DARK_TOKENS}}
105
-
106
- .ol-editor[data-ol-scheme="dark"] {${DARK_TOKENS}}
107
-
108
- /* Native widget chrome -- the popup a \`select\` opens, scrollbars, the caret,
109
- form control backgrounds -- is painted by the browser from \`color-scheme\`,
110
- not from any property we can hand an integrator. Left alone it follows the
111
- page, which is right while the editor's own palette also follows the page and
112
- wrong the moment either attribute pins the editor to one world. So it is set
113
- exactly when the editor stops following along, and inherited from the host
114
- otherwise. */
115
- .ol-editor[data-ol-theme="light"] { color-scheme: light; }
116
- .ol-editor[data-ol-theme="dark"] { color-scheme: dark; }
117
- .ol-editor[data-ol-scheme="light"] { color-scheme: light; }
118
- .ol-editor[data-ol-scheme="dark"] { color-scheme: dark; }
119
-
120
- /* Wrapping, not scrolling and not an overflow menu. Both of those hide
121
- controls -- one off-screen, one behind a click -- and a formatting control
122
- the author cannot see is a control they do not have. */
123
- .ol-editor .ol-toolbar {
124
- display: flex;
125
- flex-wrap: wrap;
126
- align-items: center;
127
- gap: var(--ol-gap);
128
- box-sizing: border-box;
129
- margin: 0;
130
- padding: 4px;
131
- border: 1px solid var(--ol-border);
132
- border-bottom: 0;
133
- border-radius: var(--ol-radius) var(--ol-radius) 0 0;
134
- background: var(--ol-surface);
135
- font: inherit;
136
- position: relative;
137
- z-index: var(--ol-z);
138
- }
139
-
140
- .ol-editor .ol-group {
141
- display: flex;
142
- flex-wrap: wrap;
143
- align-items: center;
144
- gap: var(--ol-gap);
145
- }
146
-
147
- /* The divider is a BORDER on the group, not a standalone flex item.
148
- As its own element it could wrap onto the trailing edge of a row with nothing
149
- after it -- a stranded line floating at the end of a row. Wrapping begins
150
- around 690-740px, well inside ordinary desktop widths (a CMS sidebar, a
151
- half-width split pane), so this was not a 360px-only edge case.
152
- border-inline-start rather than border-left, so it flips under RTL. */
153
- .ol-editor .ol-group + .ol-group {
154
- border-inline-start: 1px solid var(--ol-border);
155
- padding-inline-start: 5px;
156
- margin-inline-start: 1px;
157
- }
158
-
159
- /* Every property a host reset or \`button {}\` rule is likely to touch is set
160
- here explicitly. Specificity is (0,2,0) via the descendant selector, which
161
- beats a bare element or single-class host rule without resorting to
162
- !important. */
163
- .ol-editor .ol-btn {
164
- box-sizing: border-box;
165
- display: inline-flex;
166
- align-items: center;
167
- justify-content: center;
168
- flex: 0 0 auto;
169
- width: var(--ol-button-size);
170
- height: var(--ol-button-size);
171
- min-width: var(--ol-button-size);
172
- min-height: var(--ol-button-size);
173
- max-width: none;
174
- padding: 0;
175
- margin: 0;
176
- border: 1px solid transparent;
177
- border-radius: var(--ol-radius);
178
- background: transparent;
179
- color: var(--ol-text);
180
- font: inherit;
181
- font-family: var(--ol-font);
182
- font-size: var(--ol-font-size);
183
- font-weight: 400;
184
- line-height: 1;
185
- letter-spacing: normal;
186
- text-transform: none;
187
- text-align: center;
188
- text-decoration: none;
189
- text-shadow: none;
190
- box-shadow: none;
191
- opacity: 1;
192
- cursor: pointer;
193
- appearance: none;
194
- -webkit-appearance: none;
195
- outline-offset: var(--ol-focus-offset);
196
- -webkit-tap-highlight-color: transparent;
197
- transition: background-color 120ms ease, border-color 120ms ease;
198
- }
199
-
200
- .ol-editor .ol-btn:hover {
201
- background: var(--ol-surface-hover);
202
- }
203
-
204
- /* :focus-visible only, so a mouse click does not leave a ring behind, but the
205
- ring is never removed for keyboard users. */
206
- .ol-editor .ol-btn:focus-visible {
207
- outline: var(--ol-focus-width) solid var(--ol-focus);
208
- outline-offset: var(--ol-focus-offset);
209
- }
210
-
211
- /* Pressed state is distinguished from hover by THREE signals, not just colour:
212
- a filled background, a visible border, and an inset shadow that reads as
213
- physically depressed. Colour alone would fail for a colour-blind author and
214
- would be invisible in forced-colours mode. */
215
- .ol-editor .ol-btn[aria-pressed="true"] {
216
- background: var(--ol-surface-active);
217
- border-color: var(--ol-accent);
218
- color: var(--ol-accent);
219
- box-shadow: inset 0 1px 2px rgb(0 0 0 / 12%);
220
- }
221
-
222
- .ol-editor .ol-btn[aria-pressed="true"]:hover {
223
- background: var(--ol-surface-active);
224
- border-color: var(--ol-accent);
225
- }
226
-
227
- /* aria-disabled rather than the disabled attribute: a disabled button is
228
- removed from the roving tabindex and cannot be reached or announced, so an
229
- author using a screen reader cannot discover that the control exists. */
230
- .ol-editor .ol-btn[aria-disabled="true"] {
231
- opacity: 0.4;
232
- cursor: default;
233
- }
234
-
235
- .ol-editor .ol-btn[aria-disabled="true"]:hover {
236
- background: transparent;
237
- }
238
-
239
- .ol-editor .ol-icon {
240
- width: var(--ol-icon-size);
241
- height: var(--ol-icon-size);
242
- display: block;
243
- pointer-events: none;
244
- flex: 0 0 auto;
245
- }
246
-
247
- /* Block-type select. Sized and coloured to sit level with the icon buttons so
248
- it does not read as bolted on, but it stays a native <select> -- a custom
249
- listbox is a large amount of ARIA that would then owe real screen reader
250
- testing to be worth anything. */
251
- .ol-editor .ol-select {
252
- box-sizing: border-box;
253
- height: var(--ol-button-size);
254
- max-width: 11em;
255
- padding: 0 22px 0 6px;
256
- margin: 0;
257
- border: 1px solid var(--ol-border);
258
- border-radius: var(--ol-radius);
259
- background-color: transparent;
260
- background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
261
- linear-gradient(135deg, currentColor 50%, transparent 50%);
262
- background-position: right 10px center, right 6px center;
263
- background-size: 4px 4px, 4px 4px;
264
- background-repeat: no-repeat;
265
- color: var(--ol-text);
266
- font-family: var(--ol-font);
267
- font-size: var(--ol-font-size);
268
- font-weight: 400;
269
- line-height: 1;
270
- text-transform: none;
271
- letter-spacing: normal;
272
- box-shadow: none;
273
- cursor: pointer;
274
- appearance: none;
275
- -webkit-appearance: none;
276
- }
277
-
278
- .ol-editor .ol-select:hover {
279
- background-color: var(--ol-surface-hover);
280
- }
281
-
282
- .ol-editor .ol-select:focus-visible {
283
- outline: var(--ol-focus-width) solid var(--ol-focus);
284
- outline-offset: var(--ol-focus-offset);
285
- }
286
-
287
- /* The option list is painted by the OS, which does not inherit our tokens, so
288
- give it explicit colours or dark mode shows black text on black. */
289
- .ol-editor .ol-select option {
290
- background: var(--ol-surface);
291
- color: var(--ol-text);
292
- }
293
-
294
- .ol-editor .ol-content {
295
- box-sizing: border-box;
296
- border: 1px solid var(--ol-border);
297
- border-radius: 0 0 var(--ol-radius) var(--ol-radius);
298
- background: var(--ol-surface);
299
- }
300
-
301
- /* Deliberately minimal: the content area inherits the host's typography, which
302
- is the entire reason this project does not use Shadow DOM. Only padding and
303
- the focus ring are ours. */
304
- .ol-editor .ol-content .ProseMirror {
305
- padding: 12px;
306
- min-height: 8rem;
307
- outline: none;
308
- }
309
-
310
- .ol-editor .ol-content:focus-within {
311
- outline: 2px solid var(--ol-focus);
312
- outline-offset: -1px;
313
- }
314
-
315
- /* Tables.
316
- These styles live in core, not in the opt-in table plugin, because table
317
- NODES live in core: every deployment reads and renders tables even where
318
- editing them is switched off. Unstyled tables would render as runs of
319
- undelimited text. */
320
- .ol-editor .ol-content .ProseMirror table {
321
- border-collapse: collapse;
322
- table-layout: fixed;
323
- width: 100%;
324
- margin: 0 0 1em;
325
- overflow: hidden;
326
- }
327
-
328
- .ol-editor .ol-content .ProseMirror td,
329
- .ol-editor .ol-content .ProseMirror th {
330
- border: 1px solid var(--ol-border);
331
- padding: 6px 8px;
332
- vertical-align: top;
333
- /* A zero-width cell cannot be clicked into, so it cannot be repaired. */
334
- min-width: 2em;
335
- position: relative;
336
- }
337
-
338
- .ol-editor .ol-content .ProseMirror th {
339
- background: var(--ol-surface-hover);
340
- font-weight: 600;
341
- text-align: start;
342
- }
343
-
344
- /* prosemirror-tables marks cells in a rectangular selection with this class.
345
- An ::after overlay rather than a background so it composes with a cell that
346
- already has one, and so a header cell still reads as a header. */
347
- .ol-editor .ol-content .ProseMirror .selectedCell::after {
348
- content: "";
349
- position: absolute;
350
- inset: 0;
351
- background: var(--ol-surface-active);
352
- opacity: 0.4;
353
- pointer-events: none;
354
- }
355
-
356
- /* The column resize handle, drawn by prosemirror-tables' columnResizing. */
357
- .ol-editor .ol-content .ProseMirror .column-resize-handle {
358
- position: absolute;
359
- right: -2px;
360
- top: 0;
361
- bottom: 0;
362
- width: 4px;
363
- background: var(--ol-accent);
364
- pointer-events: none;
365
- z-index: 20;
366
- }
367
-
368
- .ol-editor .ol-content .ProseMirror.resize-cursor {
369
- cursor: col-resize;
370
- }
371
-
372
- /* Preserved-but-unrecognised markup, surfaced rather than hidden. */
373
- .ol-editor .ol-content .ProseMirror-selectednode {
374
- outline: 2px solid var(--ol-focus);
375
- outline-offset: 2px;
376
- border-radius: 2px;
377
- }
378
-
379
- .ol-editor .ol-source {
380
- box-sizing: border-box;
381
- display: block;
382
- width: 100%;
383
- min-height: 12rem;
384
- padding: 12px;
385
- border: 1px solid var(--ol-border);
386
- border-radius: 0 0 var(--ol-radius) var(--ol-radius);
387
- background: var(--ol-surface);
388
- color: var(--ol-text);
389
- font-family: var(--ol-font-mono);
390
- font-size: 13px;
391
- line-height: 1.5;
392
- resize: vertical;
393
- white-space: pre-wrap;
394
- }
395
-
396
- /* Directional icons under RTL.
397
- Group order reverses for free with flexbox, but a curved undo arrow does not:
398
- in an RTL document "back" points the other way. Only genuinely directional
399
- icons are flipped -- bold and italic must not be mirrored. */
400
- .ol-editor[dir="rtl"] .ol-icon--directional,
401
- [dir="rtl"] .ol-editor .ol-icon--directional {
402
- transform: scaleX(-1);
403
- }
404
-
405
- /* The announcement region. Visually hidden but not display:none, which would
406
- remove it from the accessibility tree and silence it. */
407
- .ol-editor .ol-live {
408
- position: absolute;
409
- width: 1px;
410
- height: 1px;
411
- margin: -1px;
412
- padding: 0;
413
- overflow: hidden;
414
- clip: rect(0 0 0 0);
415
- clip-path: inset(50%);
416
- white-space: nowrap;
417
- border: 0;
418
- }
419
-
420
- /* Coarse pointers get a larger target. WCAG 2.2 SC 2.5.8 asks for 24x24 CSS px
421
- minimum; 32 clears that on a mouse and 40 is comfortable on a thumb. */
422
- @media (pointer: coarse) {
423
- .ol-editor {
424
- --ol-button-size: var(--openleaf-button-size, 40px);
425
- --ol-gap: var(--openleaf-gap, 4px);
426
- }
427
- }
428
-
429
- @media (prefers-reduced-motion: reduce) {
430
- .ol-editor .ol-btn {
431
- transition: none;
432
- }
433
- }
434
-
435
- /* Forced colours (Windows high contrast) replaces our palette wholesale. The
436
- pressed state must not depend on a background we no longer control, so it is
437
- re-expressed as a border, which the mode preserves. */
438
- @media (forced-colors: active) {
439
- .ol-editor .ol-btn {
440
- border-color: ButtonBorder;
441
- color: ButtonText;
442
- }
443
- .ol-editor .ol-btn[aria-pressed="true"] {
444
- border-color: Highlight;
445
- color: Highlight;
446
- box-shadow: none;
447
- }
448
- .ol-editor .ol-btn:focus-visible {
449
- outline-color: Highlight;
450
- }
451
- .ol-editor .ol-btn[aria-disabled="true"] {
452
- color: GrayText;
453
- opacity: 1;
454
- }
455
- }
456
- `;
98
+ import { CSS } from './css.js';
99
+ export { CSS } from './css.js';
457
100
  let externallyProvided = false;
458
101
  /**
459
102
  * Declare that the integrator has linked `openleaf.css` themselves, so no
@@ -463,7 +106,10 @@ export function markStylesExternal() {
463
106
  externallyProvided = true;
464
107
  }
465
108
  const injected = new WeakSet();
466
- const registered = new Map();
109
+ // WeakMap, like its sibling above: a strong Map here pins every Document this
110
+ // module has ever styled -- every iframe, every closed print preview -- for the
111
+ // life of the page. Only get/set are used, so nothing needs to iterate it.
112
+ const registered = new WeakMap();
467
113
  let warned = false;
468
114
  /**
469
115
  * Attach a stylesheet through the CSP-safe path.
@@ -490,9 +136,19 @@ export function registerStyles(css, target) {
490
136
  // CSP gates resources *parsed as style* -- <style> elements, style attributes,
491
137
  // linked stylesheets. A CSSOM object attached through adoptedStyleSheets never
492
138
  // passes through that gate, by design rather than by loophole.
493
- if (typeof CSSStyleSheet !== 'undefined' && 'adoptedStyleSheets' in Document.prototype) {
139
+ //
140
+ // The constructor comes from the TARGET document's own window, and the
141
+ // capability is probed on the target rather than on this module's realm. A
142
+ // constructed sheet carries the document it was constructed for, and
143
+ // `adoptedStyleSheets` throws NotAllowedError for a sheet belonging to another
144
+ // one -- so `new CSSStyleSheet()` here, resolved from whichever realm this
145
+ // module happens to be loaded in, could never style an iframe or a print view.
146
+ // Confirmed in all three engines: top-realm sheet -> NotAllowedError, sheet
147
+ // built through the frame's own window -> adopted and applied.
148
+ const view = doc.defaultView;
149
+ if (view?.CSSStyleSheet && 'adoptedStyleSheets' in doc) {
494
150
  try {
495
- const sheet = new CSSStyleSheet();
151
+ const sheet = new view.CSSStyleSheet();
496
152
  sheet.replaceSync(css);
497
153
  doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, sheet];
498
154
  seen.add(css);
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgGG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B,IAAI,kBAAkB,GAAG,KAAK,CAAA;AAE9B;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,kBAAkB,GAAG,IAAI,CAAA;AAC3B,CAAC;AAED,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAY,CAAA;AACxC,8EAA8E;AAC9E,gFAAgF;AAChF,2EAA2E;AAC3E,MAAM,UAAU,GAAG,IAAI,OAAO,EAAyB,CAAA;AACvD,IAAI,MAAM,GAAG,KAAK,CAAA;AAElB;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,MAAiB;IAC3D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC9E,IAAI,CAAC,GAAG;QAAE,OAAO,aAAa,CAAA;IAE9B,IAAI,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAA;QAChB,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IAC3B,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IAEnC,+EAA+E;IAC/E,+EAA+E;IAC/E,+DAA+D;IAC/D,EAAE;IACF,uEAAuE;IACvE,2EAA2E;IAC3E,qEAAqE;IACrE,+EAA+E;IAC/E,2EAA2E;IAC3E,+EAA+E;IAC/E,4EAA4E;IAC5E,+DAA+D;IAC/D,MAAM,IAAI,GAAG,GAAG,CAAC,WAAkD,CAAA;IACnE,IAAI,IAAI,EAAE,aAAa,IAAI,oBAAoB,IAAI,GAAG,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,CAAA;YACtC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACtB,GAAG,CAAC,kBAAkB,GAAG,CAAC,GAAG,GAAG,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;YAC3D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACb,OAAO,SAAS,CAAA;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,CAAA;QACb,OAAO,CAAC,IAAI,CACV,iFAAiF;YAC/E,mDAAmD;YACnD,yEAAyE;YACzE,yDAAyD,CAC5D,CAAA;IACH,CAAC;IACD,OAAO,aAAa,CAAA;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAa;IACxC,IAAI,kBAAkB;QAAE,OAAO,UAAU,CAAA;IACzC,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAA;IACvC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACxC,IAAI,OAAO,KAAK,SAAS;QAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5C,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Test-only registry controls. Import from `@openleaf-editor/ui/testing`. */
2
+ export { clearToolbarItems } from './registry.js';
3
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Test-only registry controls. Import from `@openleaf-editor/ui/testing`. */
2
+ export { clearToolbarItems } from './registry.js';
3
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA"}