@scalewing/react 1.40.0 → 1.42.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 (191) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +274 -7
  3. package/dist/calendar-labels.d.ts +2 -0
  4. package/dist/calendar-labels.js +7 -0
  5. package/dist/components/Article.d.ts +60 -0
  6. package/dist/components/Article.js +42 -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/DenominationGrid.d.ts +3 -2
  14. package/dist/components/DenominationGrid.js +21 -3
  15. package/dist/components/Dialog.d.ts +29 -13
  16. package/dist/components/Dialog.js +22 -20
  17. package/dist/components/DocumentViewer.d.ts +41 -0
  18. package/dist/components/DocumentViewer.js +72 -0
  19. package/dist/components/Field.d.ts +13 -2
  20. package/dist/components/Field.js +14 -38
  21. package/dist/components/FileField.d.ts +44 -0
  22. package/dist/components/FileField.js +66 -0
  23. package/dist/components/FilterChips.d.ts +7 -37
  24. package/dist/components/FilterChips.js +32 -24
  25. package/dist/components/ListRow.d.ts +33 -3
  26. package/dist/components/ListRow.js +18 -17
  27. package/dist/components/MarkdownView.d.ts +39 -0
  28. package/dist/components/MarkdownView.js +30 -0
  29. package/dist/components/NavCount.d.ts +15 -2
  30. package/dist/components/NavCount.js +16 -6
  31. package/dist/components/SegmentedControl.d.ts +17 -1
  32. package/dist/components/SegmentedControl.js +11 -3
  33. package/dist/components/Switch.d.ts +16 -1
  34. package/dist/components/Switch.js +17 -6
  35. package/dist/components/action-bar/ActionBarSummary.d.ts +10 -2
  36. package/dist/components/action-bar/ActionBarSummary.js +11 -2
  37. package/dist/components/chart/use-chart-width.js +2 -24
  38. package/dist/components/date-field/CalendarEntryButton.d.ts +24 -0
  39. package/dist/components/date-field/CalendarEntryButton.js +16 -0
  40. package/dist/components/date-field/TypedEntry.d.ts +26 -0
  41. package/dist/components/date-field/TypedEntry.js +13 -0
  42. package/dist/components/denomination-grid/CountCell.d.ts +16 -0
  43. package/dist/components/denomination-grid/CountCell.js +14 -0
  44. package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -1
  45. package/dist/components/denomination-grid/DenominationStrip.js +2 -2
  46. package/dist/components/denomination-grid/EntryCell.d.ts +3 -1
  47. package/dist/components/denomination-grid/EntryCell.js +2 -2
  48. package/dist/components/denomination-grid/StripRow.js +1 -10
  49. package/dist/components/denomination-grid/TransposedStrip.d.ts +17 -0
  50. package/dist/components/denomination-grid/TransposedStrip.js +43 -0
  51. package/dist/components/denomination-grid/types.d.ts +31 -0
  52. package/dist/components/denomination-grid/types.js +7 -1
  53. package/dist/components/denomination-grid/validate-options.d.ts +7 -0
  54. package/dist/components/denomination-grid/validate-options.js +27 -0
  55. package/dist/components/dialog/DialogFooter.d.ts +6 -5
  56. package/dist/components/dialog/DialogFooter.js +6 -6
  57. package/dist/components/dialog/validate.d.ts +24 -0
  58. package/dist/components/dialog/validate.js +23 -0
  59. package/dist/components/document-viewer/document-viewer-labels.d.ts +23 -0
  60. package/dist/components/document-viewer/document-viewer-labels.js +23 -0
  61. package/dist/components/document-viewer/page-box.d.ts +8 -0
  62. package/dist/components/document-viewer/page-box.js +12 -0
  63. package/dist/components/document-viewer/pdf-document.d.ts +32 -0
  64. package/dist/components/document-viewer/pdf-document.js +66 -0
  65. package/dist/components/document-viewer/pdf-options.d.ts +36 -0
  66. package/dist/components/document-viewer/pdf-options.js +46 -0
  67. package/dist/components/document-viewer/render-pdf-page.d.ts +20 -0
  68. package/dist/components/document-viewer/render-pdf-page.js +38 -0
  69. package/dist/components/document-viewer/scroll-chain.d.ts +6 -0
  70. package/dist/components/document-viewer/scroll-chain.js +23 -0
  71. package/dist/components/document-viewer/use-error-report.d.ts +5 -0
  72. package/dist/components/document-viewer/use-error-report.js +13 -0
  73. package/dist/components/document-viewer/use-page-render.d.ts +21 -0
  74. package/dist/components/document-viewer/use-page-render.js +70 -0
  75. package/dist/components/document-viewer/use-pdf-document.d.ts +22 -0
  76. package/dist/components/document-viewer/use-pdf-document.js +47 -0
  77. package/dist/components/document-viewer/use-pinch-zoom.d.ts +12 -0
  78. package/dist/components/document-viewer/use-pinch-zoom.js +67 -0
  79. package/dist/components/document-viewer/use-zoom.d.ts +23 -0
  80. package/dist/components/document-viewer/use-zoom.js +70 -0
  81. package/dist/components/document-viewer/zoom.d.ts +29 -0
  82. package/dist/components/document-viewer/zoom.js +37 -0
  83. package/dist/components/field/field-checks.d.ts +34 -0
  84. package/dist/components/field/field-checks.js +42 -0
  85. package/dist/components/file-field/file-field-checks.d.ts +13 -0
  86. package/dist/components/file-field/file-field-checks.js +21 -0
  87. package/dist/components/file-field/use-file-drop.d.ts +34 -0
  88. package/dist/components/file-field/use-file-drop.js +78 -0
  89. package/dist/components/file-field/use-swap-focus.d.ts +15 -0
  90. package/dist/components/file-field/use-swap-focus.js +40 -0
  91. package/dist/components/filter-chips/FilterChip.d.ts +16 -0
  92. package/dist/components/filter-chips/FilterChip.js +20 -0
  93. package/dist/components/filter-chips/options.d.ts +75 -0
  94. package/dist/components/filter-chips/options.js +11 -0
  95. package/dist/components/filter-chips/validate.d.ts +9 -0
  96. package/dist/components/filter-chips/validate.js +48 -0
  97. package/dist/components/list/ListRowContent.d.ts +8 -2
  98. package/dist/components/list/ListRowContent.js +6 -3
  99. package/dist/components/list/ListRowItem.d.ts +10 -0
  100. package/dist/components/list/ListRowItem.js +17 -0
  101. package/dist/components/list/row-naming.d.ts +17 -0
  102. package/dist/components/list/row-naming.js +19 -0
  103. package/dist/components/list/row-slot.d.ts +8 -0
  104. package/dist/components/list/row-slot.js +12 -0
  105. package/dist/components/markdown/markdown-limits.d.ts +14 -0
  106. package/dist/components/markdown/markdown-limits.js +14 -0
  107. package/dist/components/markdown/markdown-model.d.ts +94 -0
  108. package/dist/components/markdown/markdown-model.js +8 -0
  109. package/dist/components/markdown/markdown-options.d.ts +18 -0
  110. package/dist/components/markdown/markdown-options.js +10 -0
  111. package/dist/components/markdown/markdown-rules.d.ts +28 -0
  112. package/dist/components/markdown/markdown-rules.js +81 -0
  113. package/dist/components/markdown/markdown-text.d.ts +17 -0
  114. package/dist/components/markdown/markdown-text.js +86 -0
  115. package/dist/components/markdown/parse-markdown.d.ts +4 -0
  116. package/dist/components/markdown/parse-markdown.js +21 -0
  117. package/dist/components/markdown/read-blocks.d.ts +8 -0
  118. package/dist/components/markdown/read-blocks.js +168 -0
  119. package/dist/components/markdown/read-inlines.d.ts +12 -0
  120. package/dist/components/markdown/read-inlines.js +126 -0
  121. package/dist/components/markdown/read-markdown.d.ts +9 -0
  122. package/dist/components/markdown/read-markdown.js +27 -0
  123. package/dist/components/markdown/reading-context.d.ts +18 -0
  124. package/dist/components/markdown/reading-context.js +35 -0
  125. package/dist/components/markdown/render-markdown.d.ts +10 -0
  126. package/dist/components/markdown/render-markdown.js +52 -0
  127. package/dist/components/use-element-width.d.ts +11 -0
  128. package/dist/components/use-element-width.js +38 -0
  129. package/dist/css/chart-tones.d.ts +2 -0
  130. package/dist/css/chart-tones.js +5 -1
  131. package/dist/css/css-article.d.ts +2 -0
  132. package/dist/css/css-article.js +110 -0
  133. package/dist/css/css-bar-chart.d.ts +17 -2
  134. package/dist/css/css-bar-chart.js +38 -7
  135. package/dist/css/css-button-group-attached.d.ts +3 -0
  136. package/dist/css/css-button-group-attached.js +18 -1
  137. package/dist/css/css-canvas-grouped.d.ts +17 -0
  138. package/dist/css/css-canvas-grouped.js +40 -0
  139. package/dist/css/css-components.js +18 -0
  140. package/dist/css/css-count-pill.js +14 -1
  141. package/dist/css/css-date-field-calendar-entry.d.ts +11 -0
  142. package/dist/css/css-date-field-calendar-entry.js +50 -0
  143. package/dist/css/css-date-field.js +4 -0
  144. package/dist/css/css-denomination-grid.js +4 -0
  145. package/dist/css/css-denomination-transposed.d.ts +4 -0
  146. package/dist/css/css-denomination-transposed.js +178 -0
  147. package/dist/css/css-dialog-canvas.d.ts +3 -0
  148. package/dist/css/css-dialog-canvas.js +20 -0
  149. package/dist/css/css-dialog-frame.js +19 -2
  150. package/dist/css/css-dialog-grabber.d.ts +4 -0
  151. package/dist/css/css-dialog-grabber.js +56 -0
  152. package/dist/css/css-dialog.js +3 -2
  153. package/dist/css/css-document-viewer.d.ts +2 -0
  154. package/dist/css/css-document-viewer.js +186 -0
  155. package/dist/css/css-document.js +3 -0
  156. package/dist/css/css-field-width.d.ts +12 -0
  157. package/dist/css/css-field-width.js +49 -0
  158. package/dist/css/css-field.js +4 -0
  159. package/dist/css/css-file-field.d.ts +2 -0
  160. package/dist/css/css-file-field.js +180 -0
  161. package/dist/css/css-filter-chips-layout.d.ts +2 -0
  162. package/dist/css/css-filter-chips-layout.js +42 -0
  163. package/dist/css/css-filter-chips.js +4 -0
  164. package/dist/css/css-list-row-trailing.d.ts +2 -0
  165. package/dist/css/css-list-row-trailing.js +91 -0
  166. package/dist/css/css-list-row.d.ts +6 -0
  167. package/dist/css/css-list-row.js +19 -3
  168. package/dist/css/css-list.js +5 -1
  169. package/dist/css/css-markdown.d.ts +2 -0
  170. package/dist/css/css-markdown.js +144 -0
  171. package/dist/css/css-segmented-sizing.d.ts +13 -0
  172. package/dist/css/css-segmented-sizing.js +66 -0
  173. package/dist/css/css-segmented.js +4 -0
  174. package/dist/css/css-switch.d.ts +6 -0
  175. package/dist/css/css-switch.js +39 -0
  176. package/dist/css/css-variables.js +1 -0
  177. package/dist/css/stacking.d.ts +1 -0
  178. package/dist/css/stacking.js +4 -1
  179. package/dist/css/stylesheet.js +12 -0
  180. package/dist/date-field-labels.d.ts +5 -0
  181. package/dist/date-field-labels.js +1 -0
  182. package/dist/document-viewer-worker.d.ts +9 -0
  183. package/dist/document-viewer-worker.js +9 -0
  184. package/dist/index.d.ts +15 -9
  185. package/dist/index.js +13 -7
  186. package/dist/list-options.d.ts +11 -7
  187. package/dist/list-options.js +20 -8
  188. package/dist/styles.css +889 -44
  189. package/dist/theme/ThemeProvider.d.ts +11 -1
  190. package/dist/theme/ThemeProvider.js +4 -2
  191. package/package.json +10 -2
