@0001-labs/design-system-1 0.3.0-alpha.22 → 0.3.0-alpha.23

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.
@@ -19,7 +19,9 @@
19
19
  * A tile's `data-place` is its square across, its square down, its width and
20
20
  * its height, in whole squares counted from 0. Tiles are placed a square
21
21
  * apart; a tile a square away from another, with the two overlapping along
22
- * that side, reaches towards it.
22
+ * that side, reaches towards it. A tile can have a place per layout,
23
+ * `data-place-phone="0 0 12 7"`, taken while the bento says
24
+ * `data-layout="phone"`; the page sets the layout and the columns for it.
23
25
  */
24
26
 
25
27
  /** A tile's place in squares: across, down, wide, high. */
@@ -51,10 +53,17 @@ export function bentoReach(places: readonly BentoPlace[]): BentoReach[] {
51
53
  });
52
54
  }
53
55
 
54
- /** Places one squares bento's tiles: their squares and their reach, as custom properties. */
56
+ /** A tile's place in the bento's layout: `data-place-<layout>` where the bento names one and the tile has it, else `data-place`. */
57
+ export function tilePlace(tile: HTMLElement, layout = ""): BentoPlace | undefined {
58
+ const own = layout ? tile.getAttribute(`data-place-${layout}`) : null;
59
+ return bentoPlace(own ?? tile.dataset.place);
60
+ }
61
+
62
+ /** Places one squares bento's tiles: their squares and their reach, as custom properties. The bento's `data-layout` (or `layout`) picks each tile's place for that layout. */
55
63
  export function placeBento(bento: HTMLElement): void {
64
+ const layout = bento.dataset.layout ?? bento.getAttribute("layout") ?? "";
56
65
  const tiles = [...bento.children].filter((child): child is HTMLElement => child instanceof HTMLElement && !child.hidden);
57
- const placed = tiles.map(tile => ({ tile, place: bentoPlace(tile.dataset.place) })).filter((entry): entry is { tile: HTMLElement; place: BentoPlace } => !!entry.place);
66
+ const placed = tiles.map(tile => ({ tile, place: tilePlace(tile, layout) })).filter((entry): entry is { tile: HTMLElement; place: BentoPlace } => !!entry.place);
58
67
  const reach = bentoReach(placed.map(entry => entry.place));
59
68
  placed.forEach(({ tile, place: [x, y, w, h] }, index) => {
60
69
  const sides = reach[index]!;
@@ -77,7 +86,7 @@ export function placeBentos(root: ParentNode = document): () => void {
77
86
  });
78
87
  for (const bento of bentos) {
79
88
  placeBento(bento);
80
- observer.observe(bento, { childList: true, subtree: false, attributes: true, attributeFilter: ["data-place", "hidden"] });
89
+ observer.observe(bento, { childList: true, subtree: false, attributes: true, attributeFilter: ["data-place", "data-layout", "hidden"] });
81
90
  for (const tile of bento.children) observer.observe(tile, { attributes: true, attributeFilter: ["data-place", "hidden"] });
82
91
  }
83
92
  return () => observer.disconnect();
@@ -24,16 +24,24 @@
24
24
  * data-rows="2" a tile two rows high (to 6)
25
25
  * data-place="0 0 15 7" a tile's square, width and height in squares
26
26
  *
27
- * Tokens: `--ds-bento-gap` (half a square), `--ds-bento-columns`,
28
- * `--ds-bento-row`, and on a tile `--ds-bento-span`, `--ds-bento-rows`.
27
+ * `data-fit` lets a squares bento's columns share a measure other than its
28
+ * squares (each tile still reaches a quarter square, so the gap is a column
29
+ * less half a square); `data-layout` (say `phone`) makes `placeBento()` take each tile's
30
+ * `data-place-phone` where it has one, a place per layout.
31
+ *
32
+ * Tokens: `--ds-bento-unit` (the square, `--ds-unit` by default),
33
+ * `--ds-bento-gap` (half of it), `--ds-bento-columns`, `--ds-bento-row`,
34
+ * `--ds-bento-padding` (a squares tile that is not a card, one square), and
35
+ * on a tile `--ds-bento-span`, `--ds-bento-rows`.
29
36
  */
30
37
 
31
38
  .ds-bento {
32
- --ds-bento-gap: calc(var(--ds-unit) / 2);
39
+ --ds-bento-unit: var(--ds-unit);
40
+ --ds-bento-gap: calc(var(--ds-bento-unit) / 2);
33
41
  box-sizing: border-box;
34
42
  display: grid;
35
43
  grid-template-columns: repeat(var(--ds-bento-columns, 3), minmax(0, 1fr));
36
- grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-unit))), auto);
44
+ grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-bento-unit))), auto);
37
45
  grid-auto-flow: row dense;
