stilo-editor 0.0.0-stage → 0.1.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -2
  3. package/dist/characters--8h5uTeF.js +854 -0
  4. package/dist/content.css +161 -0
  5. package/dist/core/drop.d.ts +6 -0
  6. package/dist/core/editor.d.ts +108 -0
  7. package/dist/core/errors.d.ts +6 -0
  8. package/dist/core/events.d.ts +19 -0
  9. package/dist/core/extension-manager.d.ts +57 -0
  10. package/dist/core/extension.d.ts +43 -0
  11. package/dist/core/helpers/active.d.ts +33 -0
  12. package/dist/core/helpers/input-rules.d.ts +21 -0
  13. package/dist/core/helpers/lists.d.ts +12 -0
  14. package/dist/core/helpers/marks.d.ts +38 -0
  15. package/dist/core/helpers/nodes.d.ts +14 -0
  16. package/dist/core/helpers/parse-rules.d.ts +8 -0
  17. package/dist/core/html/css.d.ts +91 -0
  18. package/dist/core/html/parse.d.ts +7 -0
  19. package/dist/core/html/sanitize.d.ts +49 -0
  20. package/dist/core/html/serialize.d.ts +31 -0
  21. package/dist/core/types.d.ts +107 -0
  22. package/dist/extensions/blockquote/index.d.ts +15 -0
  23. package/dist/extensions/bold/index.d.ts +17 -0
  24. package/dist/extensions/bullet-list/index.d.ts +9 -0
  25. package/dist/extensions/clear-formatting/index.d.ts +12 -0
  26. package/dist/extensions/code/index.d.ts +15 -0
  27. package/dist/extensions/default-extensions/index.d.ts +46 -0
  28. package/dist/extensions/document/index.d.ts +17 -0
  29. package/dist/extensions/drop-cursor/index.d.ts +15 -0
  30. package/dist/extensions/gap-cursor/index.d.ts +6 -0
  31. package/dist/extensions/hard-break/index.d.ts +11 -0
  32. package/dist/extensions/heading/index.d.ts +24 -0
  33. package/dist/extensions/highlight/index.d.ts +24 -0
  34. package/dist/extensions/history/index.d.ts +21 -0
  35. package/dist/extensions/horizontal-rule/index.d.ts +11 -0
  36. package/dist/extensions/index.d.ts +27 -0
  37. package/dist/extensions/italic/index.d.ts +16 -0
  38. package/dist/extensions/link/index.d.ts +23 -0
  39. package/dist/extensions/list-item/index.d.ts +16 -0
  40. package/dist/extensions/move-block/index.d.ts +17 -0
  41. package/dist/extensions/ordered-list/index.d.ts +12 -0
  42. package/dist/extensions/paragraph/index.d.ts +14 -0
  43. package/dist/extensions/placeholder/index.d.ts +13 -0
  44. package/dist/extensions/strike/index.d.ts +16 -0
  45. package/dist/extensions/subscript/index.d.ts +16 -0
  46. package/dist/extensions/superscript/index.d.ts +17 -0
  47. package/dist/extensions/text/index.d.ts +12 -0
  48. package/dist/extensions/text-style/index.d.ts +14 -0
  49. package/dist/extensions/underline/index.d.ts +15 -0
  50. package/dist/index.d.ts +13 -0
  51. package/dist/index.js +1 -0
  52. package/dist/src-3tAxKI0c.js +1316 -0
  53. package/dist/style.css +797 -0
  54. package/dist/ui/components/character-picker.d.ts +22 -0
  55. package/dist/ui/components/characters.d.ts +10 -0
  56. package/dist/ui/components/color-button.d.ts +23 -0
  57. package/dist/ui/components/dropdown.d.ts +25 -0
  58. package/dist/ui/components/icon.d.ts +3 -0
  59. package/dist/ui/components/link-bubble.d.ts +19 -0
  60. package/dist/ui/components/link-popover.d.ts +20 -0
  61. package/dist/ui/components/popover.d.ts +27 -0
  62. package/dist/ui/components/shortcut.d.ts +11 -0
  63. package/dist/ui/i18n/en.d.ts +3 -0
  64. package/dist/ui/i18n/it.d.ts +3 -0
  65. package/dist/ui/i18n/types.d.ts +4 -0
  66. package/dist/ui/index.d.ts +19 -0
  67. package/dist/ui/toolbar/items.d.ts +12 -0
  68. package/dist/ui/toolbar/palette.d.ts +6 -0
  69. package/dist/ui/toolbar/toolbar.d.ts +28 -0
  70. package/dist/ui/toolbar/types.d.ts +87 -0
  71. package/dist/ui.css +635 -0
  72. package/dist/ui.js +1292 -0
  73. package/package.json +86 -4
