contain-css-svelte 1.4.3 → 1.5.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 (49) hide show
  1. package/dist/Card.svelte +57 -3
  2. package/dist/controls/Button.svelte +32 -0
  3. package/dist/controls/ButtonLink.svelte +32 -0
  4. package/dist/controls/Checkbox.svelte +36 -0
  5. package/dist/controls/CircleButton.svelte +32 -0
  6. package/dist/controls/Input.svelte +32 -0
  7. package/dist/controls/RadioButton.svelte +36 -1
  8. package/dist/controls/Select.svelte +35 -0
  9. package/dist/controls/Slider.svelte +32 -0
  10. package/dist/controls/TabItem.svelte +36 -0
  11. package/dist/controls/Toggle.svelte +32 -0
  12. package/dist/dropdowns/DropdownMenu.svelte +53 -1
  13. package/dist/layout/Accordion.svelte +32 -0
  14. package/dist/layout/Bar.svelte +50 -0
  15. package/dist/layout/ColumnContainer.svelte +32 -0
  16. package/dist/layout/Columns.svelte +32 -0
  17. package/dist/layout/Container.svelte +48 -2
  18. package/dist/layout/DataList.svelte +33 -1
  19. package/dist/layout/DataList.svelte.d.ts +7 -0
  20. package/dist/layout/DataListItem.svelte +56 -2
  21. package/dist/layout/Fieldset.svelte +32 -0
  22. package/dist/layout/Form.svelte +32 -0
  23. package/dist/layout/FormItem.svelte +46 -0
  24. package/dist/layout/GridLayout.svelte +59 -0
  25. package/dist/layout/Hero.svelte +42 -0
  26. package/dist/layout/Inline.svelte +37 -1
  27. package/dist/layout/MenuList.svelte +32 -0
  28. package/dist/layout/Page.svelte +137 -10
  29. package/dist/layout/Page.svelte.d.ts +17 -0
  30. package/dist/layout/RowContainer.svelte +32 -0
  31. package/dist/layout/Sidebar.svelte +104 -56
  32. package/dist/layout/SidebarContainer.svelte +32 -0
  33. package/dist/layout/SplitPane.svelte +32 -0
  34. package/dist/layout/Stack.svelte +32 -0
  35. package/dist/layout/TabBar.svelte +127 -8
  36. package/dist/layout/TabBar.svelte.d.ts +16 -0
  37. package/dist/layout/Table.svelte +60 -9
  38. package/dist/layout/Tile.svelte +89 -6
  39. package/dist/misc/CodeInner.svelte +32 -0
  40. package/dist/misc/Progress.svelte +32 -0
  41. package/dist/misc/Tag.svelte +32 -0
  42. package/dist/overlays/Dialog.svelte +32 -0
  43. package/dist/overlays/Tooltip.svelte +32 -0
  44. package/dist/sass/_responsive.scss +43 -0
  45. package/dist/typography/TextLayout.svelte +47 -0
  46. package/dist/vars/defaults.css +4 -1
  47. package/dist/vars/layout.css +4 -1
  48. package/dist/vars/responsive-typography.css +4 -1
  49. package/package.json +1 -1
package/dist/Card.svelte CHANGED
@@ -112,6 +112,38 @@ let hasFooter = $derived(Boolean(footer));
112
112
  we deliberately avoid everywhere else.
113
113
 
114
114
  One definition, used by both, so they cannot drift again. */
