contain-css-svelte 1.2.3 → 1.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.
Files changed (50) hide show
  1. package/dist/Card.svelte +216 -288
  2. package/dist/controls/Button.svelte +39 -1
  3. package/dist/controls/ButtonLink.svelte +39 -1
  4. package/dist/controls/Checkbox.svelte +38 -0
  5. package/dist/controls/CircleButton.svelte +39 -1
  6. package/dist/controls/Input.svelte +39 -1
  7. package/dist/controls/RadioButton.svelte +38 -0
  8. package/dist/controls/Select.svelte +38 -0
  9. package/dist/controls/Slider.svelte +39 -1
  10. package/dist/controls/TabItem.svelte +39 -1
  11. package/dist/controls/Toggle.svelte +39 -1
  12. package/dist/dropdowns/DropdownMenu.svelte +39 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +2 -1
  15. package/dist/layout/Accordion.svelte +39 -1
  16. package/dist/layout/Bar.svelte +49 -1
  17. package/dist/layout/ColumnContainer.svelte +39 -1
  18. package/dist/layout/Columns.svelte +39 -1
  19. package/dist/layout/Container.svelte +217 -292
  20. package/dist/layout/DataList.svelte +39 -1
  21. package/dist/layout/DataListItem.svelte +217 -292
  22. package/dist/layout/Fieldset.svelte +39 -1
  23. package/dist/layout/Form.svelte +217 -292
  24. package/dist/layout/FormItem.svelte +39 -1
  25. package/dist/layout/GridLayout.svelte +38 -0
  26. package/dist/layout/Hero.svelte +217 -292
  27. package/dist/layout/Inline.svelte +45 -1
  28. package/dist/layout/MenuList.svelte +39 -1
  29. package/dist/layout/Page.svelte +44 -2
  30. package/dist/layout/RowContainer.svelte +39 -1
  31. package/dist/layout/Sidebar.svelte +757 -65
  32. package/dist/layout/Sidebar.svelte.d.ts +58 -1
  33. package/dist/layout/SidebarContainer.svelte +198 -0
  34. package/dist/layout/SidebarContainer.svelte.d.ts +20 -0
  35. package/dist/layout/SplitPane.svelte +39 -1
  36. package/dist/layout/Stack.svelte +45 -1
  37. package/dist/layout/TabBar.svelte +39 -1
  38. package/dist/layout/Table.svelte +469 -443
  39. package/dist/layout/Tile.svelte +216 -291
  40. package/dist/misc/CodeInner.svelte +39 -1
  41. package/dist/misc/Progress.svelte +217 -292
  42. package/dist/misc/Tag.svelte +39 -1
  43. package/dist/overlays/Dialog.svelte +217 -292
  44. package/dist/overlays/Tooltip.svelte +267 -349
  45. package/dist/sass/_responsive.scss +15 -0
  46. package/dist/sass/_typography.scss +203 -191
  47. package/dist/typography/TextLayout.svelte +494 -292
  48. package/dist/vars/defaults.css +258 -0
  49. package/dist/vars/typography-context.css +271 -0
  50. package/package.json +1 -1
@@ -6,6 +6,63 @@ declare const Sidebar: import("svelte").Component<ContainProps<HTMLAttributes<HT
6
6
  left?: boolean;
7
7
  right?: boolean;
8
8
  children?: Snippet;
