@scalewing/react 1.39.0 → 1.41.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 (181) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +255 -5
  3. package/dist/calendar-labels.d.ts +2 -0
  4. package/dist/calendar-labels.js +7 -0
  5. package/dist/calendar-month.d.ts +6 -0
  6. package/dist/calendar-month.js +15 -0
  7. package/dist/components/BarChart.d.ts +20 -4
  8. package/dist/components/BarChart.js +13 -6
  9. package/dist/components/ButtonGroup.d.ts +8 -1
  10. package/dist/components/ButtonGroup.js +11 -2
  11. package/dist/components/DateField.d.ts +14 -2
  12. package/dist/components/DateField.js +14 -11
  13. package/dist/components/DateRangeButton.d.ts +65 -0
  14. package/dist/components/DateRangeButton.js +54 -0
  15. package/dist/components/DenominationGrid.d.ts +3 -2
  16. package/dist/components/DenominationGrid.js +21 -3
  17. package/dist/components/Dialog.d.ts +29 -13
  18. package/dist/components/Dialog.js +22 -20
  19. package/dist/components/Field.d.ts +13 -2
  20. package/dist/components/Field.js +14 -38
  21. package/dist/components/FilterChips.d.ts +7 -37
  22. package/dist/components/FilterChips.js +32 -24
  23. package/dist/components/ListGroup.d.ts +33 -0
  24. package/dist/components/ListGroup.js +19 -0
  25. package/dist/components/ListRow.d.ts +60 -0
  26. package/dist/components/ListRow.js +60 -0
  27. package/dist/components/NavCount.d.ts +21 -0
  28. package/dist/components/NavCount.js +23 -0
  29. package/dist/components/SectionNav.js +1 -8
  30. package/dist/components/SegmentedControl.d.ts +17 -1
  31. package/dist/components/SegmentedControl.js +11 -3
  32. package/dist/components/StatTile.d.ts +11 -4
  33. package/dist/components/StatTile.js +11 -4
  34. package/dist/components/Switch.d.ts +16 -1
  35. package/dist/components/Switch.js +17 -6
  36. package/dist/components/action-bar/ActionBarSummary.d.ts +10 -2
  37. package/dist/components/action-bar/ActionBarSummary.js +11 -2
  38. package/dist/components/{date-field → calendar}/CalendarGrid.d.ts +17 -2
  39. package/dist/components/{date-field → calendar}/CalendarGrid.js +11 -3
  40. package/dist/components/calendar/CalendarPopover.d.ts +25 -0
  41. package/dist/components/calendar/CalendarPopover.js +22 -0
  42. package/dist/components/calendar/MonthStep.d.ts +16 -0
  43. package/dist/components/calendar/MonthStep.js +17 -0
  44. package/dist/components/calendar/use-grid-focus.d.ts +18 -0
  45. package/dist/components/calendar/use-grid-focus.js +35 -0
  46. package/dist/components/calendar/wrap-tab.d.ts +7 -0
  47. package/dist/components/calendar/wrap-tab.js +29 -0
  48. package/dist/components/date-field/CalendarDialog.js +9 -67
  49. package/dist/components/date-field/CalendarEntryButton.d.ts +24 -0
  50. package/dist/components/date-field/CalendarEntryButton.js +16 -0
  51. package/dist/components/date-field/CalendarHeader.js +2 -11
  52. package/dist/components/date-field/TypedEntry.d.ts +26 -0
  53. package/dist/components/date-field/TypedEntry.js +13 -0
  54. package/dist/components/date-range/DateRangePopover.d.ts +7 -0
  55. package/dist/components/date-range/DateRangePopover.js +17 -0
  56. package/dist/components/date-range/DateRangeSheet.d.ts +7 -0
  57. package/dist/components/date-range/DateRangeSheet.js +15 -0
  58. package/dist/components/date-range/RangeMonths.d.ts +28 -0
  59. package/dist/components/date-range/RangeMonths.js +50 -0
  60. package/dist/components/date-range/RangePresets.d.ts +16 -0
  61. package/dist/components/date-range/RangePresets.js +10 -0
  62. package/dist/components/date-range/RangeSummary.d.ts +15 -0
  63. package/dist/components/date-range/RangeSummary.js +11 -0
  64. package/dist/components/date-range/range-panel-props.d.ts +31 -0
  65. package/dist/components/date-range/range-panel-props.js +1 -0
  66. package/dist/components/date-range/use-range-popup.d.ts +21 -0
  67. package/dist/components/date-range/use-range-popup.js +53 -0
  68. package/dist/components/denomination-grid/CountCell.d.ts +16 -0
  69. package/dist/components/denomination-grid/CountCell.js +14 -0
  70. package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -1
  71. package/dist/components/denomination-grid/DenominationStrip.js +2 -2
  72. package/dist/components/denomination-grid/EntryCell.d.ts +3 -1
  73. package/dist/components/denomination-grid/EntryCell.js +2 -2
  74. package/dist/components/denomination-grid/StripRow.js +1 -10
  75. package/dist/components/denomination-grid/TransposedStrip.d.ts +17 -0
  76. package/dist/components/denomination-grid/TransposedStrip.js +43 -0
  77. package/dist/components/denomination-grid/types.d.ts +31 -0
  78. package/dist/components/denomination-grid/types.js +7 -1
  79. package/dist/components/denomination-grid/validate-options.d.ts +7 -0
  80. package/dist/components/denomination-grid/validate-options.js +27 -0
  81. package/dist/components/dialog/DialogFooter.d.ts +6 -5
  82. package/dist/components/dialog/DialogFooter.js +6 -6
  83. package/dist/components/dialog/validate.d.ts +24 -0
  84. package/dist/components/dialog/validate.js +23 -0
  85. package/dist/components/field/field-checks.d.ts +34 -0
  86. package/dist/components/field/field-checks.js +42 -0
  87. package/dist/components/filter-chips/FilterChip.d.ts +16 -0
  88. package/dist/components/filter-chips/FilterChip.js +20 -0
  89. package/dist/components/filter-chips/options.d.ts +75 -0
  90. package/dist/components/filter-chips/options.js +11 -0
  91. package/dist/components/filter-chips/validate.d.ts +9 -0
  92. package/dist/components/filter-chips/validate.js +48 -0
  93. package/dist/components/link-press.d.ts +7 -0
  94. package/dist/components/link-press.js +13 -0
  95. package/dist/components/list/ListRowAccessoryMark.d.ts +5 -0
  96. package/dist/components/list/ListRowAccessoryMark.js +7 -0
  97. package/dist/components/list/ListRowContent.d.ts +22 -0
  98. package/dist/components/list/ListRowContent.js +11 -0
  99. package/dist/components/list/list-row-container.d.ts +5 -0
  100. package/dist/components/list/list-row-container.js +6 -0
  101. package/dist/components/use-media-query.d.ts +5 -0
  102. package/dist/components/use-media-query.js +18 -0
  103. package/dist/css/chart-tones.d.ts +2 -0
  104. package/dist/css/chart-tones.js +5 -1
  105. package/dist/css/chevron.d.ts +6 -0
  106. package/dist/css/chevron.js +14 -0
  107. package/dist/css/css-bar-chart.d.ts +17 -2
  108. package/dist/css/css-bar-chart.js +38 -7
  109. package/dist/css/css-button-group-attached.d.ts +3 -0
  110. package/dist/css/css-button-group-attached.js +26 -5
  111. package/dist/css/css-button-group-track.js +1 -1
  112. package/dist/css/css-canvas-grouped.d.ts +17 -0
  113. package/dist/css/css-canvas-grouped.js +40 -0
  114. package/dist/css/css-checkbox.js +2 -2
  115. package/dist/css/css-components.js +15 -0
  116. package/dist/css/css-count-pill.d.ts +2 -0
  117. package/dist/css/css-count-pill.js +54 -0
  118. package/dist/css/css-date-field-calendar-entry.d.ts +11 -0
  119. package/dist/css/css-date-field-calendar-entry.js +50 -0
  120. package/dist/css/css-date-field.js +7 -2
  121. package/dist/css/css-date-range-presets.d.ts +2 -0
  122. package/dist/css/css-date-range-presets.js +109 -0
  123. package/dist/css/css-date-range.d.ts +2 -0
  124. package/dist/css/css-date-range.js +197 -0
  125. package/dist/css/css-denomination-grid.js +4 -0
  126. package/dist/css/css-denomination-transposed.d.ts +4 -0
  127. package/dist/css/css-denomination-transposed.js +178 -0
  128. package/dist/css/css-dialog-canvas.d.ts +3 -0
  129. package/dist/css/css-dialog-canvas.js +20 -0
  130. package/dist/css/css-dialog-frame.js +19 -2
  131. package/dist/css/css-dialog-grabber.d.ts +4 -0
  132. package/dist/css/css-dialog-grabber.js +56 -0
  133. package/dist/css/css-dialog.js +3 -2
  134. package/dist/css/css-document.js +3 -0
  135. package/dist/css/css-field-width.d.ts +12 -0
  136. package/dist/css/css-field-width.js +49 -0
  137. package/dist/css/css-field.js +4 -0
  138. package/dist/css/css-filter-chips-layout.d.ts +2 -0
  139. package/dist/css/css-filter-chips-layout.js +42 -0
  140. package/dist/css/css-filter-chips.js +4 -0
  141. package/dist/css/css-list-row.d.ts +8 -0
  142. package/dist/css/css-list-row.js +209 -0
  143. package/dist/css/css-list.d.ts +3 -0
  144. package/dist/css/css-list.js +85 -0
  145. package/dist/css/css-scroll-region.d.ts +18 -0
  146. package/dist/css/css-scroll-region.js +41 -0
  147. package/dist/css/css-section-nav-filled.js +2 -25
  148. package/dist/css/css-segmented-sizing.d.ts +13 -0
  149. package/dist/css/css-segmented-sizing.js +66 -0
  150. package/dist/css/css-segmented.js +4 -0
  151. package/dist/css/css-stat-tile.d.ts +7 -0
  152. package/dist/css/css-stat-tile.js +16 -0
  153. package/dist/css/css-steps.js +2 -2
  154. package/dist/css/css-switch.d.ts +6 -0
  155. package/dist/css/css-switch.js +39 -0
  156. package/dist/css/css-table-bounded-edges.js +4 -27
  157. package/dist/css/range-band.d.ts +2 -0
  158. package/dist/css/range-band.js +7 -0
  159. package/dist/css/stacking.d.ts +1 -0
  160. package/dist/css/stacking.js +6 -3
  161. package/dist/css/stylesheet.js +10 -0
  162. package/dist/date-field-labels.d.ts +5 -0
  163. package/dist/date-field-labels.js +1 -0
  164. package/dist/date-range-draft.d.ts +26 -0
  165. package/dist/date-range-draft.js +36 -0
  166. package/dist/date-range-input.d.ts +26 -0
  167. package/dist/date-range-input.js +58 -0
  168. package/dist/date-range-labels.d.ts +22 -0
  169. package/dist/date-range-labels.js +26 -0
  170. package/dist/date-range-view.d.ts +12 -0
  171. package/dist/date-range-view.js +29 -0
  172. package/dist/date-range-words.d.ts +11 -0
  173. package/dist/date-range-words.js +40 -0
  174. package/dist/index.d.ts +16 -9
  175. package/dist/index.js +14 -7
  176. package/dist/list-options.d.ts +71 -0
  177. package/dist/list-options.js +84 -0
  178. package/dist/styles.css +863 -41
  179. package/dist/theme/ThemeProvider.d.ts +11 -1
  180. package/dist/theme/ThemeProvider.js +4 -2
  181. package/package.json +1 -1