115
+ /* The "small" size tier: a component whose container is this wide or less
116
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
117
+
118
+ The convention, shared by every component that has a size worth changing
119
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
120
+
121
+ --{component}-{property}-small
122
+
123
+ applies inside a small container. What wins there, in order:
124
+ 1. the `-small` variable, if you set it;
125
+ 2. otherwise the regular variable, if you set it -- a size you chose on
126
+ purpose is not overridden behind your back;
127
+ 3. otherwise the component's own small default, which for most
128
+ properties is simply its regular default.
129
+
130
+ Container queries can't read a custom property, so the breakpoint itself
131
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
132
+ which already switched there. (The Sidebar's rail-to-sheet switch,
133
+ above, is a separate, layout-chrome decision and keeps its own value.) */
134
+ /* Styles for the small tier: the nearest container is narrow, OR the
135
+ viewport is.
136
+
137
+ The container query is the real answer -- a Tile in a 400px pane on a
138
+ desktop is small. But a container query only matches inside an ancestor
139
+ that *is* a container, and a component dropped straight into a page (no
140
+ Page, no Container around it) has none, so on a phone it would never
141
+ find out. The viewport query covers that: a narrow viewport means every
142
+ container in it is narrow too, so the two never disagree in the
143
+ direction that matters.
144
+
145
+ An element never queries itself, so on a component that is its own
146
+ container (Tile, Bar) this asks about the space it was given. */
115
147
  /* Warning: because we define a fallback
116
148
  media query, the media query can override the container
117
149
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -128,6 +160,15 @@ let hasFooter = $derived(Boolean(footer));
128
160
  overflow-x: hidden;
129
161
  container-type: inline-size;
130
162
  width: var(--w);
163
+ /* --card-width is the size a Card *wants*; it never gets to push past
164
+ its container. `stretch` is "whatever the parent leaves after my
165
+ margins", so a 250px card in a 200px pane just becomes a narrower
166
+ card -- whose own container queries then take it from there. The
167
+ prefixed lines cover browsers that only know the old keyword. */
168
+ max-width: 100%;
169
+ max-width: -moz-available;
170
+ max-width: -webkit-fill-available;
171
+ max-width: stretch;
131
172
  /* Was a single `margin` shorthand (--card-margin, 16px on every side).
132
173
  Split into block/inline -- same default on each axis, so nothing
133
174
  visually changes for existing callers -- but now a caller who wants
@@ -887,7 +928,16 @@ section {
887
928
 
888
929
  /* ── Container queries ──────────────────────────────────── */
889
930
  /* NOTE: .card targets the *parent* container; children target the card itself */
