@panphora/bevel 0.3.3 → 0.4.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.
package/README.md CHANGED
@@ -111,6 +111,10 @@ New mutating components emit cancelable `bevel:beforechange`, then `bevel:change
111
111
 
112
112
  Richclay, Quickcrop and Datastar remain optional. Load their adapters from `integrations/` after `bevel.js`. The Richclay adapter exposes `Bevel.richtext.mount()` and `unmount()`. The Quickcrop adapter exposes `Bevel.crop()`. The Datastar adapter exposes `Bevel.datastar.mount()`, `unmount()`, `control()` and `state()`.
113
113
 
114
+ The Sheet add-on is CSS only. Load `integrations/sheet.css` after `bevel.css` for a compact toolbar (`.bevel-toolbar--sheet` on a `.bevel-toolbar`), a phone tool strip (`.bevel-sheet-tools`), a spreadsheet grid (`.bevel-sheet-grid`, or saved `<table grid>` markup with `<td n>` for numbers), sheet tabs (`.bevel-sheet-tabs`) and a flat look picker (`.bevel-sheet-looks`). It adds four selection tokens: `--bevel-sel`, `--bevel-sel-fill`, `--bevel-sel-head` and `--bevel-sel-line`. The application positions `.bevel-sheet-grid__selection` and `.bevel-sheet-grid__editor` over the grid. See `examples/components/sheet.html`.
115
+
116
+ The application supplies `table-layout: fixed` and a table width when column widths should clip cell content.
117
+
114
118
  Nested Datastar registrations retain their own sessions when an outer registration unmounts. The adapter passes the remaining roots through `Bevel.destroy(root, { preserve: roots })`; those subtrees and their owned rich editors are excluded from teardown. Ordinary `Bevel.destroy(root)` still releases the entire subtree.
115
119
 
116
120
  For Richclay, load its Squire and DOMPurify scripts followed by its `richclay.js` global build before mounting. Bevel reuses externally mounted instances and never destroys them. It owns newly created instances even when the author supplied `contenteditable`. Repeated mounts reuse the instance; unmount releases its owned editor and theme tracking. A missing peer throws and emits `bevel:error`.
@@ -1575,11 +1575,16 @@
1575
1575
  {
1576
1576
  "source": "src/components/split-panes/editor-page.html",
1577
1577
  "output": "examples/components/split-panes-editor.html"
1578
+ },
1579
+ {
1580
+ "source": "src/docs/sheet-addon.html",
1581
+ "output": "examples/components/sheet.html"
1578
1582
  }
1579
1583
  ],
1580
1584
  "exampleStyles": [
1581
1585
  "examples/components/context-hypercms.css",
1582
- "integrations/quickcrop.css"
1586
+ "integrations/quickcrop.css",
1587
+ "integrations/sheet.css"
1583
1588
  ],
1584
1589
  "build": {
1585
1590
  "javascript": [
@@ -0,0 +1,114 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Sheet add-on · Bevel</title>
7
+ <link rel="stylesheet" href="../../bevel-fonts.css">
8
+ <link rel="stylesheet" href="../../bevel.css">
9
+ <link rel="stylesheet" href="../../integrations/sheet.css">
10
+ <style>
11
+ .sheet-demo { display: grid; gap: 28px; max-inline-size: 960px; margin-inline: auto; }
12
+ .sheet-demo .bevel-sheet { block-size: 360px; }
13
+ .sheet-demo__phone { inline-size: 360px; max-inline-size: 100%; }
14
+ .sheet-demo__phone .bevel-sheet { block-size: 300px; }
15
+ .sheet-demo pre { overflow-x: auto; }
16
+ </style>
17
+ </head>
18
+ <body>
19
+ <main class="bevel-example">
20
+ <div class="sheet-demo">
21
+ <header class="bevel-example__header">
22
+ <div>
23
+ <h1>Sheet add-on</h1>
24
+ <p>An optional stylesheet for spreadsheet-like tools: a compact toolbar, a grid with headers that stay in place, a selection, sheet tabs and a flat look picker. Link it after <code>bevel.css</code>. It adds no script.</p>
25
+ </div>
26
+ </header>
27
+
28
+ <pre><code>&lt;link rel="stylesheet" href="bevel.css"&gt;
29
+ &lt;link rel="stylesheet" href="integrations/sheet.css"&gt;</code></pre>
30
+
31
+ <section class="bevel-sheet" aria-label="Budget workbook">
32
+ <div class="bevel-toolbar bevel-toolbar--sheet" role="toolbar" aria-label="Formatting">
33
+ <div class="bevel-toolbar__group">
34
+ <button class="bevel-toolbar__icon" type="button" aria-label="Undo"><svg width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true" focusable="false"><path d="M224,128a96,96,0,0,1-94.71,96H128A95.38,95.38,0,0,1,62.1,197.8a8,8,0,0,1,11-11.63A80,80,0,1,0,71.43,71.39a3.07,3.07,0,0,1-.26.25L44.59,96H72a8,8,0,0,1,0,16H24a8,8,0,0,1-8-8V56a8,8,0,0,1,16,0V85.8L60.25,60A96,96,0,0,1,224,128Z"/></svg></button>
35
+ <button class="bevel-toolbar__icon" type="button" aria-label="Redo"><svg width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true" focusable="false"><path d="M240,56v48a8,8,0,0,1-8,8H184a8,8,0,0,1,0-16H211.4L184.81,71.64l-.25-.24a80,80,0,1,0-1.67,114.78,8,8,0,0,1,11,11.63A95.44,95.44,0,0,1,128,224h-1.32A96,96,0,1,1,195.75,60L224,85.8V56a8,8,0,1,1,16,0Z"/></svg></button>
36
+ </div>
37
+ <span class="bevel-toolbar__separator" aria-hidden="true"></span>
38
+ <div class="bevel-toolbar__group">
39
+ <button class="bevel-button" type="button" aria-haspopup="menu" aria-expanded="false">Currency <svg class="bevel-sheet-caret" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.18" stroke-linecap="square" stroke-linejoin="miter" aria-hidden="true" focusable="false"><path d="m5 9 7 7 7-7"/></svg></button>
40
+ <button class="bevel-button" type="button" aria-label="Fewer decimals">.0</button>
41
+ <button class="bevel-button" type="button" aria-label="More decimals">.00</button>
42
+ </div>
43
+ <span class="bevel-toolbar__separator" aria-hidden="true"></span>
44
+ <div class="bevel-toolbar__group">
45
+ <button class="bevel-toolbar__icon" type="button" aria-label="Bold" aria-pressed="true"><svg width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true" focusable="false"><path d="M178.48,115.7A44,44,0,0,0,148,40H80a8,8,0,0,0-8,8V200a8,8,0,0,0,8,8h80a48,48,0,0,0,18.48-92.3ZM88,56h60a28,28,0,0,1,0,56H88Zm72,136H88V128h72a32,32,0,0,1,0,64Z"/></svg></button>
46
+ <button class="bevel-toolbar__icon" type="button" aria-label="Italic" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true" focusable="false"><path d="M200,56a8,8,0,0,1-8,8H157.77L115.1,192H144a8,8,0,0,1,0,16H64a8,8,0,0,1,0-16H98.23L140.9,64H112a8,8,0,0,1,0-16h80A8,8,0,0,1,200,56Z"/></svg></button>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="bevel-sheet__viewport">
51
+ <table class="bevel-sheet-grid" id="sheet-demo-budget">
52
+ <colgroup><col style="width:42px"><col style="width:200px"><col style="width:120px"><col style="width:120px"><col style="width:120px"></colgroup>
53
+ <thead>
54
+ <tr><th class="bevel-sheet-grid__coord" scope="col"></th><th class="bevel-sheet-grid__coord" scope="col">A</th><th class="bevel-sheet-grid__coord" scope="col" aria-selected="true">B</th><th class="bevel-sheet-grid__coord" scope="col">C</th><th class="bevel-sheet-grid__coord" scope="col">D</th></tr>
55
+ <tr style="background:var(--bevel-sel-head);font-weight:400;text-align:center;white-space:normal"><th class="bevel-sheet-grid__coord" scope="row">1</th><td>Item</td><td>Planned</td><td>Spent</td><td>Left</td></tr>
56
+ </thead>
57
+ <tbody>
58
+ <tr><th class="bevel-sheet-grid__coord" scope="row">2</th><td>Rent</td><td n>1,200.00</td><td n>1,200.00</td><td n>0.00</td></tr>
59
+ <tr><th class="bevel-sheet-grid__coord" scope="row" aria-selected="true">3</th><td>Groceries</td><td n aria-selected="true">420.00</td><td n>388.15</td><td n>31.85</td></tr>
60
+ <tr><th class="bevel-sheet-grid__coord" scope="row" aria-selected="true">4</th><td>Transport</td><td n aria-selected="true">160.00</td><td n>142.60</td><td n>17.40</td></tr>
61
+ <tr><th class="bevel-sheet-grid__coord" scope="row" aria-selected="true">5</th><td>Utilities</td><td n aria-selected="true">210.00</td><td n>226.30</td><td n>-16.30</td></tr>
62
+ <tr><th class="bevel-sheet-grid__coord" scope="row">6</th><td>Savings</td><td n>500.00</td><td n>500.00</td><td n>0.00</td></tr>
63
+ <tr class="bevel-sheet-grid__total"><th class="bevel-sheet-grid__coord" scope="row">7</th><td>Total</td><td n>2,490.00</td><td n>2,457.05</td><td n>32.95</td></tr>
64
+ </tbody>
65
+ </table>
66
+ </div>
67
+
68
+ <div class="bevel-sheet-tabs">
69
+ <div class="bevel-sheet-tabs__list" role="tablist" aria-label="Sheets">
70
+ <button class="bevel-sheet-tabs__tab" type="button" role="tab" aria-selected="true" aria-controls="sheet-demo-budget">Budget</button>
71
+ <button class="bevel-sheet-tabs__tab" type="button" role="tab" aria-selected="false" aria-controls="sheet-demo-budget">Trips</button>
72
+ <button class="bevel-sheet-tabs__add" type="button" aria-label="Add a sheet">+</button>
73
+ </div>
74
+ <div class="bevel-sheet-tabs__status"><span>Sum <strong>790.00</strong></span><span>Count <strong>3</strong></span></div>
75
+ </div>
76
+ </section>
77
+
78
+ <div class="bevel-sheet-looks" role="group" aria-label="Page look">
79
+ <div class="bevel-sheet-looks__group">
80
+ <span class="bevel-sheet-looks__label">Look</span>
81
+ <button class="bevel-sheet-looks__button" type="button" aria-label="Previous look">&lsaquo;</button>
82
+ <span class="bevel-sheet-looks__current">Ledger</span>
83
+ <button class="bevel-sheet-looks__button" type="button" aria-label="Next look">&rsaquo;</button>
84
+ </div>
85
+ <button class="bevel-sheet-looks__button bevel-sheet-looks__button--confirm" type="button">Use this look</button>
86
+ </div>
87
+
88
+ <div class="sheet-demo__phone">
89
+ <section class="bevel-sheet" aria-label="Budget workbook on a phone">
90
+ <div class="bevel-sheet-tools" role="toolbar" aria-label="Cell tools">
91
+ <button class="bevel-sheet-tools__button" type="button" aria-label="Bold" aria-pressed="true"><span class="bevel-sheet-tools__cap">B</span></button>
92
+ <button class="bevel-sheet-tools__button" type="button" aria-label="Italic" aria-pressed="false"><span class="bevel-sheet-tools__cap">I</span></button>
93
+ <button class="bevel-sheet-tools__button" type="button" aria-label="Currency"><span class="bevel-sheet-tools__cap">$</span></button>
94
+ <button class="bevel-sheet-tools__button" type="button" aria-label="Sum"><span class="bevel-sheet-tools__cap">&Sigma;</span></button>
95
+ <button class="bevel-sheet-tools__button" type="button" aria-label="Undo"><span class="bevel-sheet-tools__cap"><svg width="17" height="17" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true" focusable="false"><path d="M224,128a96,96,0,0,1-94.71,96H128A95.38,95.38,0,0,1,62.1,197.8a8,8,0,0,1,11-11.63A80,80,0,1,0,71.43,71.39a3.07,3.07,0,0,1-.26.25L44.59,96H72a8,8,0,0,1,0,16H24a8,8,0,0,1-8-8V56a8,8,0,0,1,16,0V85.8L60.25,60A96,96,0,0,1,224,128Z"/></svg></span></button>
96
+ </div>
97
+ <div class="bevel-sheet__viewport">
98
+ <table grid>
99
+ <thead><tr><td>Item</td><td>Planned</td></tr></thead>
100
+ <tbody>
101
+ <tr><td>Rent</td><td n>1,200.00</td></tr>
102
+ <tr><td>Groceries</td><td n>420.00</td></tr>
103
+ <tr><td>Transport</td><td n>160.00</td></tr>
104
+ </tbody>
105
+ </table>
106
+ </div>
107
+ </section>
108
+ </div>
109
+
110
+ <p>The second grid is plain saved markup, <code>&lt;table grid&gt;</code> with <code>&lt;td n&gt;</code> for numbers. It needs no classes, so a file opened with no script still reads as a sheet.</p>
111
+ </div>
112
+ </main>
113
+ </body>
114
+ </html>
@@ -0,0 +1,99 @@
1
+ /* Bevel add-on: the Sheet look. Optional. Link it after bevel.css.
2
+ It styles the Sheet template's saved <table grid> markup and plain
3
+ .bevel-sheet-* classes, so other data apps can use the same look.
4
+ The full interactive workbook is the Sheet starter template. */
5
+ @layer base, components;
6
+
7
+ @layer base {
8
+ :root {
9
+ --bevel-sel: light-dark(#1D5B79, #5CA8CC);
10
+ --bevel-sel-fill: light-dark(#E5F0F6, #182B3A);
11
+ --bevel-sel-head: light-dark(#D8E8F1, #1E3548);
12
+ --bevel-sel-line: light-dark(#ADCBE0, #2D4F6C);
13
+ }
14
+ }
15
+
16
+ @layer components {
17
+ .bevel-sheet { display: flex; flex-direction: column; min-inline-size: 0; border: 1px solid var(--bevel-line-2); background: var(--bevel-surface); color: var(--bevel-ink); font-family: var(--bevel-font-sans); }
18
+ .bevel-sheet__viewport { position: relative; flex: 1; min-block-size: 0; overflow: auto; overscroll-behavior: contain; background: var(--bevel-surface); }
19
+
20
+ .bevel-toolbar--sheet { flex-wrap: nowrap; gap: 4px; min-block-size: 36px; padding: 0 10px; border: 0; border-block-end: 1px solid var(--bevel-line-2); background: var(--bevel-ground); overflow-x: auto; }
21
+ .bevel-toolbar--sheet .bevel-toolbar__group { gap: 3px; }
22
+ .bevel-toolbar--sheet .bevel-toolbar__separator { flex: none; block-size: 18px; margin-inline: 5px; }
23
+ .bevel-toolbar--sheet .bevel-toolbar__icon { inline-size: 26px; block-size: 26px; }
24
+ .bevel-toolbar--sheet .bevel-toolbar__group .bevel-toolbar__icon + .bevel-toolbar__icon { margin-inline-start: 0; }
25
+ .bevel-toolbar--sheet .bevel-button { flex: none; gap: 5px; height: 26px; padding: 0 9px; font-size: 12px; line-height: 1; }
26
+ .bevel-toolbar--sheet .bevel-button[aria-pressed="true"], .bevel-toolbar--sheet .bevel-button[aria-expanded="true"] { border-color: var(--bevel-edge-in) var(--bevel-edge-in-hi) var(--bevel-edge-in-hi) var(--bevel-edge-in); background: var(--bevel-face-in); }
27
+ .bevel-toolbar--sheet svg { flex: none; inline-size: 14px; block-size: 14px; }
28
+ .bevel-toolbar--sheet .bevel-sheet-caret { inline-size: 11px; block-size: 11px; }
29
+
30
+ .bevel-sheet-tools { display: flex; align-items: center; justify-content: space-between; gap: 2px; block-size: 44px; padding: 0 6px; border-block-end: 1px solid var(--bevel-line-2); background: var(--bevel-ground); overflow-x: auto; }
31
+ .bevel-sheet-tools__button { display: inline-grid; flex: none; place-items: center; inline-size: 44px; block-size: 44px; padding: 0; border: 0; background: transparent; color: var(--bevel-ink); cursor: pointer; }
32
+ .bevel-sheet-tools__button:focus-visible { outline: 2px solid var(--bevel-brass); outline-offset: -2px; }
33
+ .bevel-sheet-tools__cap { display: inline-grid; place-items: center; inline-size: 30px; block-size: 30px; border: 2px solid; border-color: var(--bevel-edge-hi) var(--bevel-edge-lo) var(--bevel-edge-lo) var(--bevel-edge-hi); background: var(--bevel-face); font: 600 11.5px/1 var(--bevel-font-sans); }
34
+ .bevel-sheet-tools__cap svg { inline-size: 17px; block-size: 17px; }
35
+ .bevel-sheet-tools__button:hover .bevel-sheet-tools__cap { background: color-mix(in srgb, var(--bevel-face), var(--bevel-edge-hi) 45%); }
36
+ .bevel-sheet-tools__button:active .bevel-sheet-tools__cap, .bevel-sheet-tools__button[aria-pressed="true"] .bevel-sheet-tools__cap { border-color: var(--bevel-edge-in) var(--bevel-edge-in-hi) var(--bevel-edge-in-hi) var(--bevel-edge-in); background: var(--bevel-face-in); color: var(--bevel-sel); }
37
+
38
+ :where(.bevel-sheet-grid, table[grid]) { border-collapse: separate; border-spacing: 0; border-block-start: 1px solid var(--bevel-line); border-inline-start: 1px solid var(--bevel-line); background: var(--bevel-surface); color: var(--bevel-ink); font: 400 13px/1.35 var(--bevel-font-sans); text-align: start; white-space: nowrap; }
39
+ :where(.bevel-sheet-grid, table[grid]) :is(td, th) { block-size: 26px; padding: 0 8px; border: 0; border-inline-end: 1px solid var(--bevel-line); border-block-end: 1px solid var(--bevel-line); font-size: 13px; line-height: 25px; vertical-align: middle; overflow: hidden; text-overflow: ellipsis; }
40
+ :where(.bevel-sheet-grid, table[grid]) th { font-weight: inherit; text-align: inherit; }
41
+ :where(.bevel-sheet-grid, table[grid]) td[n], .bevel-sheet-grid__num { text-align: end; font-family: var(--bevel-font-mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
42
+ /* Stacking: frozen cells 2, frozen selection/editor 3, row and column labels 4, corner 5. */
43
+ :where(.bevel-sheet-grid, table[grid]) thead tr { background: var(--bevel-ground); color: var(--bevel-ink); font-weight: 600; }
44
+ :where(.bevel-sheet-grid, table[grid]) thead td { position: sticky; inset-block-start: var(--bevel-sheet-frozen-top, 0px); z-index: 2; block-size: 27px; border-block-end: 2px solid var(--bevel-line-3); background: inherit; }
45
+ :where(.bevel-sheet-grid, table[grid]) td[aria-selected="true"] { background: var(--bevel-sel-fill); }
46
+ .bevel-sheet-grid:has(.bevel-sheet-grid__coord) { --bevel-sheet-frozen-top: 24px; }
47
+
48
+ .bevel-sheet-grid .bevel-sheet-grid__coord { position: sticky; z-index: 4; border-inline-end-color: var(--bevel-line-2); border-block-end-color: var(--bevel-line-2); background: var(--bevel-sunk); color: var(--bevel-muted); font: 500 11px/23px var(--bevel-font-mono); text-align: center; }
49
+ .bevel-sheet-grid thead .bevel-sheet-grid__coord { inset-block-start: var(--bevel-sheet-frozen-top, 0px); }
50
+ .bevel-sheet-grid thead tr:first-child .bevel-sheet-grid__coord { inset-block-start: 0; block-size: 24px; }
51
+ .bevel-sheet-grid .bevel-sheet-grid__coord:first-child { inset-inline-start: 0; padding: 0; }
52
+ .bevel-sheet-grid thead tr:first-child .bevel-sheet-grid__coord:first-child { z-index: 5; }
53
+ .bevel-sheet-grid .bevel-sheet-grid__coord[aria-selected="true"] { background: var(--bevel-sel-head); color: var(--bevel-sel); font-weight: 600; }
54
+ .bevel-sheet-grid tr:has(> .bevel-sheet-grid__coord[aria-selected="true"]):has(+ tr > .bevel-sheet-grid__coord[aria-selected="true"]) > .bevel-sheet-grid__coord[aria-selected="true"] { border-block-end-color: var(--bevel-sel-line); }
55
+
56
+ .bevel-sheet-grid tr:has(+ .bevel-sheet-grid__total) > :is(td, th) { border-block-end-color: var(--bevel-line-3); }
57
+ :where(.bevel-sheet-grid .bevel-sheet-grid__total) > td { block-size: 28px; border-block-end-color: var(--bevel-line-2); background: var(--bevel-ground); font-weight: 600; }
58
+
59
+ .bevel-sheet-grid__selection { position: absolute; z-index: 1; box-sizing: border-box; border: 2px solid var(--bevel-sel); pointer-events: none; }
60
+ .bevel-sheet-grid__handle { position: absolute; inset-inline-end: -5px; inset-block-end: -5px; inline-size: 8px; block-size: 8px; border: 1.5px solid var(--bevel-surface); background: var(--bevel-sel); pointer-events: auto; cursor: crosshair; }
61
+ .bevel-sheet-grid__editor { position: absolute; z-index: 1; box-sizing: border-box; margin: 0; padding: 0 6px; border: 0; outline: 2px solid var(--bevel-brass); outline-offset: -2px; background: var(--bevel-surface); color: var(--bevel-ink); font: 500 12px/1 var(--bevel-font-mono); box-shadow: var(--bevel-shadow); }
62
+
63
+ .bevel-sheet-grid__selection--frozen, .bevel-sheet-grid__editor--frozen { z-index: 3; }
64
+
65
+ .bevel-sheet-tabs { display: flex; align-items: stretch; justify-content: space-between; gap: 12px; min-block-size: 30px; padding: 0 10px; border-block-start: 1px solid var(--bevel-line-2); background: var(--bevel-sunk); }
66
+ .bevel-sheet-tabs__list { display: flex; align-items: stretch; gap: 2px; min-inline-size: 0; overflow-x: auto; }
67
+ .bevel-sheet-tabs__tab { display: inline-flex; align-items: center; gap: 6px; padding: 0 14px; border: 0; border-inline: 1px solid var(--bevel-line-2); background: transparent; color: var(--bevel-muted); font: 500 12px/1 var(--bevel-font-sans); white-space: nowrap; cursor: pointer; }
68
+ .bevel-sheet-tabs__tab:hover { background: var(--bevel-ground); color: var(--bevel-ink); }
69
+ .bevel-sheet-tabs__tab[aria-selected="true"] { margin-block-start: -1px; border-block-start: 1px solid var(--bevel-surface); background: var(--bevel-surface); color: var(--bevel-sel); font-weight: 600; }
70
+ .bevel-sheet-tabs__add { inline-size: 28px; border: 0; background: transparent; color: var(--bevel-muted); font: 500 15px/1 var(--bevel-font-sans); cursor: pointer; }
71
+ .bevel-sheet-tabs__add:hover { background: var(--bevel-face); color: var(--bevel-ink); }
72
+ .bevel-sheet-tabs__tab:focus-visible, .bevel-sheet-tabs__add:focus-visible { outline: 2px solid var(--bevel-brass); outline-offset: -2px; }
73
+ .bevel-sheet-tabs__status { display: flex; align-items: center; gap: 14px; color: var(--bevel-ink-2); font: 11.5px/1 var(--bevel-font-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
74
+ .bevel-sheet-tabs__status strong { color: var(--bevel-ink); font-weight: 600; }
75
+
76
+ .bevel-sheet-looks { display: flex; align-items: center; justify-content: space-between; gap: 8px; inline-size: 100%; max-inline-size: 440px; padding: 5px 10px; border: 1px solid var(--bevel-line-2); background: var(--bevel-surface); color: var(--bevel-ink-2); font: 12px/1.2 var(--bevel-font-sans); }
77
+ .bevel-sheet-looks__group { display: inline-flex; align-items: center; gap: 4px; }
78
+ .bevel-sheet-looks__label { margin-inline-end: 2px; color: var(--bevel-muted); }
79
+ .bevel-sheet-looks__current { min-inline-size: 112px; color: var(--bevel-ink); font-weight: 600; text-align: center; }
80
+ .bevel-sheet-looks__button { display: inline-flex; align-items: center; justify-content: center; margin: 0; padding: 4px 7px; border: 0; border-radius: 0; background: transparent; box-shadow: none; color: var(--bevel-muted); font: 500 12px/1.2 var(--bevel-font-sans); cursor: pointer; appearance: none; }
81
+ .bevel-sheet-looks__button:hover { background: var(--bevel-sunk); color: var(--bevel-ink); }
82
+ .bevel-sheet-looks__button:focus-visible { outline: 2px solid var(--bevel-brass); outline-offset: -2px; }
83
+ .bevel-sheet-looks__button--confirm { color: var(--bevel-sel); font-weight: 600; }
84
+
85
+ @media (pointer: coarse) {
86
+ .bevel-toolbar--sheet .bevel-toolbar__icon { inline-size: 40px; block-size: 40px; }
87
+ .bevel-sheet-tabs { min-block-size: 44px; }
88
+ .bevel-sheet-looks__button { min-inline-size: 44px; min-block-size: 44px; }
89
+ }
90
+ @media (forced-colors: active) {
91
+ :where(.bevel-sheet-grid, table[grid]) td[aria-selected="true"] { outline: 1px solid Highlight; outline-offset: -1px; }
92
+ .bevel-sheet-grid .bevel-sheet-grid__coord[aria-selected="true"], .bevel-sheet-tabs__tab[aria-selected="true"] { text-decoration: underline; }
93
+ }
94
+ @media print {
95
+ .bevel-toolbar--sheet, .bevel-sheet-tools, .bevel-sheet-tabs__add, .bevel-sheet-looks, .bevel-sheet-grid__selection, .bevel-sheet-grid__handle { display: none; }
96
+ .bevel-sheet__viewport { overflow: visible; }
97
+ :where(.bevel-sheet-grid, table[grid]) thead td, .bevel-sheet-grid .bevel-sheet-grid__coord { position: static; }
98
+ }
99
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panphora/bevel",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Beveled controls in an editorial page. One stylesheet, one script, no build.",
5
5
  "license": "MIT-0",
6
6
  "author": "David Miranda",
@@ -450,6 +450,7 @@
450
450
  "fonts": "node scripts/vendor-fonts.mjs",
451
451
  "vendor:floating": "node scripts/vendor-floating-ui.mjs",
452
452
  "check": "node scripts/check.mjs && node scripts/icon-guard.mjs --strict",
453
+ "sheet-addon": "node --test tests/sheet-addon.test.mjs",
453
454
  "check:icons": "node scripts/icon-guard.mjs",
454
455
  "contrast": "node scripts/contrast.mjs",
455
456
  "roundtrip": "node scripts/roundtrip.mjs",
@@ -458,7 +459,7 @@
458
459
  "correction:c1": "node tests/correction-c1.mjs",
459
460
  "correction:c2": "node tests/correction-c2.mjs",
460
461
  "correction:c2:overlays": "node tests/correction-c2-modal-drawer.mjs",
461
- "test": "node scripts/test-guard.mjs && npm run test:build && npm run test:showcase && npm run check && npm run contrast && npm run roundtrip && npm run functional && npm run datastar && npm run correction:c1 && npm run datastar:native && npm run clay:snapshot && npm run datastar:pickers && npm run correction:c2:overlays && npm run correction:c2:pickers && npm run correction:c2:forms && npm run correction:c2:wizard && npm run datastar:lifecycle && npm run datastar:reload && npm run richclay:integration && npm run inline-edit:integration && npm run quickcrop:integration && npm run packaged:peers && npm run upload:integration && npm run correction:c3:navigation && npm run correction:app-shell && npm run file-tree && npm run correction:c3:code-diff && npm run correction:c3:feedback && npm run correction:c3:split && npm run correction:c3:navigation-controls && npm run correction:c3:display && npm run correction:c3:rich-toolbar && npm run correction:c3:grid && npm run correction:c3:kanban && npm run context:hypercms && npm run context:quickcrop && npm run datastar:active && npm run datastar:board && npm run datastar:upload && npm run datastar:grid && npm run datastar:state-reload && npm run acceptance:layout && npm run final-review:regressions",
462
+ "test": "node scripts/test-guard.mjs && npm run test:build && npm run test:showcase && npm run check && npm run sheet-addon && npm run contrast && npm run roundtrip && npm run functional && npm run datastar && npm run correction:c1 && npm run datastar:native && npm run clay:snapshot && npm run datastar:pickers && npm run correction:c2:overlays && npm run correction:c2:pickers && npm run correction:c2:forms && npm run correction:c2:wizard && npm run datastar:lifecycle && npm run datastar:reload && npm run richclay:integration && npm run inline-edit:integration && npm run quickcrop:integration && npm run packaged:peers && npm run upload:integration && npm run correction:c3:navigation && npm run correction:app-shell && npm run file-tree && npm run correction:c3:code-diff && npm run correction:c3:feedback && npm run correction:c3:split && npm run correction:c3:navigation-controls && npm run correction:c3:display && npm run correction:c3:rich-toolbar && npm run correction:c3:grid && npm run correction:c3:kanban && npm run context:hypercms && npm run context:quickcrop && npm run datastar:active && npm run datastar:board && npm run datastar:upload && npm run datastar:grid && npm run datastar:state-reload && npm run acceptance:layout && npm run final-review:regressions",
462
463
  "dev": "node scripts/dev.mjs",
463
464
  "datastar:native": "node tests/datastar-native.mjs",
464
465
  "correction:c2:pickers": "node tests/correction-c2-pickers.mjs",
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "richclay",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "source": "Explicitly supplied local distribution; hashes identify the exact tested bytes, not a published release claim.",
5
5
  "files": {
6
- "richclay.js": "17d57ae64eac48f8fc57b90f0f18c9112fcb4194ef2b5b20096695d697e629a5",
6
+ "richclay.js": "cb11c591ef58cec92b7ce7b392606a8a74ba52a972750013a2a9a58eeb3c8c41",
7
7
  "richclay.css": "b2aed9608266f6798ea25edfa40c344c84b8f37d65e19ce8484f93ad849cd3c8",
8
8
  "LICENSE": "5312a8ef6ff9a844697b8b112612467efd12957e8afba098ce600dec0f8396c4",
9
9
  "THIRD-PARTY-NOTICES.md": "3659529614b62297b8336ac7f6189ef9f67425911265bff1cde8d136df21562b",
@@ -1549,7 +1549,10 @@ var RichClayBundle = (() => {
1549
1549
  currentAnchor() {
1550
1550
  const editor = this.editor;
1551
1551
  if (!editor.active || editor.options.readOnly || editor.dialog) return null;
1552
- if (editor.element.ownerDocument.hidden) return null;
1552
+ const doc = editor.element.ownerDocument;
1553
+ if (doc.hidden) return null;
1554
+ const live = doc.getSelection?.();
1555
+ if (!live || !live.rangeCount || !editor.element.contains(live.anchorNode)) return null;
1553
1556
  return editor.currentLinkElement();
1554
1557
  }
1555
1558
  update() {