palace-ui 0.12.0 → 0.12.1
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 +6 -0
- package/SPEC.md +29 -3
- package/catalog.html +48 -1
- package/package.json +1 -1
- package/palace.css +52 -2
package/README.md
CHANGED
|
@@ -13,4 +13,10 @@ rotation, chunky offset shadows. One stylesheet, no build step, no JavaScript.
|
|
|
13
13
|
- `SPEC.md`: the design specification, written to be followed exactly by people and AI agents alike
|
|
14
14
|
- `catalog.html`: every component on one page; open it in a browser
|
|
15
15
|
|
|
16
|
+
## Utilities
|
|
17
|
+
|
|
18
|
+
- `.visually-hidden`: text for screen readers only. A scrolling container
|
|
19
|
+
(`overflow-x: auto`) that holds it needs `position: relative`, or the hidden
|
|
20
|
+
text widens the page.
|
|
21
|
+
|
|
16
22
|
MIT licensed.
|
package/SPEC.md
CHANGED
|
@@ -157,7 +157,17 @@ A navbar menu for the signed-in user is a `<details class="navbar-menu">`: the s
|
|
|
157
157
|
</nav>
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
`.
|
|
160
|
+
Group items with `.navbar-menu-group`: a thin rule above, like the one before sign out, and an optional `.navbar-menu-label` as its heading. A setting that is switched on and off is a `button.navbar-menu-setting` with `aria-pressed`: its name sits on the left and a small square switch on the right, pink when pressed. Toggle `aria-pressed` with a script, or submit a form that renders the new state. Use it for on/off settings, not for links.
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<div class="navbar-menu-group" role="group" aria-labelledby="menu-settings">
|
|
164
|
+
<p class="navbar-menu-label" id="menu-settings">Settings</p>
|
|
165
|
+
<button type="button" class="navbar-menu-setting" aria-pressed="true">Notifications</button>
|
|
166
|
+
<button type="button" class="navbar-menu-setting" aria-pressed="false">Sound</button>
|
|
167
|
+
</div>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`.visually-hidden` hides text visually and keeps it for screen readers (see Visually Hidden).
|
|
161
171
|
|
|
162
172
|
With an icon beside the brand name (`.navbar-brand` uses `inline-flex` layout with `gap: 10px`; images/SVGs are auto-sized to 24×24):
|
|
163
173
|
|
|
@@ -302,7 +312,7 @@ Use `.card-static` instead of `.card` when the card is a container (e.g. auth fo
|
|
|
302
312
|
|
|
303
313
|
### Buttons
|
|
304
314
|
|
|
305
|
-
Size modifiers compose with any color variant:
|
|
315
|
+
Size modifiers compose with any color variant. `.btn` works on `<button>` and on `<a>` alike: each size sets its own line height, so a button and a link button of the same size are the same height (41px default, 28px `.btn-sm`, 51px `.btn-lg` and `.cta`) and line up side by side.
|
|
306
316
|
|
|
307
317
|
```html
|
|
308
318
|
<!-- Size modifiers -->
|
|
@@ -626,11 +636,27 @@ Inline keyboard key: bordered, uppercase mono, with a small pink offset shadow.
|
|
|
626
636
|
<kbd>Ctrl</kbd> + <kbd>Z</kbd>
|
|
627
637
|
```
|
|
628
638
|
|
|
639
|
+
### Visually Hidden
|
|
640
|
+
|
|
641
|
+
`.visually-hidden` keeps text for screen readers and draws nothing: a label for an icon-only column, the name of the row an "Edit" button acts on.
|
|
642
|
+
|
|
643
|
+
```html
|
|
644
|
+
<button class="btn btn-sm btn-outline">Edit<span class="visually-hidden"> Ada</span></button>
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
It is absolutely positioned where the text would have been, with no `top` or `left`, so it stays where the text is and a screen reader moving to it does not jump the page. That means it still counts toward the width of its containing block. **A scrolling container (`overflow-x: auto`) holding `.visually-hidden` text needs `position: relative`**; without it the hidden text's containing block is the page, and a wide table makes the whole page scroll sideways on a phone.
|
|
648
|
+
|
|
649
|
+
```html
|
|
650
|
+
<div style="overflow-x: auto; position: relative;">
|
|
651
|
+
<table>…<th><span class="visually-hidden">Actions</span></th>…</table>
|
|
652
|
+
</div>
|
|
653
|
+
```
|
|
654
|
+
|
|
629
655
|
## Accessibility
|
|
630
656
|
|
|
631
657
|
### Focus Visible
|
|
632
658
|
|
|
633
|
-
All interactive elements (buttons, links, inputs) have `:focus-visible` styles with a `2px` outline in accent-2 (purple) and `2px` offset. Buttons also get a lift + shadow on focus.
|
|
659
|
+
All interactive elements (buttons, links, inputs, checkboxes, radio buttons, `<summary>`) have `:focus-visible` styles with a `2px` outline in accent-2 (purple) and `2px` offset. Buttons also get a lift + shadow on focus. Text inputs show focus with a purple border and shadow instead. The navbar menu's summary keeps its own cyan ring.
|
|
634
660
|
|
|
635
661
|
### Reduced Motion
|
|
636
662
|
|
package/catalog.html
CHANGED
|
@@ -361,6 +361,17 @@
|
|
|
361
361
|
<button class="btn btn-lg btn-primary">Large</button>
|
|
362
362
|
</div>
|
|
363
363
|
|
|
364
|
+
<h3 style="margin-bottom: 12px;">Buttons and links side by side</h3>
|
|
365
|
+
<p style="margin-bottom: 12px;">A <code><button></code> and an <code><a class="btn"></code> of the same size are the same height and line up.</p>
|
|
366
|
+
<div data-source id="btn-match" style="display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; margin-bottom: 24px;">
|
|
367
|
+
<button class="btn btn-sm btn-outline">Button</button>
|
|
368
|
+
<a href="#" class="btn btn-sm btn-outline">Link</a>
|
|
369
|
+
<button class="btn btn-primary">Button</button>
|
|
370
|
+
<a href="#" class="btn btn-primary">Link</a>
|
|
371
|
+
<button class="btn btn-lg btn-secondary">Button</button>
|
|
372
|
+
<a href="#" class="btn btn-lg btn-secondary">Link</a>
|
|
373
|
+
</div>
|
|
374
|
+
|
|
364
375
|
<h3 style="margin-bottom: 12px;">Disabled</h3>
|
|
365
376
|
<div data-source style="display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 24px;">
|
|
366
377
|
<button class="btn btn-primary" disabled>Disabled</button>
|
|
@@ -462,6 +473,23 @@
|
|
|
462
473
|
</div>
|
|
463
474
|
</div>
|
|
464
475
|
|
|
476
|
+
<h3 style="margin-bottom: 12px;">Checkboxes, radio buttons and disclosures</h3>
|
|
477
|
+
<p style="margin-bottom: 12px;">Tab through them: each gets the same focus ring as links and buttons.</p>
|
|
478
|
+
<div data-source id="focus-controls" class="card-static" style="margin-bottom: 16px;">
|
|
479
|
+
<div class="stack-md">
|
|
480
|
+
<label><input type="checkbox" checked> Show lap times</label>
|
|
481
|
+
<fieldset style="border: 0;">
|
|
482
|
+
<legend class="visually-hidden">Direction</legend>
|
|
483
|
+
<label><input type="radio" name="cat-dir" checked> Anticlockwise</label>
|
|
484
|
+
<label><input type="radio" name="cat-dir"> Clockwise</label>
|
|
485
|
+
</fieldset>
|
|
486
|
+
<details>
|
|
487
|
+
<summary>More options</summary>
|
|
488
|
+
<p>Hidden until the summary is opened.</p>
|
|
489
|
+
</details>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
|
|
465
493
|
<h3 style="margin-bottom: 12px;">Inline Form</h3>
|
|
466
494
|
<div data-source style="display: flex; gap: 8px;">
|
|
467
495
|
<input type="text" placeholder="Add a label" aria-label="Add a label" style="flex: 1;">
|
|
@@ -522,6 +550,20 @@
|
|
|
522
550
|
</tbody>
|
|
523
551
|
</table>
|
|
524
552
|
</div>
|
|
553
|
+
|
|
554
|
+
<h3 style="margin-bottom: 12px; margin-top: 24px;">Scrolling table</h3>
|
|
555
|
+
<p style="margin-bottom: 12px;">A wide table scrolls inside its wrapper. The wrapper is <code>position: relative</code>, so <code>.visually-hidden</code> text in it stays inside it and the page never grows wider.</p>
|
|
556
|
+
<div data-source id="scroll-table" style="overflow-x: auto; position: relative;">
|
|
557
|
+
<table style="min-width: 640px;">
|
|
558
|
+
<thead>
|
|
559
|
+
<tr><th>Driver</th><th>Laps</th><th>Best</th><th>Last</th><th><span class="visually-hidden">Actions</span></th></tr>
|
|
560
|
+
</thead>
|
|
561
|
+
<tbody>
|
|
562
|
+
<tr><td>Ada</td><td>12</td><td>4.812</td><td>4.977</td><td><button class="btn btn-sm btn-outline">Edit<span class="visually-hidden"> Ada</span></button></td></tr>
|
|
563
|
+
<tr><td>Grace</td><td>11</td><td>4.903</td><td>5.120</td><td><button class="btn btn-sm btn-outline">Edit<span class="visually-hidden"> Grace</span></button></td></tr>
|
|
564
|
+
</tbody>
|
|
565
|
+
</table>
|
|
566
|
+
</div>
|
|
525
567
|
</div>
|
|
526
568
|
|
|
527
569
|
<!-- ════════════════════════════════════════ CODE ════════════════════════════════════════ -->
|
|
@@ -794,7 +836,7 @@
|
|
|
794
836
|
</div>
|
|
795
837
|
|
|
796
838
|
<h3 style="margin-bottom: 12px;">With a navbar menu (open it)</h3>
|
|
797
|
-
<div data-source style="margin-bottom: 24px; padding-bottom:
|
|
839
|
+
<div data-source style="margin-bottom: 24px; padding-bottom: 300px;">
|
|
798
840
|
<nav class="navbar">
|
|
799
841
|
<a href="#" class="navbar-brand">App Name</a>
|
|
800
842
|
<div class="navbar-right">
|
|
@@ -804,6 +846,11 @@
|
|
|
804
846
|
<p class="navbar-menu-label" aria-hidden="true">Your teams</p>
|
|
805
847
|
<ul aria-label="Your teams"><li><a href="#" aria-current="true">Team A</a></li><li><a href="#">Team B</a></li></ul>
|
|
806
848
|
<a href="#">Account</a>
|
|
849
|
+
<div class="navbar-menu-group" role="group" aria-labelledby="cat-menu-settings">
|
|
850
|
+
<p class="navbar-menu-label" id="cat-menu-settings">Settings</p>
|
|
851
|
+
<button type="button" class="navbar-menu-setting" aria-pressed="true">Notifications</button>
|
|
852
|
+
<button type="button" class="navbar-menu-setting" aria-pressed="false">Sound</button>
|
|
853
|
+
</div>
|
|
807
854
|
<form><button type="button">Sign out</button></form>
|
|
808
855
|
</div>
|
|
809
856
|
</details>
|
package/package.json
CHANGED
package/palace.css
CHANGED
|
@@ -114,11 +114,17 @@
|
|
|
114
114
|
/* The hidden attribute always hides, even on elements palace gives a display (buttons, .btn). */
|
|
115
115
|
[hidden] { display: none !important; }
|
|
116
116
|
|
|
117
|
-
/* Text for screen readers only:
|
|
117
|
+
/* Text for screen readers only: not drawn, still read. It is absolutely
|
|
118
|
+
positioned where it would have been, so inside a scrolling container that is
|
|
119
|
+
not positioned it still widens the page: give that container
|
|
120
|
+
position: relative. */
|
|
118
121
|
.visually-hidden {
|
|
119
122
|
position: absolute;
|
|
120
123
|
width: 1px;
|
|
121
124
|
height: 1px;
|
|
125
|
+
margin: -1px;
|
|
126
|
+
padding: 0;
|
|
127
|
+
border: 0;
|
|
122
128
|
overflow: hidden;
|
|
123
129
|
clip-path: inset(50%);
|
|
124
130
|
white-space: nowrap;
|
|
@@ -321,12 +327,17 @@ button, .btn {
|
|
|
321
327
|
transition: var(--p-transition);
|
|
322
328
|
text-decoration: none;
|
|
323
329
|
display: inline-block;
|
|
330
|
+
/* One line height for <button> and <a class="btn">, so both are the same
|
|
331
|
+
height: a button does not inherit the body's line height, a link does. */
|
|
332
|
+
line-height: calc(17 / 13);
|
|
333
|
+
text-align: center;
|
|
324
334
|
}
|
|
325
335
|
|
|
326
336
|
/* Size modifiers */
|
|
327
337
|
.btn-sm {
|
|
328
338
|
padding: 6px 14px;
|
|
329
339
|
font-size: 11px;
|
|
340
|
+
line-height: calc(14 / 11);
|
|
330
341
|
letter-spacing: 1px;
|
|
331
342
|
border-width: var(--p-border-thin);
|
|
332
343
|
}
|
|
@@ -334,6 +345,7 @@ button, .btn {
|
|
|
334
345
|
.btn-lg {
|
|
335
346
|
padding: 14px 28px;
|
|
336
347
|
font-size: 15px;
|
|
348
|
+
line-height: calc(19 / 15);
|
|
337
349
|
letter-spacing: 1px;
|
|
338
350
|
}
|
|
339
351
|
|
|
@@ -397,6 +409,8 @@ button, .btn {
|
|
|
397
409
|
padding: 14px 28px;
|
|
398
410
|
font-family: var(--p-font);
|
|
399
411
|
font-size: 15px;
|
|
412
|
+
line-height: calc(19 / 15);
|
|
413
|
+
text-align: center;
|
|
400
414
|
font-weight: 700;
|
|
401
415
|
text-transform: uppercase;
|
|
402
416
|
letter-spacing: 1px;
|
|
@@ -618,6 +632,15 @@ textarea:focus {
|
|
|
618
632
|
transform: var(--p-lift-sm);
|
|
619
633
|
}
|
|
620
634
|
|
|
635
|
+
/* Checkboxes, radio buttons and disclosure summaries: the focus ring of links
|
|
636
|
+
and buttons, without the lift. */
|
|
637
|
+
input[type="checkbox"]:focus-visible,
|
|
638
|
+
input[type="radio"]:focus-visible,
|
|
639
|
+
summary:focus-visible {
|
|
640
|
+
outline: var(--p-border-width) solid var(--p-accent-2);
|
|
641
|
+
outline-offset: 2px;
|
|
642
|
+
}
|
|
643
|
+
|
|
621
644
|
|
|
622
645
|
/* ══════════════════════════════════════════
|
|
623
646
|
STATUS MESSAGES
|
|
@@ -842,11 +865,38 @@ textarea:focus {
|
|
|
842
865
|
/* The current item: a pink bar, beside any focus outline, never instead of it. */
|
|
843
866
|
.navbar-menu-panel a[aria-current],
|
|
844
867
|
.navbar-menu-panel a[aria-current]:focus-visible { box-shadow: inset 3px 0 0 var(--p-accent-1); }
|
|
845
|
-
.navbar-menu-panel form
|
|
868
|
+
.navbar-menu-panel form,
|
|
869
|
+
.navbar-menu-group {
|
|
846
870
|
margin: var(--p-space-xs) 0 0;
|
|
847
871
|
padding-top: var(--p-space-xs);
|
|
848
872
|
border-top: var(--p-border-thin) solid var(--p-border);
|
|
849
873
|
}
|
|
874
|
+
/* A group of items under a thin rule, with an optional .navbar-menu-label. */
|
|
875
|
+
.navbar-menu-group { display: grid; }
|
|
876
|
+
.navbar-menu-group:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
|
|
877
|
+
/* A setting: its name on the left, a switch on the right, on and off from
|
|
878
|
+
aria-pressed. The switch is square-edged like everything else. */
|
|
879
|
+
.navbar-menu-panel .navbar-menu-setting {
|
|
880
|
+
display: flex;
|
|
881
|
+
align-items: center;
|
|
882
|
+
justify-content: space-between;
|
|
883
|
+
gap: var(--p-space-md);
|
|
884
|
+
}
|
|
885
|
+
.navbar-menu-setting::after {
|
|
886
|
+
content: '';
|
|
887
|
+
flex: none;
|
|
888
|
+
width: 28px;
|
|
889
|
+
height: 16px;
|
|
890
|
+
border: var(--p-border-width) solid var(--p-text);
|
|
891
|
+
background: var(--p-surface) linear-gradient(var(--p-text), var(--p-text)) no-repeat left 2px center / 8px 8px;
|
|
892
|
+
}
|
|
893
|
+
.navbar-menu-setting[aria-pressed="true"]::after {
|
|
894
|
+
background: var(--p-accent-1) linear-gradient(var(--p-text), var(--p-text)) no-repeat right 2px center / 8px 8px;
|
|
895
|
+
}
|
|
896
|
+
@media (forced-colors: active) {
|
|
897
|
+
.navbar-menu-setting::after { forced-color-adjust: none; border-color: CanvasText; background-color: Canvas; background-image: linear-gradient(CanvasText, CanvasText); }
|
|
898
|
+
.navbar-menu-setting[aria-pressed="true"]::after { background-color: Highlight; }
|
|
899
|
+
}
|
|
850
900
|
|
|
851
901
|
/* ══════════════════════════════════════════
|
|
852
902
|
TABLES
|