@@ -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
@@ -0,0 +1,2 @@
1
+ export declare function cssDocumentViewerClasses(): string;
2
+ export declare function documentViewerClassCatalog(): string[];
@@ -0,0 +1,186 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ import { breakpointQuery } from './breakpoints.js';
3
+ import { quietFill } from './quiet-fill.js';
4
+ const label = typographyVariants.label;
5
+ /** How much accent tints a selection of the page's text, in percent. */
6
+ const selectionTint = 30;
7
+ /*
8
+ * The viewer: a quiet grey stage at the large radius holding the page,
9
+ * and under it the page steps around "Page n of m". The stage scrolls
10
+ * sideways when the page is zoomed past its width; it only pans, so two
11
+ * fingers zoom the page, not the screen. The page is centred in it with a
12
+ * space-5 margin (space-3 on a phone), on the surface with the small
13
+ * elevation until PDF.js paints it.
14
+ */
15
+ function stageRules() {
16
+ return `.sw-document-viewer {
17
+ background: ${quietFill};
18
+ border-radius: var(--sw-radius-lg);
19
+ display: flex;
20
+ flex-direction: column;
21
+ min-width: 0;
22
+ padding-block-end: var(--sw-space-4);
23
+ }
24
+
25
+ .sw-document-viewer-stage {
26
+ box-sizing: border-box;
27
+ min-width: 0;
28
+ overflow-x: auto;
29
+ overscroll-behavior-x: contain;
30
+ padding: var(--sw-space-5);
31
+ touch-action: pan-x pan-y;
32
+ }
33
+
34
+ @media ${breakpointQuery('below', 'md')} {
35
+ .sw-document-viewer-stage { padding: var(--sw-space-3); }
36
+ }
37
+
38
+ .sw-document-viewer-stage:focus { outline: none; }
39
+
40
+ .sw-document-viewer-stage:focus-visible {
41
+ border-radius: var(--sw-radius-lg);
42
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
43
+ outline-offset: calc(-1 * var(--sw-focus-ring-width));
44
+ }
45
+
46
+ .sw-document-viewer-page {
47
+ aspect-ratio: 1 / var(--sw-document-page-aspect);
48
+ background: var(--sw-color-surface);
49
+ box-shadow: var(--sw-elevation-sm);
50
+ margin-inline: auto;
51
+ position: relative;
52
+ width: var(--sw-document-page-width);
53
+ }
54
+
55
+ .sw-document-viewer-page > canvas {
56
+ display: block;
57
+ height: 100%;
58
+ width: 100%;
59
+ }`;
60
+ }
61
+ /*
62
+ * The page's text, laid over the drawing by PDF.js's TextLayer: each run
63
+ * transparent at its place and size, so it is read by assistive
64
+ * technology and selected, never seen. These are the rules PDF.js's own
65
+ * viewer gives its text layer, at the scale the viewer sets
66
+ * (--total-scale-factor) with whole-pixel rounding; a selection shows in a
67
+ * tint of the accent.
68
+ */
69
+ function textLayerRules() {
70
+ return `.sw-document-viewer-text {
71
+ --scale-round-x: 1px;
72
+ --scale-round-y: 1px;
73
+ --min-font-size: 1;
74
+ --text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));
75
+ --min-font-size-inv: calc(1 / var(--min-font-size));
76
+ forced-color-adjust: none;
77
+ inset: 0;
78
+ letter-spacing: normal;
79
+ line-height: 1;
80
+ overflow: clip;
81
+ position: absolute;
82
+ text-align: initial;
83
+ text-size-adjust: none;
84
+ transform-origin: 0 0;
85
+ word-spacing: normal;
86
+ }
87
+
88
+ .sw-document-viewer-text :is(span, br) {
89
+ color: transparent;
90
+ cursor: text;
91
+ position: absolute;
92
+ transform-origin: 0% 0%;
93
+ user-select: text;
94
+ white-space: pre;
95
+ }
96
+
97
+ .sw-document-viewer-text > :not(.markedContent),
98
+ .sw-document-viewer-text .markedContent span:not(.markedContent) {
99
+ --font-height: 0;
100
+ --scale-x: 1;
101
+ --rotate: 0deg;
102
+ font-size: calc(var(--text-scale-factor) * var(--font-height));
103
+ transform: rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
104
+ }
105
+
106
+ .sw-document-viewer-text .markedContent { display: contents; }
107
+
108
+ .sw-document-viewer-text ::selection {
109
+ background: color-mix(in srgb, var(--sw-color-accent) ${selectionTint}%, transparent);
110
+ color: transparent;
111
+ }`;
112
+ }
113
+ /*
114
+ * The steps are 48-point round neutral Buttons (spacing step 8) with the
115
+ * pager's private chevron, around the page words in label type; with one
116
+ * page only the words show. Loading and a failed page centre their words
117
+ * (and the consumer's actions) in the stage.
118
+ */
119
+ function barRules() {
120
+ return `.sw-document-viewer-bar {
121
+ align-items: center;
122
+ display: flex;
123
+ gap: var(--sw-space-3);
124
+ justify-content: center;
125
+ padding-inline: var(--sw-space-3);
126
+ }
127
+
128
+ .sw-button.sw-document-viewer-step {
129
+ border-radius: var(--sw-radius-pill);
130
+ flex: none;
131
+ min-height: var(--sw-space-8);
132
+ min-width: var(--sw-space-8);
133
+ padding-inline: 0;
134
+ }
135
+
136
+ .sw-document-viewer-status {
137
+ font-family: var(--sw-font-sans);
138
+ font-size: ${label.fontSize}px;
139
+ font-variant-numeric: tabular-nums;
140
+ line-height: ${label.lineHeight}px;
141
+ text-align: center;
142
+ }
143
+
144
+ .sw-document-viewer-message {
145
+ align-items: center;
146
+ display: flex;
147
+ flex-direction: column;
148
+ gap: var(--sw-space-2);
149
+ justify-content: center;
150
+ min-height: calc(4 * var(--sw-space-8));
151
+ text-align: center;
152
+ }
153
+
154
+ .sw-document-viewer-actions {
155
+ display: flex;
156
+ flex-wrap: wrap;
157
+ gap: var(--sw-space-2);
158
+ justify-content: center;
159
+ margin-block-start: var(--sw-space-2);
160
+ }
161
+
162
+ @media (forced-colors: active) {
163
+ .sw-document-viewer { border: 1px solid CanvasText; }
164
+ .sw-document-viewer-page { outline: 1px solid CanvasText; }
165
+ }`;
166
+ }
167
+ export function cssDocumentViewerClasses() {
168
+ return `${stageRules()}
169
+
170
+ ${textLayerRules()}
171
+
172
+ ${barRules()}`;
173
+ }
174
+ export function documentViewerClassCatalog() {
175
+ return [
176
+ 'sw-document-viewer',
177
+ 'sw-document-viewer-stage',
178
+ 'sw-document-viewer-page',
179
+ 'sw-document-viewer-text',
180
+ 'sw-document-viewer-bar',
181
+ 'sw-document-viewer-step',
182
+ 'sw-document-viewer-status',
183
+ 'sw-document-viewer-message',
184
+ 'sw-document-viewer-actions',
185
+ ];
186
+ }
@@ -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 cssFileFieldClasses(): string;
2
+ export declare function fileFieldClassCatalog(): string[];