38
46
  gap: var(--ds-bento-gap);
39
47
  margin: 0;
@@ -69,15 +77,20 @@
69
77
 
70
78
  /* Squares: every tile on whole squares, a square apart, its surface a quarter square nearer each neighbour. */
71
79
  .ds-bento[data-squares] {
72
- --ds-bento-reach: calc(var(--ds-unit) / 4);
80
+ --ds-bento-reach: calc(var(--ds-bento-unit) / 4);
73
81
  /* Exactly its squares wide: each column one square. */
74
- width: calc(var(--ds-bento-columns, 48) * var(--ds-unit));
82
+ width: calc(var(--ds-bento-columns, 48) * var(--ds-bento-unit));
75
83
  max-width: none;
76
- grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-unit));
77
- grid-auto-rows: var(--ds-unit);
84
+ grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-bento-unit));
85
+ grid-auto-rows: var(--ds-bento-unit);
78
86
  grid-auto-flow: row;
79
87
  gap: 0;
80
88
  }
89
+ /* Fit: the columns share a measure narrower (or wider) than the squares, the rows still one square. */
90
+ .ds-bento[data-squares][data-fit] {
91
+ width: auto;
92
+ grid-template-columns: repeat(var(--ds-bento-columns, 48), minmax(0, 1fr));
93
+ }
81
94
  .ds-bento[data-squares] > * {
82
95
  --ds-bento-inset-top: calc(var(--ds-bento-reach) * var(--ds-bento-top, 0));
83
96
  --ds-bento-inset-end: calc(var(--ds-bento-reach) * var(--ds-bento-end, 0));
@@ -90,8 +103,8 @@
90
103
  /* A card grows its own padding by the reach (card.css); any other tile is padded here, a square inside. */
91
104
  .ds-bento[data-squares] > :not(.ds-card, ds-card) {
92
105
  padding:
93
- calc(var(--ds-unit) + var(--ds-bento-inset-top))
94
- calc(var(--ds-unit) + var(--ds-bento-inset-end))
95
- calc(var(--ds-unit) + var(--ds-bento-inset-bottom))
96
- calc(var(--ds-unit) + var(--ds-bento-inset-start));
106
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-top))
107
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-end))
108
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-bottom))
109
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-start));
97
110
  }
@@ -1,4 +1,4 @@
1
- /* version 0.3.0-alpha.22 */
1
+ /* version 0.3.0-alpha.23 */
2
2
 
3
3
  /* Noto Sans for Japanese and Chinese, for a product that shows them. Opt in:
4
4
  link it beside one.css or fonts.css, or ask Sync 1 for "cjk": true. Without
@@ -226,8 +226,10 @@ textarea.ds-input {
226
226
 
227
227
  /*
228
228
  * `.ds-checkbox` and `.ds-radio` are the `ds-checkbox` and `ds-radio` elements'
229
- * faces on a native `<input>`: one square on the field's ground with a 1px
230
- * line. The checkbox has the corners of a control and fills with the accent,
229
+ * faces on a native `<input>`: a box one control (16px) square on the field's
230
+ * ground with a 1px line, standing as an icon does, on the lower sixteen at the
231
+ * start of its square, so it takes one square and the words begin on the next
232
+ * (Joachim, 19 October 2026). The checkbox has the corners of a control and fills with the accent,
231
233
  * the check (`x-icon/check.svg`) in its ink; the radio is a circle with a dot
232
234
  * half a square across in the text colour.
233
235
  */
