@surflane/ui 0.11.0 → 0.13.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 (137) hide show
  1. package/dist/alert-dialog.d.ts +25 -7
  2. package/dist/alert-dialog.js +9 -4
  3. package/dist/app-shell.d.ts +10 -0
  4. package/dist/app-shell.js +7 -1
  5. package/dist/autocomplete.d.ts +2 -6
  6. package/dist/avatar.d.ts +7 -7
  7. package/dist/avatar.js +2 -2
  8. package/dist/bar-list.d.ts +31 -0
  9. package/dist/bar-list.js +31 -0
  10. package/dist/bottom-navigation.d.ts +6 -2
  11. package/dist/bottom-navigation.js +2 -2
  12. package/dist/button.d.ts +6 -11
  13. package/dist/button.js +8 -8
  14. package/dist/card.d.ts +15 -10
  15. package/dist/card.js +7 -2
  16. package/dist/chart.d.ts +58 -3
  17. package/dist/chart.js +330 -48
  18. package/dist/choice.d.ts +2 -2
  19. package/dist/class-names.d.ts +0 -4
  20. package/dist/class-names.js +0 -14
  21. package/dist/code.d.ts +19 -7
  22. package/dist/code.js +32 -38
  23. package/dist/combobox.d.ts +2 -8
  24. package/dist/combobox.js +2 -2
  25. package/dist/context-menu.d.ts +2 -8
  26. package/dist/context-menu.js +2 -2
  27. package/dist/css/bar-list.css +9 -0
  28. package/dist/css/chart.css +2 -0
  29. package/dist/css/dashboard.css +20 -0
  30. package/dist/css/rules/alert-dialog.css +8 -2
  31. package/dist/css/rules/app-shell.css +57 -10
  32. package/dist/css/rules/bar-list.css +101 -0
  33. package/dist/css/rules/bar.css +5 -12
  34. package/dist/css/rules/bottom-navigation.css +21 -2
  35. package/dist/css/rules/breadcrumbs.css +0 -6
  36. package/dist/css/rules/button.css +4 -12
  37. package/dist/css/rules/card.css +19 -0
  38. package/dist/css/rules/chart.css +87 -8
  39. package/dist/css/rules/choice.css +26 -2
  40. package/dist/css/rules/combobox.css +17 -16
  41. package/dist/css/rules/dashboard.css +118 -0
  42. package/dist/css/rules/date-picker.css +50 -27
  43. package/dist/css/rules/dialog.css +47 -7
  44. package/dist/css/rules/disclosure.css +17 -3
  45. package/dist/css/rules/field-control.css +9 -6
  46. package/dist/css/rules/file-upload.css +9 -5
  47. package/dist/css/rules/filter-bar.css +32 -2
  48. package/dist/css/rules/gauge.css +2 -2
  49. package/dist/css/rules/icon.css +0 -5
  50. package/dist/css/rules/input-group.css +23 -8
  51. package/dist/css/rules/link.css +0 -6
  52. package/dist/css/rules/menu.css +5 -2
  53. package/dist/css/rules/menubar.css +1 -1
  54. package/dist/css/rules/navigation-menu.css +31 -26
  55. package/dist/css/rules/number-field.css +8 -1
  56. package/dist/css/rules/otp-field.css +13 -3
  57. package/dist/css/rules/page-header.css +10 -0
  58. package/dist/css/rules/panel.css +59 -10
  59. package/dist/css/rules/popup.css +50 -0
  60. package/dist/css/rules/preview-card.css +0 -21
  61. package/dist/css/rules/scroll-area.css +20 -1
  62. package/dist/css/rules/select.css +29 -2
  63. package/dist/css/rules/sizing.css +25 -3
  64. package/dist/css/rules/skeleton.css +1 -1
  65. package/dist/css/rules/slider.css +16 -8
  66. package/dist/css/rules/spinner.css +1 -1
  67. package/dist/css/rules/stat.css +66 -0
  68. package/dist/css/rules/tabs.css +14 -6
  69. package/dist/css/rules/textarea.css +28 -0
  70. package/dist/css/rules/time-range-picker.css +14 -0
  71. package/dist/css/rules/toast.css +3 -1
  72. package/dist/css/rules/toggle.css +10 -3
  73. package/dist/css/rules/toolbar.css +10 -3
  74. package/dist/css/rules/tree.css +29 -4
  75. package/dist/css/styles.css +3 -0
  76. package/dist/css/time-range-picker.css +14 -0
  77. package/dist/dashboard.d.ts +58 -0
  78. package/dist/dashboard.js +60 -0
  79. package/dist/date-picker.d.ts +32 -3
  80. package/dist/date-picker.js +43 -4
  81. package/dist/dialog.d.ts +25 -7
  82. package/dist/dialog.js +9 -4
  83. package/dist/drawer.d.ts +10 -2
  84. package/dist/drawer.js +6 -3
  85. package/dist/icon.d.ts +15 -5
  86. package/dist/icon.js +16 -3
  87. package/dist/index.d.ts +9 -6
  88. package/dist/index.js +7 -4
  89. package/dist/inline-message.d.ts +2 -2
  90. package/dist/inline-message.js +7 -2
  91. package/dist/input.d.ts +2 -2
  92. package/dist/layout.d.ts +1 -3
  93. package/dist/layout.js +2 -2
  94. package/dist/native-select.d.ts +2 -2
  95. package/dist/navigation-menu.d.ts +16 -0
  96. package/dist/navigation-menu.js +6 -1
  97. package/dist/page-header.d.ts +10 -2
  98. package/dist/page-header.js +3 -3
  99. package/dist/panel.d.ts +6 -3
  100. package/dist/panel.js +2 -2
  101. package/dist/parts.d.ts +7 -3
  102. package/dist/parts.js +12 -4
  103. package/dist/popover.d.ts +6 -6
  104. package/dist/popover.js +3 -2
  105. package/dist/preview-card.d.ts +2 -8
  106. package/dist/preview-card.js +2 -2
  107. package/dist/select.d.ts +38 -8
  108. package/dist/select.js +110 -22
  109. package/dist/sheet.d.ts +10 -2
  110. package/dist/sheet.js +6 -3
  111. package/dist/size.d.ts +8 -6
  112. package/dist/size.js +2 -7
  113. package/dist/sizing.d.ts +13 -6
  114. package/dist/sizing.js +13 -4
  115. package/dist/sparkline.d.ts +2 -2
  116. package/dist/sparkline.js +2 -2
  117. package/dist/spinner.d.ts +2 -2
  118. package/dist/spinner.js +2 -2
  119. package/dist/stat.d.ts +24 -0
  120. package/dist/stat.js +15 -1
  121. package/dist/table.d.ts +12 -4
  122. package/dist/table.js +8 -3
  123. package/dist/textarea.d.ts +6 -3
  124. package/dist/textarea.js +2 -2
  125. package/dist/time-range-picker.d.ts +42 -0
  126. package/dist/time-range-picker.js +69 -0
  127. package/dist/toggle.d.ts +2 -2
  128. package/dist/toggle.js +2 -2
  129. package/dist/toolbar.d.ts +11 -10
  130. package/dist/toolbar.js +23 -1
  131. package/dist/tooltip.d.ts +1 -3
  132. package/dist/tooltip.js +4 -2
  133. package/dist/tree.d.ts +1 -3
  134. package/dist/tree.js +2 -2
  135. package/dist/typography.d.ts +10 -3
  136. package/dist/typography.js +4 -3
  137. package/package.json +18 -3