@@ -0,0 +1,178 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ import { pinnedStartShadeRules } from './css-scroll-region.js';
3
+ import { zIndex } from './stacking.js';
4
+ const body = typographyVariants.body;
5
+ const data = typographyVariants.data;
6
+ const label = typographyVariants.label;
7
+ /** A grid whose entry counts keep room for `--sw-denomination-count-digits` digits. */
8
+ export const denominationCountDigitsClass = 'sw-denomination-count-digits';
9
+ const transposed = '.sw-denomination-transposed';
10
+ /*
11
+ * A transposed strip, for a phone: a row per denomination under a
12
+ * hairline, each grid row's head on one line (the region scrolls rather
13
+ * than break a head word by word), the denomination column pinned with the
14
+ * strip's start shade,
15
+ * its label in the text colour at label size, then each grid row's counts
16
+ * (end-aligned, centred over steppers as in the strip) and its value line on
17
+ * the subtle fill, centred; the totals in a last row in each row's tone. A
18
+ * quiet grid row's heads and cells take the subtle fill; a disabled one's
19
+ * heads, read-only counts (toned ones too), values and total fade, its
20
+ * steppers disabled by the Stepper.
21
+ */
22
+ function transposedRules() {
23
+ return `${transposed} {
24
+ border-collapse: collapse;
25
+ width: 100%;
26
+ }
27
+
28
+ ${transposed} th,
29
+ ${transposed} td {
30
+ padding: var(--sw-space-1) var(--sw-space-2);
31
+ vertical-align: middle;
32
+ }
33
+
34
+ ${transposed} tbody tr,
35
+ ${transposed} tfoot tr {
36
+ border-top: 1px solid var(--sw-color-border);
37
+ }
38
+
39
+ ${transposed} .sw-denomination-transposed-head {
40
+ vertical-align: bottom;
41
+ white-space: nowrap;
42
+ }
43
+
44
+ ${transposed} .sw-denomination-label-line {
45
+ justify-content: flex-end;
46
+ }
47
+
48
+ .sw-denomination-transposed-label {
49
+ color: var(--sw-color-text);
50
+ font-size: ${label.fontSize}px;
51
+ font-weight: ${label.fontWeight};
52
+ letter-spacing: ${label.letterSpacing}px;
53
+ line-height: ${label.lineHeight}px;
54
+ text-align: start;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ ${transposed} td.sw-denomination-entry {
59
+ padding: var(--sw-space-1);
60
+ }
61
+
62
+ .sw-denomination-transposed-entry .sw-denomination-transposed-head,
63
+ .sw-denomination-transposed-entry .sw-denomination-cell {
64
+ text-align: center;
65
+ }
66
+
67
+ .sw-denomination-transposed-entry .sw-denomination-label-line {
68
+ justify-content: center;
69
+ }
70
+
71
+ .sw-denomination-transposed-value {
72
+ background: var(--sw-color-subtle);
73
+ font-size: ${label.fontSize}px;
74
+ font-variant-numeric: tabular-nums;
75
+ font-weight: ${data.fontWeight};
76
+ letter-spacing: ${label.letterSpacing}px;
77
+ line-height: ${label.lineHeight}px;
78
+ text-align: center;
79
+ white-space: nowrap;
80
+ }
81
+
82
+ .sw-denomination-transposed-total {
83
+ color: var(--sw-denomination-tone);
84
+ font-size: ${data.fontSize}px;
85
+ font-variant-numeric: tabular-nums;
86
+ font-weight: 600;
87
+ letter-spacing: ${data.letterSpacing}px;
88
+ line-height: ${data.lineHeight}px;
89
+ text-align: end;
90
+ white-space: nowrap;
91
+ }
92
+
93
+ .sw-denomination-transposed-entry .sw-denomination-transposed-total {
94
+ text-align: center;
95
+ }
96
+
97
+ /* The denomination column and its corner stay in view, as the strip's labels do. */
98
+ ${transposed} .sw-denomination-transposed-label,
99
+ ${transposed} :is(thead, tfoot) .sw-denomination-corner:first-child {
100
+ background: var(--sw-glass-fill);
101
+ backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
102
+ -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
103
+ inset-inline-start: 0;
104
+ position: sticky;
105
+ ${zIndex('stickyCell')}
106
+ }
107
+
108
+ ${pinnedStartShadeRules('.sw-denomination-scroll-transposed', [
109
+ '.sw-denomination-transposed-label',
110
+ ])}
111
+
112
+ .sw-denomination-transposed-quiet {
113
+ background: var(--sw-color-subtle);
114
+ }
115
+
116
+ /* Over a toned count's full strength (three classes, emitted later). */
117
+ .sw-denomination-grid${transposed} .sw-denomination-transposed-disabled:is(.sw-denomination-cell, .sw-denomination-transposed-value, .sw-denomination-transposed-total, .sw-denomination-transposed-head) {
118
+ opacity: var(--sw-disabled-opacity);
119
+ }
120
+
121
+ @media (forced-colors: active) {
122
+ .sw-denomination-transposed-value,
123
+ .sw-denomination-transposed-quiet { background: Canvas; }
124
+ .sw-denomination-transposed-label,
125
+ .sw-denomination-transposed-value,
126
+ .sw-denomination-transposed-total { color: CanvasText; }
127
+ }`;
128
+ }
129
+ /*
130
+ * The count's last options. A signed count's success colour reads from the
131
+ * cell too, so a transposed column (no row element) keeps it; a plain
132
+ * negative count is the text colour (cash out by design, never red). An
133
+ * entry count with room for more digits sets its track in the input's own
134
+ * type, so a digit's width (1ch) there is the input's, and keeps that many
135
+ * digits, its padding and its two hairlines before the strip scrolls.
136
+ */
137
+ function countRules() {
138
+ return `.sw-denomination-cell-signed.sw-denomination-cell-positive {
139
+ color: var(--sw-color-success);
140
+ }
141
+
142
+ .sw-denomination-cell-negative.sw-denomination-cell-plain {
143
+ color: var(--sw-color-text);
144
+ }
145
+
146
+ .${denominationCountDigitsClass} .sw-denomination-entry .sw-stepper-full .sw-stepper-track {
147
+ font-size: ${body.fontSize}px;
148
+ font-variant-numeric: tabular-nums;
149
+ font-weight: ${label.fontWeight};
150
+ grid-template-columns: var(--sw-space-6) minmax(calc(var(--sw-denomination-count-digits) * 1ch + 2 * var(--sw-space-1) + 2px), 1fr) var(--sw-space-6);
151
+ }
152
+
153
+ @media (forced-colors: active) {
154
+ .sw-denomination-cell-signed.sw-denomination-cell-positive,
155
+ .sw-denomination-cell-negative.sw-denomination-cell-plain { color: CanvasText; }
156
+ }`;
157
+ }
158
+ export function cssDenominationTransposedClasses() {
159
+ return `${transposedRules()}
160
+
161
+ ${countRules()}`;
162
+ }
163
+ export function denominationTransposedClassCatalog() {
164
+ return [
165
+ 'sw-denomination-transposed',
166
+ 'sw-denomination-transposed-entry',
167
+ 'sw-denomination-scroll-transposed',
168
+ 'sw-denomination-transposed-head',
169
+ 'sw-denomination-transposed-label',
170
+ 'sw-denomination-transposed-value',
171
+ 'sw-denomination-transposed-total',
172
+ 'sw-denomination-transposed-quiet',
173
+ 'sw-denomination-transposed-disabled',
174
+ 'sw-denomination-cell-signed',
175
+ 'sw-denomination-cell-plain',
176
+ denominationCountDigitsClass,
177
+ ];
178
+ }
@@ -0,0 +1,3 @@
1
+ export declare const dialogCanvasClass = "sw-dialog-canvas-grouped";
2
+ export declare function cssDialogCanvasClasses(): string;
3
+ export declare function dialogCanvasClassCatalog(): string[];
@@ -0,0 +1,20 @@
1
+ import { groupedCanvasFill } from './css-canvas-grouped.js';
2
+ export const dialogCanvasClass = 'sw-dialog-canvas-grouped';
3
+ /*
4
+ * A dialog on the grouped canvas: its fill is the grouped canvas grey, solid
5
+ * with no blur, so Cards inside it stand apart as they do on a grouped page.
6
+ * The selector carries two classes so it wins over the glass and banded
7
+ * fills at any order. A banded title row and the pinned footer keep their
8
+ * own surface, so they stay bands over the grey. Forced colours paint the
9
+ * system canvas as they do any dialog.
10
+ */
11
+ export function cssDialogCanvasClasses() {
12
+ return `.sw-dialog.${dialogCanvasClass} {
13
+ backdrop-filter: none;
14
+ -webkit-backdrop-filter: none;
15
+ background: ${groupedCanvasFill};
16
+ }`;
17
+ }
18
+ export function dialogCanvasClassCatalog() {
19
+ return [dialogCanvasClass];
20
+ }
@@ -1,3 +1,5 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ const caption = typographyVariants.caption;
1
3
  /*
2
4
  * The dialog's frame beyond its title: a consumer icon before the title, a
3
5
  * muted description under it, and a footer pinned to the bottom edge.
@@ -42,13 +44,27 @@ export function cssDialogFrameClasses() {
42
44
 
43
45
  .sw-dialog-footer-status {
44
46
  align-items: center;
47
+ column-gap: var(--sw-space-2);
45
48
  display: flex;
46
49
  flex: 1 1 auto;
50
+ flex-wrap: wrap;
51
+ min-width: 0;
52
+ }
53
+
54
+ /* The status line: muted caption words beside the actions. Its children
55
+ sit on one row and wrap as one phrase. */
56
+ .sw-dialog-footer-note {
57
+ color: var(--sw-color-muted);
58
+ font-family: var(--sw-font-sans);
59
+ font-size: ${caption.fontSize}px;
60
+ line-height: ${caption.lineHeight}px;
47
61
  min-width: 0;
62
+ overflow-wrap: anywhere;
48
63
  }