@@ -238,10 +240,12 @@ textarea.ds-input {
238
240
  display: inline-grid;
239
241
  flex: 0 0 auto;
240
242
  place-items: center;
241
- vertical-align: middle;
242
- width: var(--ds-row-height);
243
- height: var(--ds-row-height);
243
+ vertical-align: top;
244
+ width: var(--ds-control-height);
245
+ height: var(--ds-control-height);
244
246
  margin: 0;
247
+ margin-block-start: calc(var(--ds-row-height) - var(--ds-control-height));
248
+ margin-inline-end: calc(var(--ds-row-height) - var(--ds-control-height));
245
249
  padding: 0;
246
250
  border: 1px solid var(--ds-border-color);
247
251
  background: var(--ds-input-background);
@@ -267,13 +271,13 @@ textarea.ds-input {
267
271
  }
268
272
 
269
273
  .ds-checkbox::before {
270
- width: calc(0.8 * var(--ds-row-height));
271
- height: calc(0.8 * var(--ds-row-height));
274
+ width: var(--ds-control-height);
275
+ height: var(--ds-control-height);
272
276
  mask: var(--ds-checkbox-mark) center / contain no-repeat;
273
277
  }
274
278
 
275
279
  .ds-checkbox:indeterminate::before {
276
- width: calc(var(--ds-row-height) / 2);
280
+ width: calc(var(--ds-control-height) / 2);
277
281
  height: calc(2px * var(--ds-sf));
278
282
  mask: none;
279
283
  }
@@ -284,8 +288,8 @@ textarea.ds-input {
284
288
  }
285
289
 
286
290
  .ds-radio::before {
287
- width: calc(var(--ds-row-height) / 2);
288
- height: calc(var(--ds-row-height) / 2);
291
+ width: calc(var(--ds-control-height) / 2);
292
+ height: calc(var(--ds-control-height) / 2);
289
293
  border-radius: 50%;
290
294
  }
291
295
 
@@ -297,8 +301,9 @@ textarea.ds-input {
297
301
  /*
298
302
  * `.ds-switch` is the `ds-switch` element's look on a native
299
303
  * `<button role="switch" aria-checked>`: two control heights wide, its thumb
300
- * one control high less a 2px inset, travelling one control height.
301
- * `.ds-switch--rounded` is the round variant with a white thumb.
304
+ * one control high less a 2px inset, travelling one control height. A pill with a white
305
+ * round thumb, grey when off and the darker green when on, whatever the page's accent: the
306
+ * one switch (Joachim, 19 October 2026).
302
307
  */
303
308
 
304
309
  .ds-switch {
@@ -314,9 +319,9 @@ textarea.ds-input {
314
319
  margin: 0;
315
320
  padding: calc(2px * var(--ds-sf));
316
321
  border: 0;
317
- border-radius: var(--ds-radius);
322
+ border-radius: var(--ds-choice-unit);
318
323
  background: var(--ds-fill);
319
- color: var(--ds-text-color-muted);
324
+ color: var(--ds-white);
320
325
  cursor: pointer;
321
326
  touch-action: manipulation;
322
327
  }
@@ -326,35 +331,20 @@ textarea.ds-input {
326
331
  display: block;
327
332
  width: calc(var(--ds-choice-unit) - 4px * var(--ds-sf));
328
333
  height: 100%;
329
- border-radius: var(--ds-radius);
330
- background: currentColor;
334
+ border-radius: 50%;
335
+ background: var(--ds-white);
331
336
  transform: translateX(0);
332
337
  transition: transform 140ms ease;
333
338
  }
334
339
 
335
340
  .ds-switch[aria-checked="true"] {
336
- background: var(--ds-accent-color);
337
- color: var(--ds-button-text-color-on-accent);
341
+ background: var(--ds-switch-track-on);
338
342
  }
339
343
 
340
344
  .ds-switch[aria-checked="true"]::after {
341
345
  transform: translateX(var(--ds-choice-unit));
342
346
  }
343
347
 
344
- .ds-switch--rounded {
345
- border-radius: var(--ds-choice-unit);
346
- color: var(--ds-white);
347
- }
348
-
349
- .ds-switch--rounded::after {
350
- border-radius: 50%;
351
- background: var(--ds-white);
352
- }
353
-
354
- .ds-switch--rounded[aria-checked="true"] {
355
- background: var(--ds-switch-track-on);
356
- }
357
-
358
348
  @media (prefers-reduced-motion: reduce) {
359
349
  .ds-switch::after {
360
350
  transition: none;
@@ -1,4 +1,4 @@
1
- /* version 0.3.0-alpha.22 */
1
+ /* version 0.3.0-alpha.23 */
2
2
 
3
3
  /* Design system 1's faces and the typeface tokens that name them, on their
4
4
  own: a page that does not load one.css links this sheet (one.css imports
@@ -1,4 +1,4 @@
1
- /* version 0.3.0-alpha.22 */
1
+ /* version 0.3.0-alpha.23 */
2
2
 
3
3
  @import "./grid.css";
4
4
  @import "./component-tokens.css";
@@ -1,4 +1,4 @@
1
- /* DS1 — version 0.3.0-alpha.22 */
1
+ /* DS1 — version 0.3.0-alpha.23 */
2
2
  /* A classless stylesheet for native HTML. No JavaScript is required. */
3
3
 
4
4
  /* It draws on Design system 1's measures: the 20px square, 14px type on
@@ -2,8 +2,8 @@ import { LitElement, html, unsafeCSS } from "lit";
2
2
  import { define } from "../0-face/define";
3
3
  import styles from "./styles/ds-switch.css?inline";
4
4
 
5
- /** The shared switch face. The slotted button retains native activation and refs. */
6
- /** rounded selects a pill track, white circular thumb and darker-green on state. */
5
+ /** The switch: a pill with a white round thumb, grey when off and the darker green when on,
6
+ whatever the page's accent. The slotted button retains native activation and refs. */
7
7
  export class Switch extends LitElement {
8
8
  static styles = unsafeCSS(styles);
9
9
  focus(options?: FocusOptions) { this.querySelector<HTMLButtonElement>(":scope > button")?.focus(options); }
@@ -1,10 +1,14 @@
1
1
  @import "../../1-root/component-metrics.css";
2
2
 
3
+ /* One square, the box one control (16px) square on its lower sixteen at its start, as an icon
4
+ stands, so the words begin on the next square (Joachim, 19 October 2026). */
3
5
  :host {
4
6
  --ds-choice-unit: calc(var(--ds-1) * var(--ds-sf));
5
- display: inline-flex;
7
+ display: inline-grid;
8
+ align-items: end;
9
+ justify-items: start;
6
10
  flex: 0 0 auto;
7
- vertical-align: middle;
11
+ vertical-align: top;
8
12
  width: var(--ds-choice-unit);
9
13
  height: var(--ds-choice-unit);
10
14
  }
@@ -14,9 +18,9 @@
14
18
  box-sizing: border-box !important;
15
19
  display: grid !important;
16
20
  place-items: center !important;
17
- width: 100% !important;
21
+ width: var(--ds-control-height) !important;
18
22
  min-width: 0 !important;
19
- height: 100% !important;
23
+ height: var(--ds-control-height) !important;
20
24
  min-height: 0 !important;
21
25
  margin: 0 !important;
22
26
  padding: 0 !important;
@@ -31,15 +35,15 @@
31
35
  ::slotted(input:checked), ::slotted(input:indeterminate) { background: var(--ds-accent-color) !important; }
32
36
  ::slotted(input)::before {
33
37
  content: "";
34
- width: calc(.8 * var(--ds-choice-unit));
35
- height: calc(.8 * var(--ds-choice-unit));
38
+ width: var(--ds-control-height);
39
+ height: var(--ds-control-height);
36
40
  background: currentColor;
37
41
  mask: var(--ds-checkbox-mark) center / contain no-repeat;
38
42
  opacity: 0;
39
43
  }
40
44
  ::slotted(input:checked)::before { opacity: 1; }
41
45
  ::slotted(input:indeterminate)::before {
42
- width: calc(var(--ds-choice-unit) / 2);
46
+ width: calc(var(--ds-control-height) / 2);
43
47
  height: calc(2px * var(--ds-sf));
44
48
  mask: none;
45
49
  opacity: 1;
@@ -9,6 +9,9 @@
9
9
  height: var(--ds-unit);
10
10
  }
11
11
  :host([hidden]) { display: none !important; }
12
+ /* A plain radio as the checkbox: a 16px circle on its square's lower sixteen, at its start. */
13
+ :host(:not([choice])) { display: inline-grid; align-items: end; justify-items: start; vertical-align: top; }
14
+ :host(:not([choice])) ::slotted(input[type="radio"]) { width: var(--ds-control-height) !important; height: var(--ds-control-height) !important; }
12
15
  ::slotted(input[type="radio"]) {
13
16
  appearance: none !important;
14
17
  box-sizing: border-box !important;
@@ -30,8 +33,8 @@
30
33
  ::slotted(input[hidden]) { display: none !important; }
31
34
  ::slotted(input)::before {
32
35
  content: "";
33
- width: calc(var(--ds-unit) / 2);
34
- height: calc(var(--ds-unit) / 2);
36
+ width: calc(var(--ds-control-height) / 2);
37
+ height: calc(var(--ds-control-height) / 2);
35
38
  border-radius: 50%;
36
39
  background: currentColor;
37
40
  opacity: 0;
@@ -21,10 +21,10 @@
21
21
  padding: calc(2px * var(--ds-sf)) !important;
22
22
  margin: 0 !important;
23
23
  border: 0 !important;
24
- border-radius: var(--ds-radius) !important;
25
- corner-shape: var(--ds-corner-shape, round) !important;
24
+ border-radius: var(--ds-choice-unit) !important;
25
+ corner-shape: round !important;
26
26
  background: var(--ds-fill) !important;
27
- color: var(--ds-text-color-muted) !important;
27
+ color: var(--ds-white) !important;
28
28
  box-shadow: none !important;
29
29
  cursor: pointer !important;
30
30
  touch-action: manipulation;
@@ -34,32 +34,16 @@
34
34
  display: block;
35
35
  width: calc(var(--ds-choice-unit) - 4px * var(--ds-sf));
36
36
  height: 100%;
37
- border-radius: var(--ds-radius);
38
- corner-shape: var(--ds-corner-shape, round);
39
- background: currentColor;
37
+ border-radius: 50%;
38
+ corner-shape: round;
39
+ background: var(--ds-white);
40
40
  transform: translateX(0);
41
41
  transition: transform 140ms ease;
42
42
  }
43
43
  ::slotted(button[aria-checked="true"]) {
44
- background: var(--ds-accent-color) !important;
45
- color: var(--ds-button-text-color-on-accent) !important;
44
+ background: var(--ds-switch-track-on) !important;
46
45
  }
47
46
  ::slotted(button[aria-checked="true"])::after { transform: translateX(var(--ds-choice-unit)); }
48
47
  ::slotted(button:focus-visible) { outline: 2px solid var(--ds-focus-ring) !important; outline-offset: 1px !important; }
49
48
  ::slotted(button:disabled) { cursor: default !important; opacity: .5 !important; }
50
49
  @media (prefers-reduced-motion: reduce) { ::slotted(button)::after { transition: none; } }
51
-
52
- /* Rounded switches keep their shape and white thumb independently of page accents. */
53
- :host([rounded]) ::slotted(button) {
54
- border-radius: var(--ds-choice-unit) !important;
55
- corner-shape: round !important;
56
- color: var(--ds-white) !important;
57
- }
58
- :host([rounded]) ::slotted(button)::after {
59
- border-radius: 50%;
60
- corner-shape: round;
61
- background: var(--ds-white);
62
- }
63
- :host([rounded]) ::slotted(button[aria-checked="true"]) {
64
- background: var(--ds-switch-track-on) !important;
65
- }
@@ -16,12 +16,18 @@ export class Bento extends LitElement {
16
16
  static properties = {
17
17
  columns: { type: Number, reflect: true },
18
18
  squares: { type: Boolean, reflect: true },
19
+ fit: { type: Boolean, reflect: true },
20
+ layout: { type: String, reflect: true },
19
21
  };
20
22
 
21
23
  /** The number of columns (flow, three by default), or the squares across (`squares`, 48 by default). */
22
24
  declare columns: number | undefined;
23
25
  /** Places every tile on whole squares by its `data-place`. */
24
26
  declare squares: boolean;
27
+ /** With `squares`, lets the columns share a measure other than the squares. */
28
+ declare fit: boolean;
29
+ /** Takes each tile's `data-place-<layout>` where it has one (say `phone`). */
30
+ declare layout: string | undefined;
25
31
 
26
32
  static styles = [unsafeCSS(metrics), unsafeCSS(styles)];
27
33
 
@@ -30,12 +36,13 @@ export class Bento extends LitElement {
30
36
  constructor() {
31
37
  super();
32
38
  this.squares = false;
39
+ this.fit = false;
33
40
  }
34
41
 
35
42
  connectedCallback() {
36
43
  super.connectedCallback();
37
44
  this.observer = new MutationObserver(() => this.place());
38
- this.observer.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["data-place", "hidden"] });
45
+ this.observer.observe(this, { childList: true, subtree: true, attributes: true, attributeFilter: ["data-place", "hidden"], attributeOldValue: false });
39
46
  }
40
47
 
41
48
  disconnectedCallback() {
@@ -753,7 +753,7 @@ export class Calendar extends CalendarBase {
753
753
  const name = this.label ? this.pickerWords(this.label, this.label) : this.pickerWords(undefined, "Date");
754
754
  const days = start ? (end ? `${start.day}/${end.day}` : start.day) : "";
755
755
  return html`<button
756
- class="ds-select trigger"
756
+ class="ds-input trigger"
757
757
  part="trigger"
758
758
  type="button"
759
759
  aria-haspopup="dialog"
@@ -764,9 +764,8 @@ export class Calendar extends CalendarBase {
764
764
  @click=${this.toggle}
765
765
  @keydown=${this.onTriggerKey}
766
766
  >
767
- <ds-icon class="icon" type="calendar" aria-hidden="true"></ds-icon>
768
767
  <span class="text">${text}</span>
769
- <ds-icon class="arrow" type="down" aria-hidden="true"></ds-icon>
768
+ <ds-icon class="arrow" type="chevron-down" size="large" aria-hidden="true"></ds-icon>
770
769
  </button>
771
770
  <div
772
771
  class="popover"
@@ -2,11 +2,12 @@
2
2
  /* The element's bento: the same as 1-root/bento.css's .ds-bento, on the host and its slotted tiles. */
3
3
 
4
4
  :host {
5
- --ds-bento-gap: calc(var(--ds-unit) / 2);
5
+ --ds-bento-unit: var(--ds-unit);
6
+ --ds-bento-gap: calc(var(--ds-bento-unit) / 2);
6
7
  box-sizing: border-box;
7
8
  display: grid;
8
9
  grid-template-columns: repeat(var(--ds-bento-columns, 3), minmax(0, 1fr));
9
- grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-unit))), auto);
10
+ grid-auto-rows: minmax(var(--ds-bento-row, calc(10 * var(--ds-bento-unit))), auto);
10
11
  grid-auto-flow: row dense;
11
12
  gap: var(--ds-bento-gap);
12
13
  }
@@ -38,15 +39,20 @@
38
39
  }
39
40
 
40
41
  :host([squares]) {
41
- --ds-bento-reach: calc(var(--ds-unit) / 4);
42
+ --ds-bento-reach: calc(var(--ds-bento-unit) / 4);
42
43
  /* Exactly its squares wide: each column one square. */
43
- width: calc(var(--ds-bento-columns, 48) * var(--ds-unit));
44
+ width: calc(var(--ds-bento-columns, 48) * var(--ds-bento-unit));
44
45
  max-width: none;
45
- grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-unit));
46
- grid-auto-rows: var(--ds-unit);
46
+ grid-template-columns: repeat(var(--ds-bento-columns, 48), var(--ds-bento-unit));
47
+ grid-auto-rows: var(--ds-bento-unit);
47
48
  grid-auto-flow: row;
48
49
  gap: 0;
49
50
  }
51
+ /* Fit: the columns share a measure narrower (or wider) than the squares, the rows still one square. */
52
+ :host([squares][fit]) {
53
+ width: auto;
54
+ grid-template-columns: repeat(var(--ds-bento-columns, 48), minmax(0, 1fr));
55
+ }
50
56
  :host([squares]) ::slotted(*) {
51
57
  --ds-bento-inset-top: calc(var(--ds-bento-reach) * var(--ds-bento-top, 0));
52
58
  --ds-bento-inset-end: calc(var(--ds-bento-reach) * var(--ds-bento-end, 0));
@@ -59,8 +65,8 @@
59
65
  /* A card grows its own padding by the reach (card.css); any other tile is padded here, a square inside. */
60
66
  :host([squares]) ::slotted(:not(.ds-card, ds-card)) {
61
67
  padding:
62
- calc(var(--ds-unit) + var(--ds-bento-inset-top))
63
- calc(var(--ds-unit) + var(--ds-bento-inset-end))
64
- calc(var(--ds-unit) + var(--ds-bento-inset-bottom))
65
- calc(var(--ds-unit) + var(--ds-bento-inset-start));
68
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-top))
69
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-end))
70
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-bottom))
71
+ calc(var(--ds-bento-padding, var(--ds-bento-unit)) + var(--ds-bento-inset-start));
66
72
  }
@@ -5,9 +5,9 @@
5
5
  * stands on the lower sixteen of its square. The boxes are hairlines centred
6
6
  * on the grid lines; today is a red disc nine tenths of a square across.
7
7
  *
8
- * A picker is the select's face: one control high at the foot of its square,
9
- * ten squares wide by default, the calendar icon at its start and the down
10
- * arrow at its end. Its month opens on the menu's frame, half a square from
8
+ * A picker is a field's face: one control high at the foot of its square,
9
+ * ten squares wide by default, its words 4px in and the chevron-down icon
10
+ * (16px, 2px from the end) at its end; a range is one value. Its month opens on the menu's frame, half a square from
11
11
  * the field: a 1px line, half a square inside it, no shadow, so eight squares
12
12
  * wide. Inside, on whole squares: the first and last day to type (each with
13
13
  * its time below when times are on), one square spare, the compact month one
@@ -282,15 +282,14 @@
282
282
 
283
283
  .trigger {
284
284
  display: inline-flex;
285
- align-items: flex-end;
285
+ align-items: center;
286
286
  gap: calc(4px * var(--ds-sf, 1));
287
287
  width: var(--ds-calendar-picker-width);
288
- padding-inline: 0 calc(4px * var(--ds-sf, 1));
288
+ padding-inline: calc(4px * var(--ds-sf, 1)) calc(2px * var(--ds-sf, 1));
289
289
  text-align: start;
290
290
  cursor: pointer;
291
291
  }
292
292
  .trigger:disabled { cursor: default; }
293
- .trigger .icon,
294
293
  .trigger .arrow { flex: 0 0 auto; }
295
294
  .trigger .text {
296
295
  flex: 1 1 auto;
@@ -300,7 +299,6 @@
300
299
  white-space: nowrap;
301
300
  }
302
301
  .trigger[data-empty] .text { color: var(--ds-title-color); }
303
- .trigger[aria-expanded="true"] .arrow { transform: rotate(180deg); }
304
302
 
305
303
  /* The month's panel, on the menu's frame. */
306
304
  .popover {
@@ -373,7 +371,6 @@
373
371
  .popover:popover-open {
374
372
  animation: ds-calendar-picker-in 140ms cubic-bezier(0.22, 1, 0.36, 1);
375
373
  }
376
- .trigger .arrow { transition: transform 140ms ease; }
377
374
  }
378
375
  @keyframes ds-calendar-picker-in {
379
376
  from { opacity: 0; transform: translateY(calc(-4px * var(--ds-sf, 1))); }
@@ -19,7 +19,9 @@
19
19
  * A tile's `data-place` is its square across, its square down, its width and
20
20
  * its height, in whole squares counted from 0. Tiles are placed a square
21
21
  * apart; a tile a square away from another, with the two overlapping along
22
- * that side, reaches towards it.
22
+ * that side, reaches towards it. A tile can have a place per layout,
23
+ * `data-place-phone="0 0 12 7"`, taken while the bento says
24
+ * `data-layout="phone"`; the page sets the layout and the columns for it.
23
25
  */
24
26
  /** A tile's place in squares: across, down, wide, high. */
25
27
  export type BentoPlace = readonly [x: number, y: number, w: number, h: number];
@@ -34,7 +36,9 @@ export interface BentoReach {
34
36
  export declare function bentoPlace(value: string | null | undefined): BentoPlace | undefined;
35
37
  /** For each place, the sides that face another tile across a one-square gap. */
36
38
  export declare function bentoReach(places: readonly BentoPlace[]): BentoReach[];
37
- /** Places one squares bento's tiles: their squares and their reach, as custom properties. */
39
+ /** A tile's place in the bento's layout: `data-place-<layout>` where the bento names one and the tile has it, else `data-place`. */
40
+ export declare function tilePlace(tile: HTMLElement, layout?: string): BentoPlace | undefined;
41
+ /** Places one squares bento's tiles: their squares and their reach, as custom properties. The bento's `data-layout` (or `layout`) picks each tile's place for that layout. */
38
42
  export declare function placeBento(bento: HTMLElement): void;
39
43
  /** Places every squares bento on the page (or under `root`), and again when its tiles change. */
40
44
  export declare function placeBentos(root?: ParentNode): () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"bento.d.ts","sourceRoot":"","sources":["../../DS1/0-face/bento.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAE/E,gEAAgE;AAChE,MAAM,WAAW,UAAU;IAAG,KAAK,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE;AAE3F,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAKnF;AAID,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,EAAE,CAUtE;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAYnD;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,IAAI,GAAE,UAAqB,GAAG,MAAM,IAAI,CAcnE"}
1
+ {"version":3,"file":"bento.d.ts","sourceRoot":"","sources":["../../DS1/0-face/bento.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAE/E,gEAAgE;AAChE,MAAM,WAAW,UAAU;IAAG,KAAK,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE;AAE3F,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAKnF;AAID,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,EAAE,CAUtE;AAED,oIAAoI;AACpI,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,SAAK,GAAG,UAAU,GAAG,SAAS,CAGhF;AAED,8KAA8K;AAC9K,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAanD;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,IAAI,GAAE,UAAqB,GAAG,MAAM,IAAI,CAcnE"}
@@ -19,7 +19,9 @@
19
19
  * A tile's `data-place` is its square across, its square down, its width and
20
20
  * its height, in whole squares counted from 0. Tiles are placed a square
21
21
  * apart; a tile a square away from another, with the two overlapping along
22
- * that side, reaches towards it.
22
+ * that side, reaches towards it. A tile can have a place per layout,
23
+ * `data-place-phone="0 0 12 7"`, taken while the bento says
24
+ * `data-layout="phone"`; the page sets the layout and the columns for it.
23
25
  */
24
26
  /** Reads `data-place` ("x y w h"); `undefined` unless it is four whole numbers with a size. */
25
27
  export function bentoPlace(value) {
@@ -42,10 +44,16 @@ export function bentoReach(places) {
42
44
  };
43
45
  });
44
46
  }
45
- /** Places one squares bento's tiles: their squares and their reach, as custom properties. */
47
+ /** A tile's place in the bento's layout: `data-place-<layout>` where the bento names one and the tile has it, else `data-place`. */
48
+ export function tilePlace(tile, layout = "") {
49
+ const own = layout ? tile.getAttribute(`data-place-${layout}`) : null;
50
+ return bentoPlace(own ?? tile.dataset.place);
51
+ }
52
+ /** Places one squares bento's tiles: their squares and their reach, as custom properties. The bento's `data-layout` (or `layout`) picks each tile's place for that layout. */
46
53
  export function placeBento(bento) {
54
+ const layout = bento.dataset.layout ?? bento.getAttribute("layout") ?? "";
47
55
  const tiles = [...bento.children].filter((child) => child instanceof HTMLElement && !child.hidden);
48
- const placed = tiles.map(tile => ({ tile, place: bentoPlace(tile.dataset.place) })).filter((entry) => !!entry.place);
56
+ const placed = tiles.map(tile => ({ tile, place: tilePlace(tile, layout) })).filter((entry) => !!entry.place);
49
57
  const reach = bentoReach(placed.map(entry => entry.place));
50
58
  placed.forEach(({ tile, place: [x, y, w, h] }, index) => {
51
59
  const sides = reach[index];
@@ -69,7 +77,7 @@ export function placeBentos(root = document) {
69
77
  });
70
78
  for (const bento of bentos) {
71
79
  placeBento(bento);
72
- observer.observe(bento, { childList: true, subtree: false, attributes: true, attributeFilter: ["data-place", "hidden"] });
80
+ observer.observe(bento, { childList: true, subtree: false, attributes: true, attributeFilter: ["data-place", "data-layout", "hidden"] });
73
81
  for (const tile of bento.children)
74
82
  observer.observe(tile, { attributes: true, attributeFilter: ["data-place", "hidden"] });
75
83
  }
@@ -1,6 +1,6 @@
1
1
  import { LitElement } from "lit";
2
- /** The shared switch face. The slotted button retains native activation and refs. */
3
- /** rounded selects a pill track, white circular thumb and darker-green on state. */
2
+ /** The switch: a pill with a white round thumb, grey when off and the darker green when on,
3
+ whatever the page's accent. The slotted button retains native activation and refs. */
4
4
  export declare class Switch extends LitElement {
5
5
  static styles: import("lit").CSSResult;
6
6
  focus(options?: FocusOptions): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ds-switch.d.ts","sourceRoot":"","sources":["../../DS1/2-core/ds-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,KAAK,CAAC;AAIlD,qFAAqF;AACrF,oFAAoF;AACpF,qBAAa,MAAO,SAAQ,UAAU;IACpC,MAAM,CAAC,MAAM,0BAAqB;IAClC,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAC5B,MAAM;CACP;AAGD,OAAO,CAAC,MAAM,CAAC;IAAE,UAAU,qBAAqB;QAAG,WAAW,EAAE,MAAM,CAAA;KAAE;CAAE"}
1
+ {"version":3,"file":"ds-switch.d.ts","sourceRoot":"","sources":["../../DS1/2-core/ds-switch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,KAAK,CAAC;AAIlD;yFACyF;AACzF,qBAAa,MAAO,SAAQ,UAAU;IACpC,MAAM,CAAC,MAAM,0BAAqB;IAClC,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY;IAC5B,MAAM;CACP;AAGD,OAAO,CAAC,MAAM,CAAC;IAAE,UAAU,qBAAqB;QAAG,WAAW,EAAE,MAAM,CAAA;KAAE;CAAE"}
@@ -1,8 +1,8 @@
1
1
  import { LitElement, html, unsafeCSS } from "lit";
2
2
  import { define } from "../0-face/define";
3
3
  import styles from "./styles/ds-switch.css?inline";
4
- /** The shared switch face. The slotted button retains native activation and refs. */
5
- /** rounded selects a pill track, white circular thumb and darker-green on state. */
4
+ /** The switch: a pill with a white round thumb, grey when off and the darker green when on,
5
+ whatever the page's accent. The slotted button retains native activation and refs. */
6
6
  export class Switch extends LitElement {
7
7
  focus(options) { this.querySelector(":scope > button")?.focus(options); }
8
8
  render() { return html `<slot></slot>`; }