@@ -7,4 +7,23 @@
7
7
  padding: var(--surf-surface-padding, var(--surf-ui-card-padding));
8
8
  gap: var(--surf-ui-surface-padding);
9
9
  }
10
+ :where([data-ui-size], [data-ui-size] *).surf-card-title {
11
+ font-size: var(--surf-ui-title-size);
12
+ line-height: var(--surf-ui-title-leading);
13
+ letter-spacing: var(--surf-ui-title-tracking);
14
+ }
15
+ /* Compact density, after any size: a card pads 12px, keeps 8px between its parts
16
+ and titles itself with the label role, as a dense panel needs. */
17
+ :where([data-ui-density='compact'], [data-ui-density='compact'] *).surf-card {
18
+ padding: var(--surf-surface-padding, var(--surf-ui-density-gap));
19
+ gap: var(--surf-ui-density-inset);
20
+ }
21
+ :where(
22
+ [data-ui-density='compact'],
23
+ [data-ui-density='compact'] *
24
+ ).surf-card-title {
25
+ font-size: var(--surf-type-label-size);
26
+ line-height: var(--surf-type-label-leading);
27
+ letter-spacing: var(--surf-type-label-tracking);
28
+ }
10
29
  }
@@ -37,12 +37,14 @@
37
37
  align-items: center;