9
+ /**
10
+ * Float the panel *over* the page content at every width instead of
11
+ * widening the aside and pushing the content aside. Narrow/compact
12
+ * screens already overlay, so this only changes the wide layout.
13
+ *
14
+ * An overlay sidebar also takes the compact layout's affordance: a
15
+ * button that opens a sheet, starting shut. The grab-bar rail is for a
16
+ * panel that lives in the layout -- floating one over the content and
17
+ * asking someone to grab it is strange, and a panel that starts open on
18
+ * top of the content is worse.
19
+ */
20
+ overlay?: boolean;
21
+ /**
22
+ * Pin the sheet to the viewport while the page scrolls past it, instead
23
+ * of stretching it to the height of whatever it sits beside.
24
+ *
25
+ * Without it, an open sheet is as tall as its row -- right beside a
26
+ * short card, wrong beside a fifty-row table, where the top of the
27
+ * panel scrolls away and anything at its foot ends up off the bottom of
28
+ * the page. With it, the sheet (and its button) stick at
29
+ * `--sidebar-sheet-top` and stop growing at `--sidebar-sheet-max-height`,
30
+ * scrolling their own content past that.
31
+ *
32
+ * Applies wherever the sheet does: any `overlay` sidebar, and any
33
+ * sidebar in the compact layout. The wide rail is unaffected. Like any
34
+ * `position: sticky`, it needs every ancestor up to the scrolling one to
35
+ * leave `overflow` alone.
36
+ */
37
+ sticky?: boolean;
38
+ /**
39
+ * The shape of the sheet's toggle button (the sheet is what any
40
+ * `overlay` sidebar, and any sidebar in the compact layout, uses).
41
+ *
42
+ * - `"tab"` (default): the corners on the side it attaches to are
43
+ * square, so it reads as fastened to that edge -- the page edge while
44
+ * shut, the panel's edge while open. Right against a page edge.
45
+ * - `"button"`: rounded all round like any other button, for a sheet
46
+ * that does not sit against an edge -- beside a table, inside page
47
+ * padding -- where a half-flat tab looks broken.
48
+ *
49
+ * Per-state control, if you need it, is by variable:
50
+ * `--sidebar-sheet-expand-edge-radius` (the shut button) and
51
+ * `--sidebar-sheet-collapse-edge-radius` (the open one), both falling
52
+ * back to `--sidebar-sheet-edge-radius`.
53
+ */
54
+ sheetButton?: "tab" | "button";
55
+ /**
56
+ * Whether the sidebar is showing its panel. Bindable, so a caller can
57
+ * drive the sidebar from a button of their own:
58
+ * `<Sidebar bind:open />`.
59
+ *
60
+ * Left `undefined` (the default) the sidebar keeps its per-layout
61
+ * defaults -- the wide rail starts open, the compact sheet starts
62
+ * closed -- and the built-in toggles set it from there. Once it holds a
63
+ * boolean, that boolean wins in both layouts.
64
+ */
65
+ open?: boolean | undefined;
9
66
  /**
10
67
  * Accessible name for the button that opens the sidebar on narrow
11
68
  * screens, and for the one that collapses it once open. What the sidebar
@@ -14,6 +71,6 @@ declare const Sidebar: import("svelte").Component<ContainProps<HTMLAttributes<HT
14
71
  */
15
72
  expandLabel?: string;
16
73
  collapseLabel?: string;