49
64
 
50
- /* With no summary the live region stays in the dialog, so a first figure
51
- is still announced, but it takes no room in the footer. */
65
+ /* With no figure and no status line the live region stays in the
66
+ dialog, so a first figure is still announced, but it takes no room in
67
+ the footer. */
52
68
  .sw-dialog-footer-status:empty {
53
69
  clip-path: inset(50%);
54
70
  height: 1px;
@@ -78,6 +94,7 @@ export function dialogFrameClassCatalog() {
78
94
  'sw-dialog-description',
79
95
  'sw-dialog-footer',
80
96
  'sw-dialog-footer-status',
97
+ 'sw-dialog-footer-note',
81
98
  'sw-dialog-footer-actions',
82
99
  ];
83
100
  }
@@ -0,0 +1,4 @@
1
+ export declare const dialogGrabberClass = "sw-dialog-grabber";
2
+ export declare const dialogHasGrabberClass = "sw-dialog-has-grabber";
3
+ export declare function cssDialogGrabberClasses(): string;
4
+ export declare function dialogGrabberClassCatalog(): string[];
@@ -0,0 +1,56 @@
1
+ import { breakpointQuery, breakpoints } from './breakpoints.js';
2
+ import { dialogSheetClass } from './css-dialog.js';
3
+ import { dialogBandedClass } from './css-dialog-banded.js';
4
+ import { zIndex } from './stacking.js';
5
+ export const dialogGrabberClass = 'sw-dialog-grabber';
6
+ export const dialogHasGrabberClass = 'sw-dialog-has-grabber';
7
+ /* How far the grabber sits from the sheet's top edge. */
8
+ const inset = 'var(--sw-space-2)';
9
+ /*
10
+ * A bottom sheet's grabber: a space-6 by space-1 bar on the muted colour at
11
+ * 40 %, centered a space-2 step under the top edge. Its margins add up to
12
+ * nothing (up into the dialog's space-5 padding to the space-2 inset, its
13
+ * space-1 height, then a space-3 step down), so the title keeps its place
14
+ * a space-3 under the bar. It is sticky at that inset while the content
15
+ * scrolls (sticky insets count from the padding edge, so it steps back
16
+ * past the space-5 padding) and sits over a banded title band, whose top padding grows to space-5 to keep the space-3
17
+ * step under the bar. Drawn only below the sheet's breakpoint; forced colours
18
+ * draw it in the text colour (inside the same breakpoint, at the same
19
+ * specificity, so the override wins).
20
+ */
21
+ function sheetGrabberRules() {
22
+ return breakpoints
23
+ .map((breakpoint) => {
24
+ const sheet = `.${dialogSheetClass(breakpoint)}`;
25
+ return `@media ${breakpointQuery('below', breakpoint)} {
26
+ ${sheet} .${dialogGrabberClass} {
27
+ background: color-mix(in srgb, var(--sw-color-muted) 40%, transparent);
28
+ border-radius: var(--sw-radius-pill);
29
+ display: block;
30
+ height: var(--sw-space-1);
31
+ margin: calc(${inset} - var(--sw-space-5)) auto var(--sw-space-3);
32
+ position: sticky;
33
+ top: calc(${inset} - var(--sw-space-5));
34
+ width: var(--sw-space-6);
35
+ ${zIndex('sheetGrabber')}
36
+ }
37
+
38
+ ${sheet}.${dialogBandedClass}.${dialogHasGrabberClass} .sw-dialog-header {
39
+ padding-top: var(--sw-space-5);
40
+ }
41
+
42
+ @media (forced-colors: active) {
43
+ ${sheet} .${dialogGrabberClass} { background: CanvasText; forced-color-adjust: none; }
44
+ }
45
+ }`;
46
+ })
47
+ .join('\n\n');
48
+ }
49
+ export function cssDialogGrabberClasses() {
50
+ return `.${dialogGrabberClass} { display: none; }
51
+
52
+ ${sheetGrabberRules()}`;
53
+ }
54
+ export function dialogGrabberClassCatalog() {
55
+ return [dialogGrabberClass, dialogHasGrabberClass];
56
+ }
@@ -16,8 +16,9 @@ export function dialogSheetClass(sheetBelow) {
16
16
  * shows above it), and padding that clears the safe areas. A pinned