38
38
  gap: 0 var(--surf-space-4);
39
39
  }
40
+ /* The legend takes the inline end of the key: the right, or the left right to left. */
40
41
  .surf-chart-legend {
41
42
  display: flex;
42
43
  flex-wrap: wrap;
43
44
  gap: var(--surf-space-1) var(--surf-space-2);
44
45
  padding: 0;
45
- margin: 0 0 0 auto;
46
+ margin: 0;
47
+ margin-inline-start: auto;
46
48
  list-style: none;
47
49
  }
48
50
  .surf-chart-mark {
@@ -54,7 +56,7 @@
54
56
  display: inline-flex;
55
57
  align-items: center;
56
58
  gap: var(--surf-space-2);
57
- min-height: 36px;
59
+ min-height: var(--surf-control-height);
58
60
  padding: var(--surf-space-1) var(--surf-space-2);
59
61
  border: 0;
60
62
  border-radius: var(--surf-radius-md);
@@ -66,17 +68,53 @@
66
68
  cursor: pointer;
67
69
  text-align: start;
68
70
  }
69
- .surf-chart-legend-button svg {
71
+ .surf-chart-legend-button svg,
72
+ .surf-chart-legend-reference svg {
70
73
  flex: none;
71
74
  }
75
+ /* A threshold or band: named with its value, not a toggle. */
76
+ .surf-chart-legend-reference {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ gap: var(--surf-space-2);
80
+ min-height: var(--surf-control-height);
81
+ padding: var(--surf-space-1) var(--surf-space-2);
82
+ color: var(--surf-ink-body);
83
+ font: var(--surf-weight-regular)
84
+ var(--surf-type-body-size)/var(--surf-type-body-leading)
85
+ var(--surf-font-body);
86
+ }
87
+ .surf-chart-legend-more {
88
+ font-variant-numeric: tabular-nums;
89
+ }
90
+ /* The series past legendLimit, one per row in a popover. */
91
+ .surf-chart-legend-list {
92
+ display: grid;
93
+ gap: var(--surf-space-1);
94
+ margin: 0;
95
+ padding: 0;
96
+ list-style: none;
97
+ }
98
+ .surf-chart-legend-list .surf-chart-legend-button {
99
+ inline-size: 100%;
100
+ }
101
+ .surf-chart-key[data-position='bottom'] .surf-chart-legend {
102
+ margin-inline-start: 0;
103
+ }
72
104
  .surf-chart-legend-button span {
73
105
  overflow-wrap: anywhere;
74
106
  }
75
107
  .surf-chart-legend-button:hover {
76
- background: var(--surf-interaction-hover-bg);
108
+ background-image: linear-gradient(
109
+ var(--surf-interaction-hover-bg),
110
+ var(--surf-interaction-hover-bg)
111
+ );
77
112
  }
78
113
  .surf-chart-legend-button:active {
79
- background: var(--surf-interaction-active-bg);
114
+ background-image: linear-gradient(
115
+ var(--surf-interaction-active-bg),
116
+ var(--surf-interaction-active-bg)
117
+ );
80
118
  }
81
119
  .surf-chart-legend-button[aria-pressed='false'] span {
82
120
  text-decoration: line-through;
@@ -166,6 +204,10 @@
166
204
  inline-size: var(--surf-space-6);
167
205
  block-size: var(--surf-space-4);
168
206
  }
207
+ .surf-chart-tooltip-total {
208
+ padding-block-start: var(--surf-space-1);
209
+ border-block-start: 1px solid var(--surf-line);
210
+ }
169
211
  .surf-chart-tooltip-value {
170
212
  white-space: nowrap;
171
213
  margin-inline-start: auto;
@@ -177,7 +219,7 @@
177
219
  box-sizing: border-box;
178
220
  min-height: 100px;
179
221
  padding: var(--surf-space-3) var(--surf-space-4);
180
- background: var(--surf-surface);
222
+ background: var(--surf-recessed);
181
223
  color: var(--surf-ink-body);
182
224
  border-radius: var(--surf-radius-md);
183
225
  font: var(--surf-weight-regular)
@@ -206,7 +248,7 @@
206
248
  gap: var(--surf-space-3);
207
249
  min-height: 160px;
208
250
  padding: var(--surf-space-4);
209
- background: var(--surf-surface);
251
+ background: var(--surf-recessed);
210
252
  color: var(--surf-ink-muted);
211
253
  border-radius: var(--surf-radius-md);
212
254
  }
@@ -231,8 +273,39 @@
231
273
  .surf-chart-table .surf-scroll-viewport {
232
274
  max-block-size: 320px;
233
275
  }
276
+ /* Compact, for charts in dashboard cards: the plot, its legend and the floating
277
+ values show; the caption, keyboard help, readout and x-axis name stay for
278
+ assistive technology. */
279
+ .surf-chart[data-density='compact'] {
280
+ gap: var(--surf-space-2);
281
+ }
282
+ .surf-chart[data-density='compact']
283
+ :is(
284
+ .surf-chart-caption,
285
+ .surf-chart-help,
286
+ .surf-chart-inspector,
287
+ .surf-chart-x-label
288
+ ) {
289
+ position: absolute;
290
+ inline-size: 1px;
291
+ block-size: 1px;
292
+ min-height: 0;
293
+ margin: 0;
294
+ padding: 0;
295
+ overflow: hidden;
296
+ clip-path: inset(50%);
297
+ white-space: nowrap;
298
+ }
299
+ .surf-chart[data-density='compact']
300
+ :is(.surf-chart-legend-button, .surf-chart-legend-reference) {
301
+ min-height: var(--surf-space-6);
302
+ padding-block: 0;
303
+ font-size: var(--surf-type-compact-size);
304
+ line-height: var(--surf-type-compact-leading);
305
+ }
234
306
  @media (max-width: 760px), (pointer: coarse) {
235
- .surf-chart-legend-button {
307
+ .surf-chart-legend-button,
308
+ .surf-chart[data-density='compact'] .surf-chart-legend-button {
236
309
  min-height: var(--surf-control-target-size);
237
310
  }
238
311
  }
@@ -251,6 +324,12 @@
251
324
  --surf-chart-category-4: CanvasText;
252
325
  --surf-chart-category-5: CanvasText;
253
326
  --surf-chart-category-6: CanvasText;
327
+ --surf-chart-category-7: CanvasText;
328
+ --surf-chart-category-8: CanvasText;
329
+ --surf-chart-category-9: CanvasText;
330
+ --surf-chart-category-10: CanvasText;
331
+ --surf-chart-category-11: CanvasText;
332
+ --surf-chart-category-12: CanvasText;
254
333
  }
255
334
  .surf-chart-plot .recharts-surface,
256
335
  .surf-chart-mark {
@@ -39,7 +39,10 @@
39
39
  .surf-radio:hover:not([data-disabled], [data-readonly]),
40
40
  .surf-switch:hover:not([data-disabled], [data-readonly]) {
41
41
  border-color: var(--surf-control-choice-hover-border);
42
- background: var(--surf-control-hover-background);
42
+ background-image: linear-gradient(
43
+ var(--surf-interaction-hover-bg),
44
+ var(--surf-interaction-hover-bg)
45
+ );
43
46
  }
44
47
  .surf-checkbox:is([data-checked], [data-indeterminate]),
45
48
  .surf-radio[data-checked],
@@ -54,7 +57,10 @@
54
57
  [data-disabled],
55
58
  [data-readonly]
56
59
  ) {
57
- background: var(--surf-control-hover-background);
60
+ background-image: linear-gradient(
61
+ var(--surf-interaction-hover-bg),
62
+ var(--surf-interaction-hover-bg)
63
+ );
58
64
  border-color: var(--surf-control-choice-hover-border);
59
65
  }
60
66
  :is(.surf-checkbox, .surf-radio, .surf-switch):is(
@@ -103,6 +109,24 @@
103
109
  ) {
104
110
  border-color: var(--surf-status-danger-fg);
105
111
  }
112
+ /* On touch and narrow screens a ChoiceLabel makes the whole row the target. A
113
+ choice without one, such as a table row's checkbox, keeps its size and reaches
114
+ --surf-control-target-size around it instead. */
115
+ @media (max-width: 760px), (pointer: coarse) {
116
+ :is(.surf-checkbox, .surf-radio, .surf-switch):not(.surf-choice-label *) {
117
+ position: relative;
118
+ }
119
+ :is(.surf-checkbox, .surf-radio, .surf-switch):not(
120
+ .surf-choice-label *
121
+ )::after {
122
+ content: '';
123
+ position: absolute;
124
+ inset: 50% auto auto 50%;
125
+ inline-size: max(100%, var(--surf-control-target-size));
126
+ block-size: max(100%, var(--surf-control-target-size));
127
+ translate: -50% -50%;
128
+ }
129
+ }
106
130
  @media (forced-colors: active) {
107
131
  .surf-checkbox,
108
132
  .surf-radio,
@@ -28,19 +28,10 @@
28
28
  var(--surf-font-body);
29
29
  letter-spacing: var(--surf-type-body-tracking);
30
30
  outline: none;
31
- transition:
32
- opacity var(--surf-duration-fast) var(--surf-ease-out),
33
- transform var(--surf-duration-fast) var(--surf-ease-out);
34
31
  }
35
- .surf-combobox-popup[data-starting-style] {
36
- opacity: 0;
37
- transform: translateY(4px);
38
- }
39
- .surf-combobox-popup[data-ending-style] {
40
- opacity: 0;
41
- transition: none;
42
- }
43
- .surf-combobox-list {
32
+ /* In its popup the list scrolls itself. An inline list leaves scrolling to the
33
+ container it is placed in, such as a ScrollArea. */
34
+ .surf-combobox-popup .surf-combobox-list {
44
35
  max-height: min(280px, var(--available-height));
45
36
  overflow: auto;
46
37
  }
@@ -61,11 +52,16 @@
61
52
  outline: none;
62
53
  overflow-wrap: anywhere;
63
54
  }
55
+ /* The highlight is a layer over the selected fill, so the keyboard position
56
+ shows on a chosen option too. */
64
57
  .surf-combobox-item[data-highlighted] {
65
- background: var(--surf-menu-hover-background);
58
+ background-image: linear-gradient(
59
+ var(--surf-interaction-hover-bg),
60
+ var(--surf-interaction-hover-bg)
61
+ );
66
62
  }
67
63
  .surf-combobox-item[data-selected] {
68
- background: var(--surf-selected);
64
+ background-color: var(--surf-selected);
69
65
  }
70
66
  .surf-combobox-item[data-disabled] {
71
67
  opacity: var(--surf-control-disabled-opacity);
@@ -117,7 +113,7 @@
117
113
  gap: var(--surf-space-1);
118
114
  padding-inline-start: var(--surf-space-3);
119
115
  border-radius: var(--surf-radius-pill);
120
- background: var(--surf-selected);
116
+ background-color: var(--surf-selected);
121
117
  color: var(--surf-ink);
122
118
  font-size: var(--surf-type-caption-size);
123
119
  line-height: var(--surf-type-caption-leading);
@@ -143,7 +139,12 @@
143
139
  }
144
140
  }