17
- }, SidebarStyleProps & StyleProps<readonly ["bg", "fg", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant"]>>, {}, "">;
74
+ }, SidebarStyleProps & StyleProps<readonly ["bg", "fg", "fontFamily", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textTransform", "textDecoration", "fontVariant"]>>, {}, "open">;
18
75
  type Sidebar = ReturnType<typeof Sidebar>;
19
76
  export default Sidebar;
@@ -0,0 +1,198 @@
1
+ <script lang="ts">import { elementProps } from "../util";
2
+ import { COLOR_VARS, PADDING_VARS, RADIUS_VARS, } from "../styleProps";
3
+ let { right = false, children, class: className, ...restProps } = $props();
4
+ const SIDEBAR_CONTAINER_VARS = [
5
+ ...COLOR_VARS,
6
+ ...PADDING_VARS,
7
+ ...RADIUS_VARS,
8
+ ];
9
+ const el = $derived(elementProps(restProps, "sidebar-container", [
10
+ ...SIDEBAR_CONTAINER_VARS,
11
+ "width",
12
+ "height",
13
+ "gap",
14
+ ]));
15
+ </script>
16
+
17
+ <div class={["sidebar-container", className]} class:right {...el}>
18
+ {@render children?.()}
19
+ </div>
20
+
21
+ <style>/* Per-level heading (h1-h6) box/typography properties, resolved to PRIVATE,
22
+ inheriting custom properties (--_h1-color, --_h2-font-size, etc) rather than
23
+ assigned directly to a matched h1-h6 selector. Nothing in this file matches
24
+ an actual heading element anymore -- see typography-context.css (vars/), which
25
+ is the single, global, :where()-scoped rule that actually reads these vars
26
+ and applies them to real elements. That split is what lets a component
27
+ nested arbitrarily deep (through <article>, <Tile>, whatever) still get the
28
+ nearest ancestor's heading styling: these are ordinary inherited custom
29
+ properties, so DOM proximity decides which component's values apply, not
30
+ selector specificity or stylesheet order. See AGENTS-INTERNAL.md. */
31
+ /* All six heading levels' context vars in one call -- what every
32
+ "typography container" component (Container, Card, Tile, TextLayout, ...)
33
+ includes on itself once, alongside the shared --_heading-* vars below. */
34
+ /* Shared prose-measure group: p, blockquote, dl, ul, ol. li/dt/dd don't get
35
+ their own vars -- they're never wider than their ul/ol/dl parent's own
36
+ max-width box, so they're already bounded for free by ordinary block
37
+ layout, not by anything selector-based reaching them individually. */
38
+ /* p specifically also gets the fuller typography-props-bare treatment
39
+ (paragraph-prefixed), which -- same as in the original selector-based
40
+ version -- is declared/consumed AFTER the shared prose vars above, so it
41
+ wins for whichever properties both groups set. */
42
+ /* The first paragraph in a typography context (p:first-of-type, or a p right
43
+ after a heading) gets its own, slightly different treatment -- larger lede
44
+ text, no top margin. Structural matching (:first-of-type, `h1 + p`) still
45
+ has to happen where the real element is, in the global consumer rule; only
46
+ the VALUES move to context vars here. */
47
+ /* Logical, not top/bottom/left/right: margin-block/margin-inline already take
48
+ one value (both sides equal) or two (start end), so there is no separate
49
+ "which side" prop to remember and no 4-value shorthand order to get wrong.
50
+ Defaults to 0 on purpose -- unlike padding-props above, a margin that
51
+ appeared by default on every consumer would be a silent layout change the
52
+ day this mixin got added to a new component. Callers opt in with an actual
53
+ value. (Container does not use this mixin: it wants --gap/auto as its
54
+ defaults, which do not fit the "0 unless asked" contract here.) */
55
+ /* The width at or below which a Sidebar swaps its grab-bar rail for the sheet
56
+ affordance -- a floating button that opens a panel over the content.
57
+
58
+ Page has to agree with Sidebar about this, because Page is what floats the
59
+ aside out of flow and reserves the strip of padding the sheet button sits
60
+ in. They used to disagree: Sidebar switched at 512px and Page at 600px,
61
+ which left a band between 513 and 600 where Page had already lifted the
62
+ aside out of the layout while the Sidebar inside it was still showing a
63
+ rail -- a grab bar floating on top of the content, which is the affordance
64
+ we deliberately avoid everywhere else.
65
+
66
+ One definition, used by both, so they cannot drift again. */
67
+ /* Warning: because we define a fallback
68
+ media query, the media query can override the container
69
+ if we stack a bunch of these in a row and aren't thoughtful about the order.
70
+ Put min-width queries *after* max-width queries so that smaller
71
+ container queries don't get their styles overridden by large media queries.
72
+ */
73
+ /* Convenience groupings */
74
+ .sidebar-container {
75
+ --link-bg: var(--sidebar-container-link-bg, var(--surface-link-bg, inherit));
76
+ --link-fg: var(--sidebar-container-link-fg, var(--surface-link-fg, inherit));
77
+ --_bg-mix-color: var(--sidebar-container-bg-mix-color, var(--surface-bg-mix-color, var(--bg-mix-color, transparent)));
78
+ --_bg-mix-amount: var(--sidebar-container-bg-mix-amount, var(--surface-bg-mix-amount, var(--bg-mix-amount, 0%)));
79
+ --_fg-mix-color: var(--sidebar-container-fg-mix-color, var(--surface-fg-mix-color, var(--fg-mix-color, transparent)));
80
+ --_fg-mix-amount: var(--sidebar-container-fg-mix-amount, var(--surface-fg-mix-amount, var(--fg-mix-amount, 0%)));
81
+ --_bg-base: var(--sidebar-container-bg, var(--surface-bg, var(--bg, unset)));
82
+ --_fg-base: var(--sidebar-container-fg, var(--surface-fg, var(--fg, unset)));
83
+ --_background-color: color-mix(
84
+ in srgb,
85
+ var(--_bg-base),
86
+ var(--_bg-mix-color) var(--_bg-mix-amount)
87
+ );
88
+ --_color: color-mix(
89
+ in srgb,
90
+ var(--_fg-base),
91
+ var(--_fg-mix-color) var(--_fg-mix-amount)
92
+ );
93
+ --muted-color: var(--muted-color-override, var(--_background-color));
94
+ --primary-text-fg: var(
95
+ --primary-text-fg-override,
96
+ color-mix(
97
+ in srgb,
98
+ var(--_color),
99
+ var(--primary-color)
100
+ var(--primary-text-amount, var(--text-amount, 50%))
101
+ )
102
+ );
103
+ --secondary-text-fg: var(
104
+ --secondary-text-fg-override,
105
+ color-mix(
106
+ in srgb,
107
+ var(--_color),
108
+ var(--secondary-color)
109
+ var(--secondary-text-amount, var(--text-amount, 50%))
110
+ )
111
+ );
112
+ --info-text-fg: var(
113
+ --info-text-fg-override,
114
+ color-mix(
115
+ in srgb,
116
+ var(--_color),
117
+ var(--info-color)
118
+ var(--info-text-amount, var(--text-amount, 50%))
119
+ )
120
+ );
121
+ --success-text-fg: var(
122
+ --success-text-fg-override,
123
+ color-mix(
124
+ in srgb,
125
+ var(--_color),
126
+ var(--success-color)
127
+ var(--success-text-amount, var(--text-amount, 50%))
128
+ )
129
+ );
130
+ --warning-text-fg: var(
131
+ --warning-text-fg-override,
132
+ color-mix(
133
+ in srgb,
134
+ var(--_color),
135
+ var(--warning-color)
136
+ var(--warning-text-amount, var(--text-amount, 50%))
137
+ )
138
+ );
139
+ --danger-text-fg: var(
140
+ --danger-text-fg-override,
141
+ color-mix(
142
+ in srgb,
143
+ var(--_color),
144
+ var(--danger-color)
145
+ var(--danger-text-amount, var(--text-amount, 50%))
146
+ )
147
+ );
148
+ --muted-text-fg: var(
149
+ --muted-text-fg-override,
150
+ color-mix(
151
+ in srgb,
152
+ var(--_color),
153
+ var(--muted-color)
154
+ var(--muted-text-amount, var(--text-amount, 50%))
155
+ )
156
+ );
157
+ background-color: var(--_background-color);
158
+ color: var(--_color);
159
+ box-sizing: border-box;
160
+ --_padding: var(--sidebar-container-padding, var(--padding, 4px));
161
+ padding: var(--_padding);
162
+ border: var(--sidebar-container-border, var(--border, inherit));
163
+ border-width: var(--sidebar-container-border-width, var(--__missing-border-width));
164
+ border-style: var(--sidebar-container-border-style, var(--__missing-border-style));
165
+ border-color: var(--sidebar-container-border-color, var(--__missing-border-color));
166
+ border-top: var(--sidebar-container-border-top, var(--border-top, var(--sidebar-container-border, var(--border, none))));
167
+ border-right: var(--sidebar-container-border-right, var(--border-right, var(--sidebar-container-border, var(--border, none))));
168
+ border-bottom: var(--sidebar-container-border-bottom, var(--border-bottom, var(--sidebar-container-border, var(--border, none))));
169
+ border-left: var(--sidebar-container-border-left, var(--border-left, var(--sidebar-container-border, var(--border, none))));
170
+ border-radius: var(--sidebar-container-border-radius, var(--border-radius, none));
171
+ /* (1) so the Sidebar's container queries have something to measure */
172
+ container-type: inline-size;
173
+ /* (3) so the content sits beside the sidebar, not under it */
174
+ display: flex;
175
+ gap: var(--sidebar-container-gap, 0);
176
+ /* so an overlay sheet anchors here rather than escaping up the tree */
177
+ position: relative;
178
+ box-sizing: border-box;
179
+ width: var(--sidebar-container-width, 100%);
180
+ /* (2) a height to fill. `auto` would collapse, because a collapsed
181
+ sidebar has no in-flow content of its own. */
182
+ height: var(--sidebar-container-height, 100%);
183
+ min-height: var(--sidebar-container-min-height, 0);
184
+ /* Deliberately NOT `overflow: hidden`: that is what makes an overlay
185
+ sheet vanish inside a <Container>. */
186
+ }
187
+
188
+ .sidebar-container.right {
189
+ flex-direction: row-reverse;
190
+ }
191
+
192
+ /* The content beside the sidebar takes the remaining width and scrolls on
193
+ its own, so a long page does not stretch the sidebar past the viewport. */
194
+ .sidebar-container > :global(:not(aside)) {
195
+ flex: 1 1 auto;
196
+ min-width: 0;
197
+ overflow: auto;
198
+ }</style>
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { ContainProps } from "../types";
4
+ import { type StyleProps } from "../styleProps";
5
+ declare const SidebarContainer: import("svelte").Component<ContainProps<HTMLAttributes<HTMLDivElement>, {
6
+ /** Put the sidebar after the content in the flex row. Pair with
7
+ * `<Sidebar right />`, which is what draws its border and rail on the
8
+ * correct edge. */
9
+ right?: boolean;
10
+ children?: Snippet;
11
+ }, StyleProps<readonly ["bg", "fg", "padding", "borderRadius"]> & {
12
+ /** Shorthands for --sidebar-container-{width,height,gap}. Height
13
+ * matters: a collapsed sidebar has no in-flow content, so an auto
14
+ * height collapses to nothing. */
15
+ width?: string | null;
16
+ height?: string | null;
17
+ gap?: string | null;
18
+ }>, {}, "">;
19
+ type SidebarContainer = ReturnType<typeof SidebarContainer>;
20
+ export default SidebarContainer;
@@ -116,7 +116,33 @@ onMount(() => {
116
116
  </div>
117
117
  </div>
118
118
 
119
- <style>/* Logical, not top/bottom/left/right: margin-block/margin-inline already take
119
+ <style>/* Per-level heading (h1-h6) box/typography properties, resolved to PRIVATE,
120
+ inheriting custom properties (--_h1-color, --_h2-font-size, etc) rather than
121
+ assigned directly to a matched h1-h6 selector. Nothing in this file matches
122
+ an actual heading element anymore -- see typography-context.css (vars/), which
123
+ is the single, global, :where()-scoped rule that actually reads these vars
124
+ and applies them to real elements. That split is what lets a component
125
+ nested arbitrarily deep (through <article>, <Tile>, whatever) still get the
126
+ nearest ancestor's heading styling: these are ordinary inherited custom
127
+ properties, so DOM proximity decides which component's values apply, not
128
+ selector specificity or stylesheet order. See AGENTS-INTERNAL.md. */
129
+ /* All six heading levels' context vars in one call -- what every
130
+ "typography container" component (Container, Card, Tile, TextLayout, ...)
131
+ includes on itself once, alongside the shared --_heading-* vars below. */
132
+ /* Shared prose-measure group: p, blockquote, dl, ul, ol. li/dt/dd don't get
133
+ their own vars -- they're never wider than their ul/ol/dl parent's own
134
+ max-width box, so they're already bounded for free by ordinary block
135
+ layout, not by anything selector-based reaching them individually. */
136
+ /* p specifically also gets the fuller typography-props-bare treatment
137
+ (paragraph-prefixed), which -- same as in the original selector-based
138
+ version -- is declared/consumed AFTER the shared prose vars above, so it
139
+ wins for whichever properties both groups set. */
140
+ /* The first paragraph in a typography context (p:first-of-type, or a p right
141
+ after a heading) gets its own, slightly different treatment -- larger lede
142
+ text, no top margin. Structural matching (:first-of-type, `h1 + p`) still
143
+ has to happen where the real element is, in the global consumer rule; only
144
+ the VALUES move to context vars here. */
145
+ /* Logical, not top/bottom/left/right: margin-block/margin-inline already take
120
146
  one value (both sides equal) or two (start end), so there is no separate
121
147
  "which side" prop to remember and no 4-value shorthand order to get wrong.
122
148
  Defaults to 0 on purpose -- unlike padding-props above, a margin that
@@ -124,6 +150,18 @@ onMount(() => {
124
150
  day this mixin got added to a new component. Callers opt in with an actual
125
151
  value. (Container does not use this mixin: it wants --gap/auto as its
126
152
  defaults, which do not fit the "0 unless asked" contract here.) */
153
+ /* The width at or below which a Sidebar swaps its grab-bar rail for the sheet
154
+ affordance -- a floating button that opens a panel over the content.
155
+
156
+ Page has to agree with Sidebar about this, because Page is what floats the
157
+ aside out of flow and reserves the strip of padding the sheet button sits
158
+ in. They used to disagree: Sidebar switched at 512px and Page at 600px,
159
+ which left a band between 513 and 600 where Page had already lifted the
160
+ aside out of the layout while the Sidebar inside it was still showing a
161
+ rail -- a grab bar floating on top of the content, which is the affordance
162
+ we deliberately avoid everywhere else.
163
+
164
+ One definition, used by both, so they cannot drift again. */
127
165
  /* Warning: because we define a fallback
128
166
  media query, the media query can override the container
129
167
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -32,7 +32,33 @@ const el = $derived(elementProps({ justify, align: resolvedAlign, gap, ...restPr
32
32
  {@render children?.()}
33
33
  </div>
34
34
 
35
- <style>/* Logical, not top/bottom/left/right: margin-block/margin-inline already take
35
+ <style>/* Per-level heading (h1-h6) box/typography properties, resolved to PRIVATE,
36
+ inheriting custom properties (--_h1-color, --_h2-font-size, etc) rather than
37
+ assigned directly to a matched h1-h6 selector. Nothing in this file matches
38
+ an actual heading element anymore -- see typography-context.css (vars/), which
39
+ is the single, global, :where()-scoped rule that actually reads these vars
40
+ and applies them to real elements. That split is what lets a component
41
+ nested arbitrarily deep (through <article>, <Tile>, whatever) still get the
42
+ nearest ancestor's heading styling: these are ordinary inherited custom
43
+ properties, so DOM proximity decides which component's values apply, not
44
+ selector specificity or stylesheet order. See AGENTS-INTERNAL.md. */
45
+ /* All six heading levels' context vars in one call -- what every
46
+ "typography container" component (Container, Card, Tile, TextLayout, ...)
47
+ includes on itself once, alongside the shared --_heading-* vars below. */
48
+ /* Shared prose-measure group: p, blockquote, dl, ul, ol. li/dt/dd don't get
49
+ their own vars -- they're never wider than their ul/ol/dl parent's own
50
+ max-width box, so they're already bounded for free by ordinary block
51
+ layout, not by anything selector-based reaching them individually. */
52
+ /* p specifically also gets the fuller typography-props-bare treatment
53
+ (paragraph-prefixed), which -- same as in the original selector-based
54
+ version -- is declared/consumed AFTER the shared prose vars above, so it
55
+ wins for whichever properties both groups set. */
56
+ /* The first paragraph in a typography context (p:first-of-type, or a p right
57
+ after a heading) gets its own, slightly different treatment -- larger lede
58
+ text, no top margin. Structural matching (:first-of-type, `h1 + p`) still
59
+ has to happen where the real element is, in the global consumer rule; only
60
+ the VALUES move to context vars here. */
61
+ /* Logical, not top/bottom/left/right: margin-block/margin-inline already take
36
62
  one value (both sides equal) or two (start end), so there is no separate
37
63
  "which side" prop to remember and no 4-value shorthand order to get wrong.
38
64
  Defaults to 0 on purpose -- unlike padding-props above, a margin that
@@ -40,6 +66,18 @@ const el = $derived(elementProps({ justify, align: resolvedAlign, gap, ...restPr
40
66
  day this mixin got added to a new component. Callers opt in with an actual
41
67
  value. (Container does not use this mixin: it wants --gap/auto as its
42
68
  defaults, which do not fit the "0 unless asked" contract here.) */
69
+ /* The width at or below which a Sidebar swaps its grab-bar rail for the sheet
70
+ affordance -- a floating button that opens a panel over the content.
71
+
72
+ Page has to agree with Sidebar about this, because Page is what floats the
73
+ aside out of flow and reserves the strip of padding the sheet button sits
74
+ in. They used to disagree: Sidebar switched at 512px and Page at 600px,
75
+ which left a band between 513 and 600 where Page had already lifted the
76
+ aside out of the layout while the Sidebar inside it was still showing a
77
+ rail -- a grab bar floating on top of the content, which is the affordance
78
+ we deliberately avoid everywhere else.
79
+
80
+ One definition, used by both, so they cannot drift again. */
43
81
  /* Warning: because we define a fallback
44
82
  media query, the media query can override the container
45
83
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -60,6 +98,12 @@ const el = $derived(elementProps({ justify, align: resolvedAlign, gap, ...restPr
60
98
  border-bottom: var(--stack-border-bottom, var(--border-bottom, var(--stack-border, var(--border, none))));
61
99
  border-left: var(--stack-border-left, var(--border-left, var(--stack-border, var(--border, none))));
62
100
  border-radius: var(--stack-border-radius, var(--border-radius, none));
101
+ /* A layout helper, not a surface: padding comes only from
102
+ --stack-padding (or the `padding` prop), never from the theme's
103
+ --padding. box-props falls back to --padding, which is inherited, so
104
+ without this every Stack picked up the page's padding -- or
105
+ whatever padding an enclosing Card set. */
106
+ --_padding: var(--stack-padding, 0);
63
107
  --_margin-block: var(--stack-margin-block, var(--margin-block, 0));
64
108
  --_margin-inline: var(--stack-margin-inline, var(--margin-inline, 0));
65
109
  margin-block: var(--_margin-block);
@@ -46,7 +46,33 @@ let lastActive = $state(active);
46
46
  </Bar>
47
47
  </div>
48
48
 
49
- <style>/* Logical, not top/bottom/left/right: margin-block/margin-inline already take
49
+ <style>/* Per-level heading (h1-h6) box/typography properties, resolved to PRIVATE,
50
+ inheriting custom properties (--_h1-color, --_h2-font-size, etc) rather than
51
+ assigned directly to a matched h1-h6 selector. Nothing in this file matches
52
+ an actual heading element anymore -- see typography-context.css (vars/), which
53
+ is the single, global, :where()-scoped rule that actually reads these vars
54
+ and applies them to real elements. That split is what lets a component
55
+ nested arbitrarily deep (through <article>, <Tile>, whatever) still get the
56
+ nearest ancestor's heading styling: these are ordinary inherited custom
57
+ properties, so DOM proximity decides which component's values apply, not
58
+ selector specificity or stylesheet order. See AGENTS-INTERNAL.md. */
59
+ /* All six heading levels' context vars in one call -- what every
60
+ "typography container" component (Container, Card, Tile, TextLayout, ...)
61
+ includes on itself once, alongside the shared --_heading-* vars below. */
62
+ /* Shared prose-measure group: p, blockquote, dl, ul, ol. li/dt/dd don't get
63
+ their own vars -- they're never wider than their ul/ol/dl parent's own
64
+ max-width box, so they're already bounded for free by ordinary block
65
+ layout, not by anything selector-based reaching them individually. */
66
+ /* p specifically also gets the fuller typography-props-bare treatment
67
+ (paragraph-prefixed), which -- same as in the original selector-based
68
+ version -- is declared/consumed AFTER the shared prose vars above, so it
69
+ wins for whichever properties both groups set. */
70
+ /* The first paragraph in a typography context (p:first-of-type, or a p right
71
+ after a heading) gets its own, slightly different treatment -- larger lede
72
+ text, no top margin. Structural matching (:first-of-type, `h1 + p`) still
73
+ has to happen where the real element is, in the global consumer rule; only
74
+ the VALUES move to context vars here. */
75
+ /* Logical, not top/bottom/left/right: margin-block/margin-inline already take
50
76
  one value (both sides equal) or two (start end), so there is no separate
51
77
  "which side" prop to remember and no 4-value shorthand order to get wrong.
52
78
  Defaults to 0 on purpose -- unlike padding-props above, a margin that
@@ -54,6 +80,18 @@ let lastActive = $state(active);
54
80
  day this mixin got added to a new component. Callers opt in with an actual
55
81
  value. (Container does not use this mixin: it wants --gap/auto as its
56
82
  defaults, which do not fit the "0 unless asked" contract here.) */
83
+ /* The width at or below which a Sidebar swaps its grab-bar rail for the sheet
84
+ affordance -- a floating button that opens a panel over the content.
85
+
86
+ Page has to agree with Sidebar about this, because Page is what floats the
87
+ aside out of flow and reserves the strip of padding the sheet button sits
88
+ in. They used to disagree: Sidebar switched at 512px and Page at 600px,
89
+ which left a band between 513 and 600 where Page had already lifted the
90
+ aside out of the layout while the Sidebar inside it was still showing a
91
+ rail -- a grab bar floating on top of the content, which is the affordance
92
+ we deliberately avoid everywhere else.
93
+
94
+ One definition, used by both, so they cannot drift again. */
57
95
  /* Warning: because we define a fallback
58
96
  media query, the media query can override the container
59
97
  if we stack a bunch of these in a row and aren't thoughtful about the order.