17
17
  * footer steps past that padding so its surface reaches the bottom edge,
18
18
  * and pads itself clear of the home indicator. Emitted after
19
- * `sw-dialog-lg` and `sw-dialog-xl` so it wins at equal specificity. No
20
- * grabber: there is no drag gesture.
19
+ * `sw-dialog-lg` and `sw-dialog-xl` so it wins at equal specificity. A
20
+ * grabber is opt-in (css-dialog-grabber.ts) and marks the sheet only: there
21
+ * is no drag gesture.
21
22
  */
22
23
  function sheetRules() {
23
24
  return breakpoints
@@ -1,5 +1,6 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
2
  import { cssBoxLinkClasses } from './css-box-link.js';
3
+ import { cssCanvasGroupedRules } from './css-canvas-grouped.js';
3
4
  const body = typographyVariants.body;
4
5
  /** The native controls that take typed text: the canvas's text controls. */
5
6
  export const typedInputs = [
@@ -84,6 +85,8 @@ body {
84
85
  color-scheme: dark;
85
86
  }
86
87
 
88
+ ${cssCanvasGroupedRules()}
89
+
87
90
  [data-theme] a {
88
91
  color: var(--sw-color-accent);
89
92
  text-decoration: none;
@@ -0,0 +1,12 @@
1
+ import { type TableColumnSize } from './css-table-layout.js';
2
+ /**
3
+ * The widths a field's control can be capped at: the Table column sizes
4
+ * (`xs` 4rem to `xl` 16rem), so a short value such as a rate or a count
5
+ * sits in a box its own size instead of across the form's column.
6
+ */
7
+ export type FieldWidth = TableColumnSize;
8
+ export declare const fieldWidths: FieldWidth[];
9
+ export declare function fieldWidthClass(width: FieldWidth): string;
10
+ export declare function assertFieldWidth(width: unknown): void;
11
+ export declare function cssFieldWidthClasses(): string;
12
+ export declare function fieldWidthClassCatalog(): string[];
@@ -0,0 +1,49 @@
1
+ import { typedInputs } from './css-document.js';
2
+ import { tableColumnSizes } from './css-table-layout.js';
3
+ export const fieldWidths = Object.keys(tableColumnSizes);
4
+ export function fieldWidthClass(width) {
5
+ return `sw-field-width-${width}`;
6
+ }
7
+ export function assertFieldWidth(width) {
8
+ if (width !== undefined && !fieldWidths.includes(width))
9
+ throw new RangeError(`Unknown Field width: ${String(width)}`);
10
+ }
11
+ /**
12
+ * The field's own control: a native text control or select, or the frame
13
+ * round an adorned or search input. A checkbox, radio, range, colour or
14
+ * file input keeps its own size.
15
+ */
16
+ const control = `:is(${typedInputs}, select, .sw-field-adorned, .sw-field-search)`;
17
+ /*
18
+ * A sized field keeps its label, description and error at the column's
19
+ * width and caps only its control, at the start of the column, never wider
20
+ * than the column on a narrow screen. Every capped control measures its
21
+ * border box, and a resized textarea stays inside the column. A select
22
+ * is a content box in the canvas (its height leaves out its two
23
+ * hairlines), so a sized one states the whole control height instead, at
24
+ * md or xs.
25
+ */
26
+ export function cssFieldWidthClasses() {
27
+ const widths = Object.entries(tableColumnSizes)
28
+ .map(([size, rem]) => `.${fieldWidthClass(size)} { --sw-field-width: ${rem}rem; }`)
29
+ .join('\n');
30
+ return `${widths}
31
+
32
+ .sw-field-sized > ${control} {
33
+ align-self: flex-start;
34
+ box-sizing: border-box;
35
+ inline-size: min(100%, var(--sw-field-width));
36
+ max-inline-size: 100%;
37
+ }
38
+
39
+ [data-theme] .sw-field-sized > select {
40
+ height: var(--sw-control-md-min-height);
41
+ }
42
+
43
+ [data-theme] .sw-field-xs.sw-field-sized > select {
44
+ height: var(--sw-control-xs-min-height);
45
+ }`;
46
+ }
47
+ export function fieldWidthClassCatalog() {
48
+ return ['sw-field-sized', ...fieldWidths.map(fieldWidthClass)];
49
+ }
@@ -1,6 +1,7 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
2
  import { controlSurface, disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
3
3
  import { cssFieldChangedClasses } from './css-field-changed.js';
4
+ import { cssFieldWidthClasses, fieldWidthClassCatalog, } from './css-field-width.js';
4
5
  import { cssFieldSearchClasses, fieldSearchClassCatalog, } from './css-field-search.js';
5
6
  const caption = typographyVariants.caption;
6
7
  /*
@@ -88,6 +89,8 @@ ${cssFieldSearchClasses()}
88
89
 
89
90
  ${cssFieldChangedClasses()}
90
91
 
92
+ ${cssFieldWidthClasses()}
93
+
91
94
  @media (forced-colors: active) {
92
95
  [data-theme] .sw-field-invalid :is(input, select, textarea),
93
96
  .sw-field-invalid .sw-field-adorned { border-color: Mark; }
@@ -110,5 +113,6 @@ export function fieldClassCatalog() {
110
113
  'sw-field-prefix',
111
114
  'sw-field-suffix',
112
115
  ...fieldSearchClassCatalog(),
116
+ ...fieldWidthClassCatalog(),
113
117
  ];
114
118
  }
@@ -0,0 +1,2 @@
1
+ export declare function cssFilterChipsLayoutClasses(): string;
2
+ export declare function filterChipsLayoutClassCatalog(): string[];
@@ -0,0 +1,42 @@
1
+ /*
2
+ * The chips' opt-in layouts.
3
+ *
4
+ * An inline count is set in the chip's own words, at tabular figures, after
5
+ * a middle dot ("Open · 3"); a chosen chip keeps it in its own ink.
6
+ *
7
+ * Chips that scroll keep one row and scroll sideways inside their own box
8
+ * (never the page) when they do not fit, each chip at its words' width on
9
+ * one line (no wrapping, which overrides the wrapping row's
10
+ * `overflow-wrap: anywhere`). The box is padded by the focus ring's reach and pulled back by
11
+ * the same amount, so a focused chip's ring is not clipped and the chips
12
+ * stay where a wrapped row puts them. A focused chip past the edge is
13
+ * scrolled into view by the browser. The scrollbar stays, thin, so a
14
+ * pointer without a sideways wheel can still reach the last chip.
15
+ */
16
+ const ringReach = 'calc(var(--sw-focus-ring-width) + var(--sw-focus-ring-offset))';
17
+ export function cssFilterChipsLayoutClasses() {
18
+ return `.sw-filter-chip-count-inline {
19
+ font-variant-numeric: tabular-nums;
20
+ }
21
+
22
+ .sw-filter-chips-scroll .sw-filter-chips-options {
23
+ flex-wrap: nowrap;
24
+ margin: calc(-1 * ${ringReach});
25
+ overflow-x: auto;
26
+ overscroll-behavior-x: contain;
27
+ padding: ${ringReach};
28
+ scrollbar-width: thin;
29
+ }
30
+
31
+ .sw-filter-chips-scroll .sw-filter-chip {
32
+ flex: none;
33
+ max-width: none;
34
+ }
35
+
36
+ .sw-filter-chips-scroll .sw-filter-chip-face {
37
+ white-space: nowrap;
38
+ }`;
39
+ }
40
+ export function filterChipsLayoutClassCatalog() {
41
+ return ['sw-filter-chip-count-inline', 'sw-filter-chips-scroll'];
42
+ }
@@ -1,4 +1,5 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
+ import { cssFilterChipsLayoutClasses, filterChipsLayoutClassCatalog, } from './css-filter-chips-layout.js';
2
3
  const label = typographyVariants.label;
3
4
  const data = typographyVariants.data;
4
5
  const caption = typographyVariants.caption;
@@ -123,6 +124,8 @@ export function cssFilterChipsClasses() {
123
124
  border-color: var(--sw-color-danger);
124
125
  }
125
126
 
127
+ ${cssFilterChipsLayoutClasses()}
128
+
126
129
  @media (forced-colors: active) {
127
130
  .sw-filter-chip-face { background: Canvas; border-color: CanvasText; color: CanvasText; }
128
131
  .sw-filter-chips-error { color: Mark; }
@@ -144,5 +147,6 @@ export function filterChipsClassCatalog() {
144
147
  'sw-filter-chip-count',
145
148
  'sw-filter-chip-quiet',
146
149
  'sw-filter-chips-error',
150
+ ...filterChipsLayoutClassCatalog(),
147
151
  ];
148
152
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The colours a row's value can take: a table cell's, and `warning`, for a
3
+ * figure that needs a look but is not wrong yet.
4
+ */
5
+ export declare const listRowValueTones: readonly ["success", "danger", "muted", "accent", "warning"];
6
+ export type ListRowValueTone = (typeof listRowValueTones)[number];
7
+ export declare function cssListRowClasses(): string;
8
+ export declare function listRowClassCatalog(): string[];