890
- /* Parent context: small — adjust card sizing vars */
931
+ /* Parent context: small (the shared small tier, $small-max -- a small
932
+ container, or a small viewport when there is no container) — adjust
933
+ card sizing vars */
934
+ @media (max-width: 600px) {
935
+ .card {
936
+ --w: var(--card-width-small);
937
+ --h: var(--card-height-small);
938
+ --sidebar-width: calc(var(--card-width-small) - var(--_padding) * 2);
939
+ }
940
+ }
891
941
  @container (max-width: 600px) {
892
942
  .card {
893
943
  --w: var(--card-width-small);
@@ -898,7 +948,9 @@ section {
898
948
  /* Card itself: narrow (≤ --card-width-small: 250px) — tighten typography and spacing */
899
949
  @container (max-width: 300px) {
900
950
  .card section {
901
- font-size: var(--card-font-size-small, calc(0.875 * var(--_font-size)));
951
+ /* Opt-in only: a narrow card is usually a phone, and text should not
952
+ shrink there. */
953
+ font-size: var(--card-font-size-small, var(--_font-size));
902
954
  }
903
955
  .card header,
904
956
  .card section {
@@ -915,7 +967,9 @@ section {
915
967
  /* Card itself: wide (≥ --card-width-large: 600px) — expand typography and spacing */
916
968
  @container (min-width: 500px) {
917
969
  .card section {
918
- font-size: var(--card-font-size-large, calc(1.125 * var(--_font-size)));
970
+ /* Opt-in only: a card's width is a layout fact, not a reason for its
971
+ text to be a different size from the text beside it. */
972
+ font-size: var(--card-font-size-large, var(--_font-size));
919
973
  }
920
974
  .card header,
921
975
  .card section {
@@ -107,6 +107,38 @@ const el = $derived(elementProps(restProps, "button", [
107
107
  we deliberately avoid everywhere else.
108
108
 
109
109
  One definition, used by both, so they cannot drift again. */
110
+ /* The "small" size tier: a component whose container is this wide or less
111
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
112
+
113
+ The convention, shared by every component that has a size worth changing
114
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
115
+
116
+ --{component}-{property}-small
117
+
118
+ applies inside a small container. What wins there, in order:
119
+ 1. the `-small` variable, if you set it;
120
+ 2. otherwise the regular variable, if you set it -- a size you chose on
121
+ purpose is not overridden behind your back;
122
+ 3. otherwise the component's own small default, which for most
123
+ properties is simply its regular default.
124
+
125
+ Container queries can't read a custom property, so the breakpoint itself
126
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
127
+ which already switched there. (The Sidebar's rail-to-sheet switch,
128
+ above, is a separate, layout-chrome decision and keeps its own value.) */
129
+ /* Styles for the small tier: the nearest container is narrow, OR the
130
+ viewport is.
131
+
132
+ The container query is the real answer -- a Tile in a 400px pane on a
133
+ desktop is small. But a container query only matches inside an ancestor
134
+ that *is* a container, and a component dropped straight into a page (no
135
+ Page, no Container around it) has none, so on a phone it would never
136
+ find out. The viewport query covers that: a narrow viewport means every
137
+ container in it is narrow too, so the two never disagree in the
138
+ direction that matters.
139
+
140
+ An element never queries itself, so on a component that is its own
141
+ container (Tile, Bar) this asks about the space it was given. */
110
142
  /* Warning: because we define a fallback
111
143
  media query, the media query can override the container
112
144
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -109,6 +109,38 @@ const iconSlotted = $derived(Boolean(icon));
109
109
  we deliberately avoid everywhere else.
110
110
 
111
111
  One definition, used by both, so they cannot drift again. */
112
+ /* The "small" size tier: a component whose container is this wide or less
113
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
114
+
115
+ The convention, shared by every component that has a size worth changing
116
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
117
+
118
+ --{component}-{property}-small
119
+
120
+ applies inside a small container. What wins there, in order:
121
+ 1. the `-small` variable, if you set it;
122
+ 2. otherwise the regular variable, if you set it -- a size you chose on
123
+ purpose is not overridden behind your back;
124
+ 3. otherwise the component's own small default, which for most
125
+ properties is simply its regular default.
126
+
127
+ Container queries can't read a custom property, so the breakpoint itself
128
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
129
+ which already switched there. (The Sidebar's rail-to-sheet switch,
130
+ above, is a separate, layout-chrome decision and keeps its own value.) */
131
+ /* Styles for the small tier: the nearest container is narrow, OR the
132
+ viewport is.
133
+
134
+ The container query is the real answer -- a Tile in a 400px pane on a
135
+ desktop is small. But a container query only matches inside an ancestor
136
+ that *is* a container, and a component dropped straight into a page (no
137
+ Page, no Container around it) has none, so on a phone it would never
138
+ find out. The viewport query covers that: a narrow viewport means every
139
+ container in it is narrow too, so the two never disagree in the
140
+ direction that matters.
141
+
142
+ An element never queries itself, so on a component that is its own
143
+ container (Tile, Bar) this asks about the space it was given. */
112
144
  /* Warning: because we define a fallback
113
145
  media query, the media query can override the container
114
146
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -135,6 +135,38 @@ let ref = $state(null);
135
135
  we deliberately avoid everywhere else.
136
136
 
137
137
  One definition, used by both, so they cannot drift again. */
138
+ /* The "small" size tier: a component whose container is this wide or less
139
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
140
+
141
+ The convention, shared by every component that has a size worth changing
142
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
143
+
144
+ --{component}-{property}-small
145
+
146
+ applies inside a small container. What wins there, in order:
147
+ 1. the `-small` variable, if you set it;
148
+ 2. otherwise the regular variable, if you set it -- a size you chose on
149
+ purpose is not overridden behind your back;
150
+ 3. otherwise the component's own small default, which for most
151
+ properties is simply its regular default.
152
+
153
+ Container queries can't read a custom property, so the breakpoint itself
154
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
155
+ which already switched there. (The Sidebar's rail-to-sheet switch,
156
+ above, is a separate, layout-chrome decision and keeps its own value.) */
157
+ /* Styles for the small tier: the nearest container is narrow, OR the
158
+ viewport is.
159
+
160
+ The container query is the real answer -- a Tile in a 400px pane on a
161
+ desktop is small. But a container query only matches inside an ancestor
162
+ that *is* a container, and a component dropped straight into a page (no
163
+ Page, no Container around it) has none, so on a phone it would never
164
+ find out. The viewport query covers that: a narrow viewport means every
165
+ container in it is narrow too, so the two never disagree in the
166
+ direction that matters.
167
+
168
+ An element never queries itself, so on a component that is its own
169
+ container (Tile, Bar) this asks about the space it was given. */
138
170
  /* Warning: because we define a fallback
139
171
  media query, the media query can override the container
140
172
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -145,6 +177,10 @@ let ref = $state(null);
145
177
  .label-sizing-box {
146
178
  position: relative;
147
179
  display: inline-block;
180
+ /* An inline-block wraps as a whole first, so short labels in a row just
181
+ flow onto the next line; only a label longer than the whole row wraps
182
+ its own text (the invisible sizer and the real label wrap alike). */
183
+ max-width: 100%;
148
184
  }
149
185
 
150
186
  .label-sizing-box .checkbox-item {
@@ -100,6 +100,38 @@ const el = $derived(elementProps(restProps, "circle-button", [
100
100
  we deliberately avoid everywhere else.
101
101
 
102
102
  One definition, used by both, so they cannot drift again. */
103
+ /* The "small" size tier: a component whose container is this wide or less
104
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
105
+
106
+ The convention, shared by every component that has a size worth changing
107
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
108
+
109
+ --{component}-{property}-small
110
+
111
+ applies inside a small container. What wins there, in order:
112
+ 1. the `-small` variable, if you set it;
113
+ 2. otherwise the regular variable, if you set it -- a size you chose on
114
+ purpose is not overridden behind your back;
115
+ 3. otherwise the component's own small default, which for most
116
+ properties is simply its regular default.
117
+
118
+ Container queries can't read a custom property, so the breakpoint itself
119
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
120
+ which already switched there. (The Sidebar's rail-to-sheet switch,
121
+ above, is a separate, layout-chrome decision and keeps its own value.) */
122
+ /* Styles for the small tier: the nearest container is narrow, OR the
123
+ viewport is.
124
+
125
+ The container query is the real answer -- a Tile in a 400px pane on a
126
+ desktop is small. But a container query only matches inside an ancestor
127
+ that *is* a container, and a component dropped straight into a page (no
128
+ Page, no Container around it) has none, so on a phone it would never
129
+ find out. The viewport query covers that: a narrow viewport means every
130
+ container in it is narrow too, so the two never disagree in the
131
+ direction that matters.
132
+
133
+ An element never queries itself, so on a component that is its own
134
+ container (Tile, Bar) this asks about the space it was given. */
103
135
  /* Warning: because we define a fallback
104
136
  media query, the media query can override the container
105
137
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -86,6 +86,38 @@ const el = $derived(elementProps(restProps, "input", INPUT_VARS));
86
86
  we deliberately avoid everywhere else.
87
87
 
88
88
  One definition, used by both, so they cannot drift again. */
89
+ /* The "small" size tier: a component whose container is this wide or less
90
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
91
+
92
+ The convention, shared by every component that has a size worth changing
93
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
94
+
95
+ --{component}-{property}-small
96
+
97
+ applies inside a small container. What wins there, in order:
98
+ 1. the `-small` variable, if you set it;
99
+ 2. otherwise the regular variable, if you set it -- a size you chose on
100
+ purpose is not overridden behind your back;
101
+ 3. otherwise the component's own small default, which for most
102
+ properties is simply its regular default.
103
+
104
+ Container queries can't read a custom property, so the breakpoint itself
105
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
106
+ which already switched there. (The Sidebar's rail-to-sheet switch,
107
+ above, is a separate, layout-chrome decision and keeps its own value.) */
108
+ /* Styles for the small tier: the nearest container is narrow, OR the
109
+ viewport is.
110
+
111
+ The container query is the real answer -- a Tile in a 400px pane on a
112
+ desktop is small. But a container query only matches inside an ancestor
113
+ that *is* a container, and a component dropped straight into a page (no
114
+ Page, no Container around it) has none, so on a phone it would never
115
+ find out. The viewport query covers that: a narrow viewport means every
116
+ container in it is narrow too, so the two never disagree in the
117
+ direction that matters.
118
+
119
+ An element never queries itself, so on a component that is its own
120
+ container (Tile, Bar) this asks about the space it was given. */
89
121
  /* Warning: because we define a fallback
90
122
  media query, the media query can override the container
91
123
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -113,6 +113,38 @@ function handleChange() {
113
113
  we deliberately avoid everywhere else.
114
114
 
115
115
  One definition, used by both, so they cannot drift again. */
116
+ /* The "small" size tier: a component whose container is this wide or less
117
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
118
+
119
+ The convention, shared by every component that has a size worth changing
120
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
121
+
122
+ --{component}-{property}-small
123
+
124
+ applies inside a small container. What wins there, in order:
125
+ 1. the `-small` variable, if you set it;
126
+ 2. otherwise the regular variable, if you set it -- a size you chose on
127
+ purpose is not overridden behind your back;
128
+ 3. otherwise the component's own small default, which for most
129
+ properties is simply its regular default.
130
+
131
+ Container queries can't read a custom property, so the breakpoint itself
132
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
133
+ which already switched there. (The Sidebar's rail-to-sheet switch,
134
+ above, is a separate, layout-chrome decision and keeps its own value.) */
135
+ /* Styles for the small tier: the nearest container is narrow, OR the
136
+ viewport is.
137
+
138
+ The container query is the real answer -- a Tile in a 400px pane on a
139
+ desktop is small. But a container query only matches inside an ancestor
140
+ that *is* a container, and a component dropped straight into a page (no
141
+ Page, no Container around it) has none, so on a phone it would never
142
+ find out. The viewport query covers that: a narrow viewport means every
143
+ container in it is narrow too, so the two never disagree in the
144
+ direction that matters.
145
+
146
+ An element never queries itself, so on a component that is its own
147
+ container (Tile, Bar) this asks about the space it was given. */
116
148
  /* Warning: because we define a fallback
117
149
  media query, the media query can override the container
118
150
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -123,6 +155,10 @@ function handleChange() {
123
155
  .label-sizing-box {
124
156
  position: relative;
125
157
  display: inline-block;
158
+ /* An inline-block wraps as a whole first, so short labels in a row just
159
+ flow onto the next line; only a label longer than the whole row wraps
160
+ its own text (the invisible sizer and the real label wrap alike). */
161
+ max-width: 100%;
126
162
  }
127
163
 
128
164
  .label-sizing-box .radio-item {
@@ -176,7 +212,6 @@ label.radio-item {
176
212
  box-sizing: border-box;
177
213
  user-select: none;
178
214
  gap: var(--radio-button-space, var(--toggle-space, var(--space-md)));
179
- white-space: nowrap;
180
215
  cursor: var(--radio-button-cursor, var(--clickable-cursor, var(--cursor, pointer)));
181
216
  }
182
217
 
@@ -212,6 +212,38 @@ $effect(() => {
212
212
  we deliberately avoid everywhere else.
213
213
 
214
214
  One definition, used by both, so they cannot drift again. */
215
+ /* The "small" size tier: a component whose container is this wide or less
216
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
217
+
218
+ The convention, shared by every component that has a size worth changing
219
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
220
+
221
+ --{component}-{property}-small
222
+
223
+ applies inside a small container. What wins there, in order:
224
+ 1. the `-small` variable, if you set it;
225
+ 2. otherwise the regular variable, if you set it -- a size you chose on
226
+ purpose is not overridden behind your back;
227
+ 3. otherwise the component's own small default, which for most
228
+ properties is simply its regular default.
229
+
230
+ Container queries can't read a custom property, so the breakpoint itself
231
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
232
+ which already switched there. (The Sidebar's rail-to-sheet switch,
233
+ above, is a separate, layout-chrome decision and keeps its own value.) */
234
+ /* Styles for the small tier: the nearest container is narrow, OR the
235
+ viewport is.
236
+
237
+ The container query is the real answer -- a Tile in a 400px pane on a
238
+ desktop is small. But a container query only matches inside an ancestor
239
+ that *is* a container, and a component dropped straight into a page (no
240
+ Page, no Container around it) has none, so on a phone it would never
241
+ find out. The viewport query covers that: a narrow viewport means every
242
+ container in it is narrow too, so the two never disagree in the
243
+ direction that matters.
244
+
245
+ An element never queries itself, so on a component that is its own
246
+ container (Tile, Bar) this asks about the space it was given. */
215
247
  /* Warning: because we define a fallback
216
248
  media query, the media query can override the container
217
249
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -318,6 +350,9 @@ select,
318
350
  background-color: var(--_background-color);
319
351
  color: var(--_color);
320
352
  width: var(--select-width, var(--target-width, var(--dropdown-menu-width, min(12em, 100vw))));
353
+ /* The measured width fits the longest option; the container may be
354
+ narrower than that. Truncate (below) rather than overflow. */
355
+ max-width: 100%;
321
356
  text-overflow: ellipsis;
322
357
  font-family: var(--select-font-family, var(--input-font-family, var(--ui-font-family, var(--font-family, unset))));
323
358
  text-transform: var(--select-text-transform, var(--input-text-transform, var(--ui-text-transform, var(--text-transform, unset))));
@@ -88,6 +88,38 @@ const el = $derived(elementProps(restProps, "slider", ["bg", "fg", "padding", "w
88
88
  we deliberately avoid everywhere else.
89
89
 
90
90
  One definition, used by both, so they cannot drift again. */
91
+ /* The "small" size tier: a component whose container is this wide or less
92
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
93
+
94
+ The convention, shared by every component that has a size worth changing
95
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
96
+
97
+ --{component}-{property}-small
98
+
99
+ applies inside a small container. What wins there, in order:
100
+ 1. the `-small` variable, if you set it;
101
+ 2. otherwise the regular variable, if you set it -- a size you chose on
102
+ purpose is not overridden behind your back;
103
+ 3. otherwise the component's own small default, which for most
104
+ properties is simply its regular default.
105
+
106
+ Container queries can't read a custom property, so the breakpoint itself
107
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
108
+ which already switched there. (The Sidebar's rail-to-sheet switch,
109
+ above, is a separate, layout-chrome decision and keeps its own value.) */
110
+ /* Styles for the small tier: the nearest container is narrow, OR the
111
+ viewport is.
112
+
113
+ The container query is the real answer -- a Tile in a 400px pane on a
114
+ desktop is small. But a container query only matches inside an ancestor
115
+ that *is* a container, and a component dropped straight into a page (no
116
+ Page, no Container around it) has none, so on a phone it would never
117
+ find out. The viewport query covers that: a narrow viewport means every
118
+ container in it is narrow too, so the two never disagree in the
119
+ direction that matters.
120
+
121
+ An element never queries itself, so on a component that is its own
122
+ container (Tile, Bar) this asks about the space it was given. */
91
123
  /* Warning: because we define a fallback
92
124
  media query, the media query can override the container
93
125
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -100,6 +100,38 @@ const el = $derived(elementProps(restProps, "tab", [
100
100
  we deliberately avoid everywhere else.
101
101
 
102
102
  One definition, used by both, so they cannot drift again. */
103
+ /* The "small" size tier: a component whose container is this wide or less
104
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
105
+
106
+ The convention, shared by every component that has a size worth changing
107
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
108
+
109
+ --{component}-{property}-small
110
+
111
+ applies inside a small container. What wins there, in order:
112
+ 1. the `-small` variable, if you set it;
113
+ 2. otherwise the regular variable, if you set it -- a size you chose on
114
+ purpose is not overridden behind your back;
115
+ 3. otherwise the component's own small default, which for most
116
+ properties is simply its regular default.
117
+
118
+ Container queries can't read a custom property, so the breakpoint itself
119
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
120
+ which already switched there. (The Sidebar's rail-to-sheet switch,
121
+ above, is a separate, layout-chrome decision and keeps its own value.) */
122
+ /* Styles for the small tier: the nearest container is narrow, OR the
123
+ viewport is.
124
+
125
+ The container query is the real answer -- a Tile in a 400px pane on a
126
+ desktop is small. But a container query only matches inside an ancestor
127
+ that *is* a container, and a component dropped straight into a page (no
128
+ Page, no Container around it) has none, so on a phone it would never
129
+ find out. The viewport query covers that: a narrow viewport means every
130
+ container in it is narrow too, so the two never disagree in the
131
+ direction that matters.
132
+
133
+ An element never queries itself, so on a component that is its own
134
+ container (Tile, Bar) this asks about the space it was given. */
103
135
  /* Warning: because we define a fallback
104
136
  media query, the media query can override the container
105
137
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -238,6 +270,10 @@ const el = $derived(elementProps(restProps, "tab", [
238
270
  .tab > :global(div > button) {
239
271
  border-radius: var(--tab-border-radius, var(--border-radius) var(--border-radius) 0 0);
240
272
  margin: 0;
273
+ /* In a TabBar that scrolls, a tab keeps its label on one line and its
274
+ full width; squeezing the labels is what made them wrap. */
275
+ flex-shrink: 0;
276
+ white-space: nowrap;
241
277
  }
242
278
 
243
279
  .tab.active > :global(button),
@@ -117,6 +117,38 @@ const effectiveOnLabel = $derived(onLabel || children);
117
117
  we deliberately avoid everywhere else.
118
118
 
119
119
  One definition, used by both, so they cannot drift again. */
120
+ /* The "small" size tier: a component whose container is this wide or less
121
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
122
+
123
+ The convention, shared by every component that has a size worth changing
124
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
125
+
126
+ --{component}-{property}-small
127
+
128
+ applies inside a small container. What wins there, in order:
129
+ 1. the `-small` variable, if you set it;
130
+ 2. otherwise the regular variable, if you set it -- a size you chose on
131
+ purpose is not overridden behind your back;
132
+ 3. otherwise the component's own small default, which for most
133
+ properties is simply its regular default.
134
+
135
+ Container queries can't read a custom property, so the breakpoint itself
136
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
137
+ which already switched there. (The Sidebar's rail-to-sheet switch,
138
+ above, is a separate, layout-chrome decision and keeps its own value.) */
139
+ /* Styles for the small tier: the nearest container is narrow, OR the
140
+ viewport is.
141
+
142
+ The container query is the real answer -- a Tile in a 400px pane on a
143
+ desktop is small. But a container query only matches inside an ancestor
144
+ that *is* a container, and a component dropped straight into a page (no
145
+ Page, no Container around it) has none, so on a phone it would never
146
+ find out. The viewport query covers that: a narrow viewport means every
147
+ container in it is narrow too, so the two never disagree in the
148
+ direction that matters.
149
+
150
+ An element never queries itself, so on a component that is its own
151
+ container (Tile, Bar) this asks about the space it was given. */
120
152
  /* Warning: because we define a fallback
121
153
  media query, the media query can override the container
122
154
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -255,7 +255,9 @@ let popoverDiv = $state();
255
255
  aria-expanded={isOpen ? "true" : "false"}
256
256
  aria-controls={id}
257
257
  >
258
- {#if label}{@render label()}{:else}Menu{/if}
258
+ <span class="trigger-label"
259
+ >{#if label}{@render label()}{:else}Menu{/if}</span
260
+ >
259
261
  </button>
260
262
  <div
261
263
  {id}
@@ -358,6 +360,38 @@ let popoverDiv = $state();
358
360
  we deliberately avoid everywhere else.
359
361
 
360
362
  One definition, used by both, so they cannot drift again. */
363
+ /* The "small" size tier: a component whose container is this wide or less
364
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
365
+
366
+ The convention, shared by every component that has a size worth changing
367
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
368
+
369
+ --{component}-{property}-small
370
+
371
+ applies inside a small container. What wins there, in order:
372
+ 1. the `-small` variable, if you set it;
373
+ 2. otherwise the regular variable, if you set it -- a size you chose on
374
+ purpose is not overridden behind your back;
375
+ 3. otherwise the component's own small default, which for most
376
+ properties is simply its regular default.
377
+
378
+ Container queries can't read a custom property, so the breakpoint itself
379
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
380
+ which already switched there. (The Sidebar's rail-to-sheet switch,
381
+ above, is a separate, layout-chrome decision and keeps its own value.) */
382
+ /* Styles for the small tier: the nearest container is narrow, OR the
383
+ viewport is.
384
+
385
+ The container query is the real answer -- a Tile in a 400px pane on a
386
+ desktop is small. But a container query only matches inside an ancestor
387
+ that *is* a container, and a component dropped straight into a page (no
388
+ Page, no Container around it) has none, so on a phone it would never
389
+ find out. The viewport query covers that: a narrow viewport means every
390
+ container in it is narrow too, so the two never disagree in the
391
+ direction that matters.
392
+
393
+ An element never queries itself, so on a component that is its own
394
+ container (Tile, Bar) this asks about the space it was given. */
361
395
  /* Warning: because we define a fallback
362
396
  media query, the media query can override the container
363
397
  if we stack a bunch of these in a row and aren't thoughtful about the order.
@@ -497,6 +531,20 @@ button:focus-visible {
497
531
 
498
532
  button {
499
533
  position: relative;
534
+ /* In a crowded row (a toolbar, a phone-width header) the trigger gives
535
+ way before its neighbours do: never wider than the space it was given,
536
+ its label on one line and truncated with an ellipsis (below). */
537
+ max-width: 100%;
538
+ }
539
+
540
+ /* The clipping lives on this inner span, not the button: overflow other
541
+ than visible moves an inline-level box's baseline to its bottom edge,
542
+ which would drop the trigger out of line with text beside it. */
543
+ .trigger-label {
544
+ display: block;
545
+ white-space: nowrap;
546
+ overflow: hidden;
547
+ text-overflow: ellipsis;
500
548
  }
501
549
 
502
550
  .dropdown-content :global(.menu) {
@@ -993,6 +1041,10 @@ button {
993
1041
 
994
1042
  nav {
995
1043
  position: relative;
1044
+ /* Lets a flex/grid parent shrink the menu below its label's width, so the
1045
+ trigger's ellipsis can kick in instead of the row overflowing. */
1046
+ min-width: 0;
1047
+ max-width: 100%;
996
1048
  }
997
1049
 
998
1050
  [popover] {
@@ -124,6 +124,38 @@ function onAccordionClicked(e) {
124
124
  we deliberately avoid everywhere else.
125
125
 
126
126
  One definition, used by both, so they cannot drift again. */
127
+ /* The "small" size tier: a component whose container is this wide or less
128
+ is on a phone, or in a pane about that narrow, and sizes itself for it.
129
+
130
+ The convention, shared by every component that has a size worth changing
131
+ there (Card started it; Tile, GridLayout, Bar and Container follow):
132
+
133
+ --{component}-{property}-small
134
+
135
+ applies inside a small container. What wins there, in order:
136
+ 1. the `-small` variable, if you set it;
137
+ 2. otherwise the regular variable, if you set it -- a size you chose on
138
+ purpose is not overridden behind your back;
139
+ 3. otherwise the component's own small default, which for most
140
+ properties is simply its regular default.
141
+
142
+ Container queries can't read a custom property, so the breakpoint itself
143
+ is fixed here rather than themeable. 600px matches Card and SplitPane,
144
+ which already switched there. (The Sidebar's rail-to-sheet switch,
145
+ above, is a separate, layout-chrome decision and keeps its own value.) */
146
+ /* Styles for the small tier: the nearest container is narrow, OR the
147
+ viewport is.
148
+
149
+ The container query is the real answer -- a Tile in a 400px pane on a
150
+ desktop is small. But a container query only matches inside an ancestor
151
+ that *is* a container, and a component dropped straight into a page (no
152
+ Page, no Container around it) has none, so on a phone it would never
153
+ find out. The viewport query covers that: a narrow viewport means every
154
+ container in it is narrow too, so the two never disagree in the
155
+ direction that matters.
156
+
157
+ An element never queries itself, so on a component that is its own
158
+ container (Tile, Bar) this asks about the space it was given. */
127
159
  /* Warning: because we define a fallback
128
160
  media query, the media query can override the container
129
161
  if we stack a bunch of these in a row and aren't thoughtful about the order.