145
141
  @media (forced-colors: active) {
146
- .surf-combobox-item:is([data-selected], [data-highlighted]) {
142
+ .surf-combobox-item[data-highlighted] {
143
+ outline: 1px solid CanvasText;
144
+ outline-offset: -1px;
145
+ }
146
+ /* A chosen value keeps its chip edge when its fill is gone. */
147
+ .surf-combobox-chip {
147
148
  outline: 1px solid CanvasText;
148
149
  outline-offset: -1px;
149
150
  }
@@ -0,0 +1,118 @@
1
+ /* Dashboard, with the styles of what it renders. */
2
+ @layer surflane.tokens, surflane.themes, surflane.base, surflane.components,
3
+ surflane.sizes;
4
+
5
+ @layer surflane.components {
6
+ /* As many columns as fit a panel's minimum width; one on a phone. */
7
+ .surf-dashboard {
8
+ --surf-dashboard-panel-min-width: 20rem;
9
+ --surf-dashboard-gap: var(--surf-space-4);
10
+ display: grid;
11
+ grid-template-columns: repeat(
12
+ auto-fill,
13
+ minmax(min(100%, var(--surf-dashboard-panel-min-width)), 1fr)
14
+ );
15
+ gap: var(--surf-dashboard-gap);
16
+ min-inline-size: 0;
17
+ }
18
+ /* columns caps the count: a column is never narrower than its share of that many. */
19
+ .surf-dashboard[data-columns] {
20
+ grid-template-columns: repeat(
21
+ auto-fill,
22
+ minmax(
23
+ min(
24
+ 100%,
25
+ max(
26
+ var(--surf-dashboard-panel-min-width),
27
+ (
28
+ 100% - (var(--surf-dashboard-columns) - 1) *
29
+ var(--surf-dashboard-gap)
30
+ ) /
31
+ var(--surf-dashboard-columns)
32
+ )
33
+ ),
34
+ 1fr
35
+ )
36
+ );
37
+ }
38
+ /* The header keeps its height; the content takes the rest of a stretched row. */
39
+ .surf-dashboard-panel {
40
+ grid-template-rows: auto minmax(0, 1fr);
41
+ align-content: start;
42
+ min-inline-size: 0;
43
+ }
44
+ .surf-dashboard-panel[data-span='2'] {
45
+ grid-column: span 2;
46
+ }
47
+ .surf-dashboard-panel[data-span='3'] {
48
+ grid-column: span 3;
49
+ }
50
+ .surf-dashboard-panel[data-span='full'] {
51
+ grid-column: 1 / -1;
52
+ }
53
+ /* As tall as an icon button, with or without one, so titles line up across a row. */
54
+ .surf-dashboard-panel-header {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: var(--surf-space-2);
58
+ min-inline-size: 0;
59
+ min-block-size: var(--surf-control-height);
60
+ }
61
+ .surf-dashboard-panel-header .surf-card-title {
62
+ min-inline-size: 0;
63
+ overflow: hidden;
64
+ text-overflow: ellipsis;
65
+ white-space: nowrap;
66
+ border-radius: var(--surf-radius-sm);
67
+ }
68
+ /* The title takes focus after Retry; a keyboard reader sees where they are. */
69
+ .surf-dashboard-panel-header .surf-card-title:focus-visible {
70
+ outline: var(--surf-focus-ring-width) solid var(--surf-interaction-focus);
71
+ outline-offset: var(--surf-focus-ring-offset);
72
+ }
73
+ .surf-dashboard-panel-header .surf-card-title:focus:not(:focus-visible) {
74
+ outline: none;
75
+ }
76
+ .surf-dashboard-panel-actions {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: var(--surf-space-1);
80
+ margin-inline-start: auto;
81
+ }
82
+ .surf-dashboard-panel-body {
83
+ min-inline-size: 0;
84
+ min-block-size: 0;
85
+ }
86
+ /* A stale panel keeps its last content under the caution. */
87
+ .surf-dashboard-panel[data-state='stale'] > .surf-dashboard-panel-body {
88
+ display: grid;
89
+ align-content: start;
90
+ gap: var(--surf-space-3);
91
+ }
92
+ .surf-dashboard-panel-empty {
93
+ margin: 0;
94
+ color: var(--surf-ink-muted);
95
+ }
96
+ /* A phone shows one panel a row, whatever it spans. */
97
+ @media (max-width: 760px) {
98
+ .surf-dashboard-panel[data-span] {
99
+ grid-column: auto;
100
+ }
101
+ }
102
+ }
103
+ @layer surflane.sizes {
104
+ /* Compact density: panels sit 12px apart. The card inside tightens itself. */
105
+ :where(
106
+ [data-ui-density='compact'],
107
+ [data-ui-density='compact'] *
108
+ ).surf-dashboard {
109
+ --surf-dashboard-gap: var(--surf-ui-density-gap);
110
+ }
111
+ :where(
112
+ [data-ui-density='compact'],
113
+ [data-ui-density='compact'] *
114
+ ).surf-dashboard-panel[data-state='stale']
115
+ > .surf-dashboard-panel-body {
116
+ gap: var(--surf-ui-density-inset);
117
+ }
118
+ }
@@ -31,7 +31,10 @@
31
31
  }
32
32
  :is(.surf-date-picker, .surf-time-field):not([data-disabled], [data-readonly])
33
33
  .surf-date-group:hover:not([data-focus-within], :focus-within) {
34
- background: var(--surf-control-hover-background);
34
+ background-image: linear-gradient(
35
+ var(--surf-interaction-hover-bg),
36
+ var(--surf-interaction-hover-bg)
37
+ );
35
38
  border-color: var(--surf-control-hover-border);
36
39
  }
37
40
  .surf-date-group[data-focus-within],
@@ -55,14 +58,14 @@
55
58
  :is(.surf-date-picker, .surf-time-field)[data-disabled] .surf-date-group {
56
59
  opacity: var(--surf-control-disabled-opacity);
57
60
  cursor: not-allowed;
58
- background: var(--surf-control-disabled-background);
61
+ background: var(--surf-recessed);
59
62
  }
60
- /* Read-only shows a value, not a box to type in: it sits on the surface plane
63
+ /* Read-only shows a value, not a box to type in: it sits on the recessed step
61
64
  without the field's border, as text fields do. */
62
65
  :is(.surf-date-picker, .surf-time-field)[data-readonly]:not([data-invalid])
63
66
  .surf-date-group:not([data-focus-within], :focus-within) {
64
67
  border-color: transparent;
65
- background: var(--surf-surface);
68
+ background: var(--surf-recessed);
66
69
  }
67
70
  .surf-date-input {
68
71
  display: flex;
@@ -73,6 +76,11 @@
73
76
  font: var(--surf-weight-regular)
74
77
  var(--surf-type-body-size)/var(--surf-type-body-leading)
75
78
  var(--surf-font-body);
79
+ /* iOS zooms the page into a focused segment whose text is under 16px. */
80
+ font-size: max(
81
+ var(--surf-control-text-min-size),
82
+ var(--surf-type-body-size)
83
+ );
76
84
  white-space: nowrap;
77
85
  }
78
86
  .surf-date-segment {
@@ -88,10 +96,12 @@
88
96
  .surf-date-segment[data-placeholder] {
89
97
  color: var(--surf-control-placeholder);
90
98
  }
99
+ /* The group carries the focus halo; the segment being typed into is marked
100
+ like a selected table row, a selected fill told apart by its 3:1 edge. */
91
101
  .surf-date-segment[data-focused] {
92
- background: var(--surf-selected);
102
+ background-color: var(--surf-selected);
93
103
  color: var(--surf-ink);
94
- outline: 1px solid var(--surf-control-focus);
104
+ box-shadow: inset 0 0 0 1px var(--surf-selected-edge);
95
105
  }
96
106
  .surf-date-range-inputs {
97
107
  display: flex;
@@ -128,13 +138,19 @@
128
138
  :is(.surf-date-trigger, .surf-calendar-nav)[data-hovered]:not(
129
139
  [data-disabled]
130
140
  ) {
131
- background: var(--surf-selected);
141
+ background-image: linear-gradient(
142
+ var(--surf-interaction-hover-bg),
143
+ var(--surf-interaction-hover-bg)
144
+ );
132
145
  }
133
146
  :is(.surf-date-trigger, .surf-calendar-nav)[data-focus-visible] {
134
147
  outline: var(--surf-focus-ring-width) solid var(--surf-interaction-focus);
135
148
  outline-offset: var(--surf-focus-ring-offset);
136
149
  }
137
- :is(.surf-date-trigger, .surf-calendar-nav)[data-disabled] {
150
+ /* A disabled field has faded its trigger with the group already. */
151
+ :is(.surf-date-trigger, .surf-calendar-nav)[data-disabled]:not(
152
+ [data-disabled] *
153
+ ) {
138
154
  opacity: var(--surf-control-disabled-opacity);
139
155
  cursor: not-allowed;
140
156
  }
@@ -145,9 +161,9 @@
145
161
  overflow: auto;
146
162
  overscroll-behavior: contain;
147
163
  padding: var(--surf-space-2);
148
- border: 1px solid var(--surf-line);
164
+ border: 1px solid var(--surf-menu-border);
149
165
  border-radius: var(--surf-radius-lg);
150
- background: var(--surf-canvas);
166
+ background: var(--surf-menu-background);
151
167
  color: var(--surf-ink);
152
168
  box-shadow: var(--surf-shadow-float);
153
169
  z-index: var(--surf-layer-popup);
@@ -204,19 +220,19 @@
204
220
  outline: none;
205
221
  font-variant-numeric: tabular-nums;
206
222
  }
207
- .surf-calendar-day[data-hovered]:not(
208
- [data-disabled],
209
- [data-unavailable],
210
- [data-selected]
211
- ) {
212
- background: var(--surf-hover);
223
+ /* Hover is a layer, over a selected day's fill too. */
224
+ .surf-calendar-day[data-hovered]:not([data-disabled], [data-unavailable]) {
225
+ background-image: linear-gradient(
226
+ var(--surf-interaction-hover-bg),
227
+ var(--surf-interaction-hover-bg)
228
+ );
213
229
  }
214
230
  .surf-calendar-day[data-selected] {
215
- background: var(--surf-selected);
231
+ background-color: var(--surf-selected);
216
232
  color: var(--surf-ink);
217
233
  }
218
234
  .surf-calendar-day:is([data-selection-start], [data-selection-end]) {
219
- background: var(--surf-brand-mark);
235
+ background-color: var(--surf-brand-mark);
220
236
  color: var(--surf-on-brand);
221
237
  }
222
238
  .surf-calendar-day[data-focus-visible] {
@@ -238,12 +254,12 @@
238
254
  @media (max-width: 760px), (pointer: coarse) {
239
255
  .surf-date-trigger,
240
256
  .surf-calendar-nav {
241
- width: 40px;
242
- height: 40px;
243
- min-width: 40px;
257
+ width: var(--surf-control-target-size);
258
+ height: var(--surf-control-target-size);
259
+ min-width: var(--surf-control-target-size);
244
260
  }
245
261
  .surf-calendar-day {
246
- min-height: 40px;
262
+ min-height: var(--surf-control-target-size);
247
263
  }
248
264
  }
249
265
  @media (prefers-reduced-motion: reduce) {
@@ -267,10 +283,12 @@
267
283
  color: HighlightText;
268
284
  forced-color-adjust: none;
269
285
  }
270
- .surf-calendar-day[data-focus-visible],
271
- .surf-date-segment[data-focused] {
286
+ .surf-calendar-day[data-focus-visible] {
272
287
  outline-color: Highlight;
273
288
  }
289
+ .surf-date-segment[data-focused] {
290
+ outline: 1px solid Highlight;
291
+ }
274
292
  }
275
293
  .surf-calendar-grid :is(th, td) {
276
294
  padding: 0;
@@ -278,8 +296,13 @@
278
296
  min-width: 0;
279
297
  text-align: center;
280
298
  }
281
- .surf-calendar-day[data-focus-visible][data-selected] {
282
- outline-color: var(--surf-ink);
299
+ /* The ring sits inside the day. On a range end's brand fill the focus color
300
+ can match the fill, so it takes the color written on that fill. */
301
+ .surf-calendar-day:is(
302
+ [data-selection-start],
303
+ [data-selection-end]
304
+ )[data-focus-visible] {
305
+ outline-color: var(--surf-on-brand);
283
306
  }
284
307
  }
285
308
  @layer surflane.sizes {
@@ -287,7 +310,7 @@
287
310
  .surf-date-input,
288
311
  .surf-date-segment
289
312
  ) {
290
- font-size: var(--surf-ui-font);
313
+ font-size: max(var(--surf-control-text-min-size), var(--surf-ui-font));
291
314
  line-height: var(--surf-ui-leading);
292
315
  }
293
316
  :where([data-ui-size], [data-ui-size] *):is(.surf-date-trigger) > svg {