package/dist/style.css ADDED
@@ -0,0 +1,797 @@
1
+ /* Stilo content styles: ProseMirror base CSS and defaults for the editable content. */
2
+
3
+ /*
4
+ * prosemirror-view/style/prosemirror.css and prosemirror-gapcursor/style/gapcursor.css.
5
+ * Copyright (C) 2015-2017 by Marijn Haverbeke and others, MIT license. Adapted to the lint
6
+ * rules: no `white-space: pre-wrap` fallback before `break-spaces`, and the separator image
7
+ * rule gains specificity instead of `!important`.
8
+ */
9
+ .ProseMirror {
10
+ position: relative;
11
+ }
12
+
13
+ .ProseMirror {
14
+ word-wrap: break-word;
15
+ white-space: break-spaces;
16
+ -webkit-font-variant-ligatures: none;
17
+ font-variant-ligatures: none;
18
+ font-feature-settings: "liga" 0; /* the above doesn't seem to work in Edge */
19
+ }
20
+
21
+ .ProseMirror pre {
22
+ white-space: pre-wrap;
23
+ }
24
+
25
+ .ProseMirror li {
26
+ position: relative;
27
+ }
28
+
29
+ .ProseMirror-hideselection *::selection {
30
+ background: transparent;
31
+ }
32
+ .ProseMirror-hideselection *::-moz-selection {
33
+ background: transparent;
34
+ }
35
+ .ProseMirror-hideselection {
36
+ caret-color: transparent;
37
+ }
38
+
39
+ /* See https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1421#issuecomment-1759320191 */
40
+ .ProseMirror [draggable][contenteditable="false"] {
41
+ user-select: text;
42
+ }
43
+
44
+ .ProseMirror-selectednode {
45
+ outline: 2px solid #8cf;
46
+ }
47
+
48
+ /* Make sure li selections wrap around markers */
49
+
50
+ li.ProseMirror-selectednode {
51
+ outline: none;
52
+ }
53
+
54
+ li.ProseMirror-selectednode:after {
55
+ content: "";
56
+ position: absolute;
57
+ left: -32px;
58
+ right: -2px;
59
+ top: -2px;
60
+ bottom: -2px;
61
+ border: 2px solid #8cf;
62
+ pointer-events: none;
63
+ }
64
+
65
+ /* Protect against generic img rules */
66
+
67
+ .ProseMirror img.ProseMirror-separator {
68
+ display: inline;
69
+ border: none;
70
+ margin: 0;
71
+ }
72
+
73
+ .ProseMirror-gapcursor {
74
+ display: none;
75
+ pointer-events: none;
76
+ position: absolute;
77
+ }
78
+
79
+ .ProseMirror-gapcursor:after {
80
+ content: "";
81
+ display: block;
82
+ position: absolute;
83
+ top: -2px;
84
+ width: 20px;
85
+ border-top: 1px solid black;
86
+ animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite;
87
+ }
88
+
89
+ @keyframes ProseMirror-cursor-blink {
90
+ to {
91
+ visibility: hidden;
92
+ }
93
+ }
94
+
95
+ .ProseMirror-focused .ProseMirror-gapcursor {
96
+ display: block;
97
+ }
98
+
99
+ /* Stilo content defaults */
100
+
101
+ /* Lists: list items hold paragraphs, which must not add their own margins. */
102
+ .stilo-content ul,
103
+ .stilo-content ol {
104
+ margin: 0.5em 0;
105
+ padding-left: 1.75em;
106
+ }
107
+
108
+ .stilo-content li > p,
109
+ .stilo-content li > ul,
110
+ .stilo-content li > ol {
111
+ margin: 0;
112
+ }
113
+
114
+ .stilo-content blockquote {
115
+ margin: 0.5em 0;
116
+ padding-left: 1em;
117
+ border-left: 3px solid var(--stilo-color-border, #d1d9e0);
118
+ color: var(--stilo-color-muted, #59636e);
119
+ }
120
+
121
+ .stilo-content hr {
122
+ margin: 1em 0;
123
+ border: none;
124
+ border-top: 1px solid var(--stilo-color-border, #d1d9e0);
125
+ }
126
+
127
+ .stilo-content code {
128
+ padding: 0.1em 0.3em;
129
+ border-radius: 0.25em;
130
+ background: var(--stilo-color-hover, #eef1f4);
131
+ font-family: ui-monospace, monospace;
132
+ font-size: 0.9em;
133
+ }
134
+
135
+ /* Placeholder: shown only while the content is editable. */
136
+ .stilo-content[contenteditable="true"] .stilo-placeholder::before {
137
+ content: attr(data-placeholder);
138
+ float: left;
139
+ height: 0;
140
+ color: var(--stilo-color-muted, #59636e);
141
+ pointer-events: none;
142
+ }
143
+
144
+ /*
145
+ * Large documents (ADR 0003): the browser skips style, layout and paint of the top-level blocks
146
+ * outside the viewport. Real typing in 10k paragraphs went from 144 ms to 24 ms per key (median,
147
+ * Chromium). A skipped block is 3em tall until it has been rendered once.
148
+ */
149
+ .stilo-content > * {
150
+ content-visibility: auto;
151
+ contain-intrinsic-size: auto 3em;
152
+ }
153
+
154
+ /* Containment stops margins from collapsing through a block: trim them inside a blockquote. */
155
+ .stilo-content blockquote > :first-child {
156
+ margin-top: 0;
157
+ }
158
+
159
+ .stilo-content blockquote > :last-child {
160
+ margin-bottom: 0;
161
+ }
162
+
163
+ /* Stilo default UI styles. */
164
+
165
+ /*
166
+ * Default values of the custom properties (docs/UI.md §7). `:where()` has no specificity, so any
167
+ * rule of the host page that sets them wins, whatever the order of the stylesheets.
168
+ */
169
+ :where(:root) {
170
+ --stilo-font-family: system-ui, sans-serif;
171
+ --stilo-font-size: 14px;
172
+
173
+ --stilo-color-text: #1f2328;
174
+ --stilo-color-muted: #59636e;
175
+ --stilo-color-bg: #ffffff;
176
+ --stilo-color-toolbar-bg: #f9fbfd;
177
+ --stilo-color-border: #d1d9e0;
178
+ --stilo-color-separator: #e4e8ec;
179
+ --stilo-color-hover: #eef1f4;
180
+ --stilo-color-hover-group: #f5f7f9;
181
+ --stilo-color-active: #dde4ee;
182
+ --stilo-color-focus: #0969da;
183
+ --stilo-color-error: #d1242f;
184
+
185
+ --stilo-radius: 6px;
186
+
187
+ --stilo-toolbar-padding-x: 2px;
188
+ --stilo-toolbar-padding-y: 4px;
189
+ --stilo-toolbar-gap: 2px;
190
+ --stilo-toolbar-group-gap: 4px;
191
+ --stilo-toolbar-separator-height: 18px;
192
+ --stilo-toolbar-sticky-top: 0;
193
+ --stilo-toolbar-shadow: 0 2px 6px rgb(0 0 0 / 0.08);
194
+ --stilo-z-toolbar: 1001;
195
+
196
+ --stilo-button-size: 30px;
197
+ --stilo-icon-size: 18px;
198
+
199
+ --stilo-popover-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
200
+ --stilo-z-popover: 1000;
201
+
202
+ --stilo-menu-h1-size: 1.5em;
203
+ --stilo-menu-h2-size: 1.3em;
204
+ --stilo-menu-h3-size: 1.15em;
205
+ --stilo-menu-h4-size: 1em;
206
+ --stilo-menu-h5-size: 1em;
207
+ --stilo-menu-h6-size: 1em;
208
+ }
209
+
210
+ /* Toolbar */
211
+ .stilo-toolbar {
212
+ display: flex;
213
+ flex-wrap: wrap;
214
+ gap: var(--stilo-toolbar-group-gap);
215
+ padding: var(--stilo-toolbar-padding-y) var(--stilo-toolbar-padding-x);
216
+ background: var(--stilo-color-toolbar-bg);
217
+ }
218
+
219
+ /*
220
+ * The toolbar and its sticky container have a background: their top corners follow the element
221
+ * that holds them, so that a rounded editor box keeps its corners (no `overflow` on the host,
222
+ * which would cut the popovers).
223
+ */
224
+ .stilo-toolbar-host,
225
+ .stilo-toolbar {
226
+ border-top-left-radius: inherit;
227
+ border-top-right-radius: inherit;
228
+ }
229
+
230
+ /* Sticky toolbar container (option `sticky`) */
231
+ .stilo-toolbar-host {
232
+ position: sticky;
233
+ top: var(--stilo-toolbar-sticky-top);
234
+ z-index: var(--stilo-z-toolbar);
235
+ background: var(--stilo-color-bg);
236
+ container-type: scroll-state;
237
+ }
238
+
239
+ /*
240
+ * A shadow while the toolbar is stuck at the top of the scrolling page. Pure CSS: browsers
241
+ * without scroll-state container queries ignore it and show the toolbar without shadow.
242
+ */
243
+ @container scroll-state(stuck: top) {
244
+ .stilo-toolbar {
245
+ box-shadow: var(--stilo-toolbar-shadow);
246
+ }
247
+ }
248
+
249
+ /* Group */
250
+ .stilo-toolbar__group {
251
+ display: flex;
252
+ gap: var(--stilo-toolbar-gap);
253
+ }
254
+
255
+ /* Separator: a short line, vertically centered, before every group after the first */
256
+ .stilo-toolbar__group:not(:first-child) {
257
+ position: relative;
258
+ padding-left: var(--stilo-toolbar-group-gap);
259
+ }
260
+
261
+ .stilo-toolbar__group:not(:first-child)::before {
262
+ content: "";
263
+ position: absolute;
264
+ top: 50%;
265
+ left: 0;
266
+ width: 1px;
267
+ height: var(--stilo-toolbar-separator-height);
268
+ background: var(--stilo-color-separator);
269
+ transform: translateY(-50%);
270
+ }
271
+
272
+ /* Button */
273
+ .stilo-toolbar__button {
274
+ display: flex;
275
+ align-items: center;
276
+ justify-content: center;
277
+ width: var(--stilo-button-size);
278
+ min-width: var(--stilo-button-size);
279
+ height: var(--stilo-button-size);
280
+ border: none;
281
+ border-radius: var(--stilo-radius);
282
+ background: transparent;
283
+ color: var(--stilo-color-text);
284
+ cursor: pointer;
285
+ font-family: var(--stilo-font-family);
286
+ font-size: var(--stilo-font-size);
287
+ padding: 0;
288
+ margin: 0;
289
+ transition: background-color 0.15s;
290
+ }
291
+
292
+ .stilo-toolbar__button:hover {
293
+ background: var(--stilo-color-hover);
294
+ }
295
+
296
+ .stilo-toolbar__button:focus-visible {
297
+ outline: 2px solid var(--stilo-color-focus);
298
+ outline-offset: 2px;
299
+ }
300
+
301
+ .stilo-toolbar__button.stilo-toolbar__button--active {
302
+ background: var(--stilo-color-active);
303
+ }
304
+
305
+ .stilo-toolbar__button[aria-disabled="true"] {
306
+ opacity: 0.4;
307
+ cursor: default;
308
+ }
309
+
310
+ .stilo-toolbar__button[aria-disabled="true"]:hover {
311
+ background: transparent;
312
+ }
313
+
314
+ /* Icon */
315
+ .stilo-icon {
316
+ width: var(--stilo-icon-size);
317
+ height: var(--stilo-icon-size);
318
+ color: var(--stilo-color-text);
319
+ }
320
+
321
+ /* Popover */
322
+ .stilo-popover-host {
323
+ position: relative;
324
+ }
325
+
326
+ .stilo-popover {
327
+ position: absolute;
328
+ top: 0;
329
+ left: 0;
330
+ width: max-content;
331
+ background: var(--stilo-color-bg);
332
+ border: 1px solid var(--stilo-color-border);
333
+ border-radius: var(--stilo-radius);
334
+ box-shadow: var(--stilo-popover-shadow);
335
+ z-index: var(--stilo-z-popover);
336
+ padding: 4px;
337
+ }
338
+
339
+ /* A component class with its own `display` must not show a closed popover. */
340
+ .stilo-popover[hidden] {
341
+ display: none;
342
+ }
343
+
344
+ /* Dropdown */
345
+ .stilo-dropdown__trigger {
346
+ width: auto;
347
+ min-width: 120px;
348
+ justify-content: space-between;
349
+ padding: 0 8px;
350
+ }
351
+
352
+ .stilo-dropdown__value {
353
+ overflow: hidden;
354
+ text-overflow: ellipsis;
355
+ white-space: nowrap;
356
+ }
357
+
358
+ .stilo-dropdown__menu {
359
+ min-width: 160px;
360
+ }
361
+
362
+ .stilo-dropdown__option {
363
+ display: flex;
364
+ align-items: center;
365
+ gap: 8px;
366
+ padding: 6px 8px;
367
+ border-radius: var(--stilo-radius);
368
+ cursor: pointer;
369
+ font-family: var(--stilo-font-family);
370
+ font-size: var(--stilo-font-size);
371
+ color: var(--stilo-color-text);
372
+ }
373
+
374
+ .stilo-dropdown__option:hover,
375
+ .stilo-dropdown__option:focus-visible {
376
+ background: var(--stilo-color-hover);
377
+ }
378
+
379
+ .stilo-dropdown__option:focus-visible {
380
+ outline: 2px solid var(--stilo-color-focus);
381
+ outline-offset: -2px;
382
+ }
383
+
384
+ .stilo-dropdown__option[aria-checked="true"] {
385
+ background: var(--stilo-color-active);
386
+ }
387
+
388
+ .stilo-dropdown__option[aria-disabled="true"] {
389
+ opacity: 0.4;
390
+ cursor: default;
391
+ }
392
+
393
+ .stilo-dropdown__option[aria-disabled="true"]:hover {
394
+ background: transparent;
395
+ }
396
+
397
+ .stilo-dropdown__label {
398
+ flex: 1;
399
+ }
400
+
401
+ .stilo-dropdown__shortcut {
402
+ font-size: 0.85em;
403
+ color: var(--stilo-color-muted);
404
+ }
405
+
406
+ /* Heading preview */
407
+ .stilo-dropdown__option--h1 .stilo-dropdown__label {
408
+ font-size: var(--stilo-menu-h1-size);
409
+ font-weight: 600;
410
+ }
411
+
412
+ .stilo-dropdown__option--h2 .stilo-dropdown__label {
413
+ font-size: var(--stilo-menu-h2-size);
414
+ font-weight: 600;
415
+ }
416
+
417
+ .stilo-dropdown__option--h3 .stilo-dropdown__label {
418
+ font-size: var(--stilo-menu-h3-size);
419
+ font-weight: 600;
420
+ }
421
+
422
+ .stilo-dropdown__option--h4 .stilo-dropdown__label {
423
+ font-size: var(--stilo-menu-h4-size);
424
+ font-weight: 600;
425
+ }
426
+
427
+ .stilo-dropdown__option--h5 .stilo-dropdown__label {
428
+ font-size: var(--stilo-menu-h5-size);
429
+ font-weight: 600;
430
+ }
431
+
432
+ .stilo-dropdown__option--h6 .stilo-dropdown__label {
433
+ font-size: var(--stilo-menu-h6-size);
434
+ font-weight: 600;
435
+ }
436
+
437
+ /* Link popover */
438
+ .stilo-link-popover__form {
439
+ display: flex;
440
+ flex-wrap: wrap;
441
+ align-items: center;
442
+ gap: 8px;
443
+ width: 320px;
444
+ padding: 4px;
445
+ font-family: var(--stilo-font-family);
446
+ font-size: var(--stilo-font-size);
447
+ color: var(--stilo-color-text);
448
+ }
449
+
450
+ .stilo-link-popover__url {
451
+ flex: 1 1 100%;
452
+ box-sizing: border-box;
453
+ padding: 6px 8px;
454
+ border: 1px solid var(--stilo-color-border);
455
+ border-radius: var(--stilo-radius);
456
+ background: var(--stilo-color-bg);
457
+ color: inherit;
458
+ font: inherit;
459
+ }
460
+
461
+ .stilo-link-popover__url:focus-visible {
462
+ outline: 2px solid var(--stilo-color-focus);
463
+ outline-offset: -1px;
464
+ }
465
+
466
+ .stilo-link-popover__url[aria-invalid="true"] {
467
+ border-color: var(--stilo-color-error);
468
+ }
469
+
470
+ .stilo-link-popover__new-tab {
471
+ display: flex;
472
+ flex: 1;
473
+ align-items: center;
474
+ gap: 6px;
475
+ cursor: pointer;
476
+ }
477
+
478
+ .stilo-link-popover__actions {
479
+ display: flex;
480
+ gap: 4px;
481
+ }
482
+
483
+ .stilo-link-popover__button {
484
+ padding: 4px 10px;
485
+ border: 1px solid var(--stilo-color-border);
486
+ border-radius: var(--stilo-radius);
487
+ background: var(--stilo-color-bg);
488
+ color: inherit;
489
+ cursor: pointer;
490
+ font: inherit;
491
+ }
492
+
493
+ .stilo-link-popover__button:hover {
494
+ background: var(--stilo-color-hover);
495
+ }
496
+
497
+ .stilo-link-popover__button:focus-visible {
498
+ outline: 2px solid var(--stilo-color-focus);
499
+ outline-offset: 1px;
500
+ }
501
+
502
+ .stilo-link-popover__button--primary,
503
+ .stilo-link-popover__button--primary:hover {
504
+ border-color: var(--stilo-color-focus);
505
+ background: var(--stilo-color-focus);
506
+ color: #ffffff;
507
+ }
508
+
509
+ /* Link bubble: small and unobtrusive */
510
+ .stilo-link-bubble {
511
+ display: flex;
512
+ gap: 1px;
513
+ padding: 2px;
514
+ }
515
+
516
+ .stilo-link-bubble__button {
517
+ display: flex;
518
+ align-items: center;
519
+ justify-content: center;
520
+ width: 24px;
521
+ height: 24px;
522
+ padding: 0;
523
+ border: none;
524
+ border-radius: var(--stilo-radius);
525
+ background: transparent;
526
+ color: var(--stilo-color-text);
527
+ cursor: pointer;
528
+ }
529
+
530
+ .stilo-link-bubble__button:hover {
531
+ background: var(--stilo-color-hover);
532
+ }
533
+
534
+ .stilo-link-bubble__button .stilo-icon {
535
+ width: 16px;
536
+ height: 16px;
537
+ }
538
+
539
+ /* Character picker: 10 columns (COLUMNS in character-picker.ts) */
540
+ .stilo-char-picker {
541
+ display: flex;
542
+ flex-direction: column;
543
+ gap: 4px;
544
+ font-family: var(--stilo-font-family);
545
+ font-size: var(--stilo-font-size);
546
+ color: var(--stilo-color-text);
547
+ }
548
+
549
+ .stilo-char-picker__search {
550
+ padding: 6px 8px;
551
+ border: 1px solid var(--stilo-color-border);
552
+ border-radius: var(--stilo-radius);
553
+ font: inherit;
554
+ }
555
+
556
+ .stilo-char-picker__search:focus-visible,
557
+ .stilo-char-picker__tab:focus-visible,
558
+ .stilo-char-picker__char:focus-visible {
559
+ outline: 2px solid var(--stilo-color-focus);
560
+ outline-offset: -2px;
561
+ }
562
+
563
+ .stilo-char-picker__tabs {
564
+ display: flex;
565
+ gap: 4px;
566
+ border-bottom: 1px solid var(--stilo-color-border);
567
+ }
568
+
569
+ .stilo-char-picker__tabs[hidden] {
570
+ display: none;
571
+ }
572
+
573
+ .stilo-char-picker__tab {
574
+ padding: 6px 10px;
575
+ border: none;
576
+ border-bottom: 2px solid transparent;
577
+ background: transparent;
578
+ color: var(--stilo-color-muted);
579
+ font: inherit;
580
+ cursor: pointer;
581
+ }
582
+
583
+ .stilo-char-picker__tab[aria-selected="true"] {
584
+ border-bottom-color: var(--stilo-color-focus);
585
+ color: var(--stilo-color-text);
586
+ }
587
+
588
+ .stilo-char-picker__panel {
589
+ max-height: 280px;
590
+ overflow-y: auto;
591
+ }
592
+
593
+ .stilo-char-picker__heading {
594
+ margin: 8px 0 4px;
595
+ color: var(--stilo-color-muted);
596
+ font-size: 0.85em;
597
+ }
598
+
599
+ .stilo-char-picker__grid {
600
+ display: grid;
601
+ grid-template-columns: repeat(10, 32px);
602
+ gap: 2px;
603
+ }
604
+
605
+ .stilo-char-picker__char {
606
+ width: 32px;
607
+ height: 32px;
608
+ padding: 0;
609
+ border: none;
610
+ border-radius: var(--stilo-radius);
611
+ background: transparent;
612
+ color: inherit;
613
+ font-size: 18px;
614
+ line-height: 1;
615
+ cursor: pointer;
616
+ }
617
+
618
+ .stilo-char-picker__char:hover {
619
+ background: var(--stilo-color-hover);
620
+ }
621
+
622
+ .stilo-char-picker__empty {
623
+ margin: 8px 0;
624
+ color: var(--stilo-color-muted);
625
+ }
626
+
627
+ /* Color split button (T-026): the main part shows the last used color under its icon */
628
+ .stilo-split {
629
+ display: flex;
630
+ }
631
+
632
+ /* Group hover: hovering one part lightly highlights both; the hovered part stays darker */
633
+ .stilo-split:hover
634
+ .stilo-toolbar__button:not(.stilo-toolbar__button--active, [aria-disabled="true"]) {
635
+ background: var(--stilo-color-hover-group);
636
+ }
637
+
638
+ .stilo-split
639
+ .stilo-toolbar__button:not(.stilo-toolbar__button--active, [aria-disabled="true"]):hover {
640
+ background: var(--stilo-color-hover);
641
+ }
642
+
643
+ .stilo-toolbar__button.stilo-split__main {
644
+ flex-direction: column;
645
+ gap: 1px;
646
+ border-top-right-radius: 0;
647
+ border-bottom-right-radius: 0;
648
+ }
649
+
650
+ .stilo-split__main .stilo-icon {
651
+ width: 16px;
652
+ height: 16px;
653
+ }
654
+
655
+ .stilo-split__color {
656
+ width: 16px;
657
+ height: 4px;
658
+ border-radius: 1px;
659
+ box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15);
660
+ }
661
+
662
+ .stilo-toolbar__button.stilo-split__arrow {
663
+ width: 20px;
664
+ min-width: 20px;
665
+ border-top-left-radius: 0;
666
+ border-bottom-left-radius: 0;
667
+ }
668
+
669
+ .stilo-split__arrow .stilo-icon {
670
+ width: 12px;
671
+ height: 12px;
672
+ }
673
+
674
+ /* Color picker: 8 columns (COLUMNS in color-button.ts) */
675
+ .stilo-color-picker {
676
+ display: flex;
677
+ flex-direction: column;
678
+ gap: 6px;
679
+ padding: 4px;
680
+ font-family: var(--stilo-font-family);
681
+ font-size: var(--stilo-font-size);
682
+ color: var(--stilo-color-text);
683
+ }
684
+
685
+ .stilo-color-picker__actions {
686
+ display: flex;
687
+ align-items: center;
688
+ gap: 6px;
689
+ }
690
+
691
+ .stilo-color-picker__none,
692
+ .stilo-color-picker__default {
693
+ flex: 1;
694
+ padding: 4px 8px;
695
+ border: none;
696
+ border-radius: var(--stilo-radius);
697
+ background: transparent;
698
+ color: inherit;
699
+ font: inherit;
700
+ text-align: center;
701
+ cursor: pointer;
702
+ }
703
+
704
+ .stilo-color-picker__none:hover,
705
+ .stilo-color-picker__default:hover {
706
+ background: var(--stilo-color-hover);
707
+ }
708
+
709
+ .stilo-color-picker__default[aria-pressed="true"] {
710
+ background: var(--stilo-color-active);
711
+ }
712
+
713
+ .stilo-color-picker__default mark {
714
+ padding: 0 4px;
715
+ border-radius: 2px;
716
+ }
717
+
718
+ .stilo-color-picker__separator {
719
+ width: 1px;
720
+ height: 18px;
721
+ background: var(--stilo-color-separator);
722
+ }
723
+
724
+ .stilo-color-picker__grid {
725
+ display: grid;
726
+ grid-template-columns: repeat(8, 22px);
727
+ gap: 4px;
728
+ }
729
+
730
+ .stilo-color-picker__swatch {
731
+ width: 22px;
732
+ height: 22px;
733
+ padding: 0;
734
+ border: none;
735
+ border-radius: 4px;
736
+ box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.15);
737
+ cursor: pointer;
738
+ }
739
+
740
+ .stilo-color-picker__swatch:hover {
741
+ transform: scale(1.15);
742
+ }
743
+
744
+ .stilo-color-picker__swatch[aria-pressed="true"] {
745
+ outline: 2px solid var(--stilo-color-text);
746
+ outline-offset: 1px;
747
+ }
748
+
749
+ .stilo-color-picker__none:focus-visible,
750
+ .stilo-color-picker__default:focus-visible,
751
+ .stilo-color-picker__swatch:focus-visible,
752
+ .stilo-color-picker__value:focus-visible,
753
+ .stilo-color-picker__native:focus-visible,
754
+ .stilo-color-picker__apply:focus-visible {
755
+ outline: 2px solid var(--stilo-color-focus);
756
+ outline-offset: 1px;
757
+ }
758
+
759
+ .stilo-color-picker__custom {
760
+ display: flex;
761
+ gap: 4px;
762
+ align-items: center;
763
+ margin: 0;
764
+ }
765
+
766
+ .stilo-color-picker__native {
767
+ width: 32px;
768
+ height: 28px;
769
+ padding: 0;
770
+ border: 1px solid var(--stilo-color-border);
771
+ border-radius: var(--stilo-radius);
772
+ background: var(--stilo-color-bg);
773
+ cursor: pointer;
774
+ }
775
+
776
+ .stilo-color-picker__value {
777
+ flex: 1;
778
+ min-width: 0;
779
+ padding: 4px 8px;
780
+ border: 1px solid var(--stilo-color-border);
781
+ border-radius: var(--stilo-radius);
782
+ font: inherit;
783
+ }
784
+
785
+ .stilo-color-picker__value[aria-invalid="true"] {
786
+ border-color: var(--stilo-color-error);
787
+ }
788
+
789
+ .stilo-color-picker__apply {
790
+ padding: 4px 10px;
791
+ border: 1px solid var(--stilo-color-focus);
792
+ border-radius: var(--stilo-radius);
793
+ background: var(--stilo-color-focus);
794
+ color: #ffffff;
795
+ font: inherit;
796
+ cursor: pointer;
797
+ }