plass-ui 1.6.0 → 1.7.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 (165) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/README.md +3 -1
  3. package/dist/components/accordion/PlAccordion.d.ts +13 -0
  4. package/dist/components/accordion/PlAccordion.js +1 -1
  5. package/dist/components/accordion/index.d.ts +1 -1
  6. package/dist/components/alert/PlAlert.js +1 -1
  7. package/dist/components/animate-headline/PlAnimateHeadline.d.ts +10 -1
  8. package/dist/components/animate-marquee/PlAnimateMarquee.d.ts +8 -1
  9. package/dist/components/animate-marquee/PlAnimateMarquee.js +1 -1
  10. package/dist/components/app-logo/PlAppLogo.js +1 -1
  11. package/dist/components/area-chart/PlAreaChart.d.ts +35 -6
  12. package/dist/components/area-chart/PlAreaChart.js +1 -1
  13. package/dist/components/aspect-ratio/PlAspectRatio.js +1 -1
  14. package/dist/components/avatar/PlAvatar.js +1 -1
  15. package/dist/components/back-top/PlBackTop.d.ts +5 -5
  16. package/dist/components/back-top/PlBackTop.js +1 -1
  17. package/dist/components/badge/PlBadge.js +1 -1
  18. package/dist/components/bar-chart/PlBarChart.d.ts +54 -2
  19. package/dist/components/bar-chart/PlBarChart.js +1 -1
  20. package/dist/components/blockquote/PlBlockquote.d.ts +2 -2
  21. package/dist/components/blockquote/PlBlockquote.js +1 -1
  22. package/dist/components/bottom-navigation/PlBottomNavigation.js +1 -1
  23. package/dist/components/button/PlButton.d.ts +7 -0
  24. package/dist/components/button/PlButton.js +1 -1
  25. package/dist/components/calendar/PlCalendar.js +1 -1
  26. package/dist/components/card/PlCard.d.ts +7 -4
  27. package/dist/components/carousel/PlCarousel.d.ts +14 -4
  28. package/dist/components/carousel/PlCarousel.js +1 -1
  29. package/dist/components/chat-bubble/PlChatBubble.js +1 -1
  30. package/dist/components/checkbox/PlCheckbox.js +1 -1
  31. package/dist/components/chip/PlChip.d.ts +2 -1
  32. package/dist/components/chip/PlChip.js +1 -1
  33. package/dist/components/collapsible/PlCollapsible.d.ts +11 -0
  34. package/dist/components/collapsible/PlCollapsible.js +1 -1
  35. package/dist/components/color-picker/PlColorPicker.d.ts +3 -1
  36. package/dist/components/color-picker/PlColorPicker.js +1 -1
  37. package/dist/components/combobox/PlCombobox.d.ts +11 -5
  38. package/dist/components/combobox/PlCombobox.js +1 -1
  39. package/dist/components/command-palette/PlCommandPalette.js +1 -1
  40. package/dist/components/confirm/PlConfirmProvider.js +1 -1
  41. package/dist/components/data-table/PlDataTable.d.ts +13 -2
  42. package/dist/components/data-table/PlDataTable.js +1 -1
  43. package/dist/components/drawer/PlDrawer.js +1 -1
  44. package/dist/components/fieldset/PlFieldset.js +1 -1
  45. package/dist/components/file-picker/PlFilePicker.d.ts +3 -1
  46. package/dist/components/file-picker/PlFilePicker.js +1 -1
  47. package/dist/components/floating-action-button/PlFloatingActionButton.d.ts +5 -0
  48. package/dist/components/floating-action-button/PlFloatingActionButton.js +1 -1
  49. package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.js +1 -1
  50. package/dist/components/footer/PlFooter.d.ts +3 -1
  51. package/dist/components/gallery/PlGallery.js +1 -1
  52. package/dist/components/gauge-chart/PlGaugeChart.js +1 -1
  53. package/dist/components/header/PlHeader.d.ts +4 -2
  54. package/dist/components/header/PlHeader.js +1 -1
  55. package/dist/components/heatmap-chart/PlHeatmapChart.js +1 -1
  56. package/dist/components/hover-card/PlHoverCard.js +1 -1
  57. package/dist/components/how-to-steps/PlHowToSteps.js +1 -1
  58. package/dist/components/image/PlImage.js +1 -1
  59. package/dist/components/line-chart/PlLineChart.d.ts +32 -6
  60. package/dist/components/line-chart/PlLineChart.js +1 -1
  61. package/dist/components/menu/PlMenu.js +1 -1
  62. package/dist/components/mockup/PlMockup.d.ts +5 -0
  63. package/dist/components/mockup/PlMockup.js +1 -1
  64. package/dist/components/modal/PlModal.js +1 -1
  65. package/dist/components/navigation-menu/PlNavigationMenu.d.ts +4 -3
  66. package/dist/components/navigation-menu/PlNavigationMenu.js +1 -1
  67. package/dist/components/number-field/PlNumberField.d.ts +7 -5
  68. package/dist/components/number-field/PlNumberField.js +1 -1
  69. package/dist/components/otp-field/PlOtpField.js +1 -1
  70. package/dist/components/overlay/PlOverlay.js +1 -1
  71. package/dist/components/page-layout/PlPageLayout.d.ts +14 -3
  72. package/dist/components/page-layout/PlPageLayout.js +1 -1
  73. package/dist/components/pagination/PlPagination.js +1 -1
  74. package/dist/components/panes/PlPanes.js +1 -1
  75. package/dist/components/pie-chart/PlPieChart.d.ts +26 -1
  76. package/dist/components/pie-chart/PlPieChart.js +1 -1
  77. package/dist/components/pill/PlPill.js +1 -1
  78. package/dist/components/popconfirm/PlPopconfirm.d.ts +8 -1
  79. package/dist/components/popconfirm/PlPopconfirm.js +1 -1
  80. package/dist/components/popover/PlPopover.js +1 -1
  81. package/dist/components/progress-box/PlProgressBox.js +1 -1
  82. package/dist/components/progress-circular/PlProgressCircular.js +1 -1
  83. package/dist/components/progress-linear/PlProgressLinear.js +1 -1
  84. package/dist/components/radio-group/PlRadioGroup.js +1 -1
  85. package/dist/components/rating/PlRating.js +1 -1
  86. package/dist/components/scatter-chart/PlScatterChart.js +1 -1
  87. package/dist/components/scroll-area/PlScrollArea.js +1 -1
  88. package/dist/components/segmented-button/PlSegmentedButton.js +1 -1
  89. package/dist/components/select/PlSelect.d.ts +4 -1
  90. package/dist/components/select/PlSelect.js +1 -1
  91. package/dist/components/sidebar/PlSidebar.js +1 -1
  92. package/dist/components/slider/PlSlider.js +1 -1
  93. package/dist/components/sparkline/PlSparkline.js +1 -1
  94. package/dist/components/stepper/PlStepper.js +1 -1
  95. package/dist/components/switch/PlSwitch.js +1 -1
  96. package/dist/components/table/PlTable.d.ts +11 -1
  97. package/dist/components/table/PlTable.js +1 -1
  98. package/dist/components/tabs/PlTabs.d.ts +18 -1
  99. package/dist/components/tabs/PlTabs.js +1 -1
  100. package/dist/components/text-field/PlTextField.d.ts +6 -8
  101. package/dist/components/text-field/PlTextField.js +1 -1
  102. package/dist/components/text-link/PlTextLink.js +1 -1
  103. package/dist/components/timeline-chart/PlTimelineChart.js +1 -1
  104. package/dist/components/toast/PlToast.js +1 -1
  105. package/dist/components/toggle/PlToggle.js +1 -1
  106. package/dist/components/tooltip/PlTooltip.d.ts +4 -0
  107. package/dist/components/tooltip/PlTooltip.js +1 -1
  108. package/dist/components/tour/PlTour.js +1 -1
  109. package/dist/components/transfer/PlTransfer.d.ts +5 -2
  110. package/dist/components/transfer/PlTransfer.js +1 -1
  111. package/dist/components/tree/PlTree.js +1 -1
  112. package/dist/components/window-pane/PlWindowPane.d.ts +13 -3
  113. package/dist/components/window-pane/PlWindowPane.js +1 -1
  114. package/dist/internal/animate.js +1 -1
  115. package/dist/internal/bottom-bar.d.ts +29 -0
  116. package/dist/internal/bottom-bar.js +1 -0
  117. package/dist/internal/calendar.js +1 -1
  118. package/dist/internal/chart-frame.d.ts +88 -10
  119. package/dist/internal/chart-frame.js +1 -1
  120. package/dist/internal/chart-line.d.ts +11 -6
  121. package/dist/internal/chart-line.js +1 -1
  122. package/dist/internal/chart.d.ts +149 -1
  123. package/dist/internal/chart.js +1 -1
  124. package/dist/internal/defaults.d.ts +2 -2
  125. package/dist/internal/focusable.d.ts +10 -0
  126. package/dist/internal/focusable.js +1 -1
  127. package/dist/internal/form.d.ts +29 -0
  128. package/dist/internal/form.js +1 -1
  129. package/dist/internal/glow.d.ts +32 -1
  130. package/dist/internal/glow.js +1 -1
  131. package/dist/internal/icons.d.ts +24 -0
  132. package/dist/internal/icons.js +1 -1
  133. package/dist/internal/labels.d.ts +22 -0
  134. package/dist/internal/labels.js +1 -1
  135. package/dist/internal/loading.d.ts +13 -0
  136. package/dist/internal/loading.js +1 -0
  137. package/dist/internal/mockup.js +1 -1
  138. package/dist/internal/notch.d.ts +57 -3
  139. package/dist/internal/notch.js +1 -1
  140. package/dist/internal/picker.d.ts +8 -2
  141. package/dist/internal/picker.js +1 -1
  142. package/dist/internal/progress.d.ts +17 -6
  143. package/dist/internal/progress.js +1 -1
  144. package/dist/internal/sizer.d.ts +12 -11
  145. package/dist/internal/sizer.js +1 -1
  146. package/dist/internal/steps.d.ts +0 -15
  147. package/dist/internal/steps.js +1 -1
  148. package/dist/internal/styles.d.ts +114 -8
  149. package/dist/internal/styles.js +1 -1
  150. package/dist/internal/table-scroll.d.ts +42 -0
  151. package/dist/internal/table-scroll.js +1 -0
  152. package/dist/internal/table.js +1 -1
  153. package/dist/internal/text.d.ts +8 -5
  154. package/dist/internal/window.js +1 -1
  155. package/dist/locales/de.js +1 -1
  156. package/dist/locales/es.js +1 -1
  157. package/dist/locales/fr.js +1 -1
  158. package/dist/locales/ja.js +1 -1
  159. package/dist/locales/ko.js +1 -1
  160. package/dist/locales/zh-Hans.js +1 -1
  161. package/dist/styles.css +1 -1
  162. package/dist/tailwind.css +406 -42
  163. package/dist/tokens.css +406 -42
  164. package/dist/types.d.ts +217 -13
  165. package/package.json +1 -1
package/dist/tokens.css CHANGED
@@ -175,6 +175,29 @@
175
175
  --plass-breakpoint-xl: var(--breakpoint-xl, 80rem);
176
176
  }
177
177
 
178
+ /* ---------------------------------------------------------------------------
179
+ * The room a fixed bottom bar takes
180
+ *
181
+ * A `PlBottomNavigation` or a `PlFloatingBottomNavigation` is `fixed` by
182
+ * default: held against the bottom of the window and out of the flow, so the
183
+ * end of the page is always under it, and so is a link a reader tabs to down
184
+ * there. Only the page can make room, and only if it knows how much, so a fixed
185
+ * bar measures itself — size, density, names and the home indicator included —
186
+ * and writes the answer here, on the root element, for as long as it is
187
+ * mounted. With no bar it is `0px`, so a page can reserve it unconditionally:
188
+ *
189
+ * main { padding-bottom: var(--plass-bottom-navigation-height); }
190
+ * html { scroll-padding-bottom: var(--plass-bottom-navigation-height); }
191
+ *
192
+ * On a bare `:root`, for the reason `--plass-z-portal` is. It is a reading
193
+ * rather than a setting: a bar replaces whatever is written here the moment it
194
+ * has measured itself.
195
+ * ------------------------------------------------------------------------- */
196
+
197
+ :root {
198
+ --plass-bottom-navigation-height: 0px;
199
+ }
200
+
178
201
  /* ---------------------------------------------------------------------------
179
202
  * Light theme (default)
180
203
  *
@@ -275,6 +298,20 @@
275
298
  --plass-glow-on-fill: rgb(255 255 255 / 0.18);
276
299
  --plass-flash-on-fill: rgb(255 255 255 / 0.26);
277
300
 
301
+ /* How much of that light a **field** carries, as a share of what a key gets.
302
+
303
+ A key is pressed and is finished with; a field is pressed once and then
304
+ written in for a minute, with the bloom sitting under the words being typed
305
+ and following the hand that is typing them. The same strength that reads as
306
+ a control answering a pointer reads as a stain on a paragraph. So a field
307
+ takes the family's tint at a little over half, which is enough to say the
308
+ surface answered and not enough to compete with the ink on it.
309
+
310
+ One value for both layers and for every family, because the thing being
311
+ dialled down is the effect rather than a colour. It is per-theme neither:
312
+ the tints it scales are already per-theme. */
313
+ --plass-glow-field-strength: 55%;
314
+
278
315
  /* Elevation, and how strongly a key's own colour bleeds into the shadow it
279
316
  casts. The ambient is a blue-grey rather than black: a neutral shadow over
280
317
  a blue-tinted page reads as dirt — and it is faint, because the tint below
@@ -883,6 +920,86 @@
883
920
  transition-duration: 0ms;
884
921
  }
885
922
 
923
+ /*
924
+ * The bloom steps out of the way while the surface is being typed into.
925
+ *
926
+ * A pointer resting on a field is a pointer that has been parked: the hand is
927
+ * on the keyboard, the light is no longer following anything, and what it is
928
+ * doing is sitting under the sentence being written. Fading it out on the first
929
+ * keystroke and back in on the next real pointer move costs the effect nothing —
930
+ * it only ever *meant* anything while the pointer was moving — and gives the
931
+ * text a clean sheet for as long as the reader is on the keys.
932
+ *
933
+ * Only the bloom. The flash is drawn by `:active`, which cannot be held down
934
+ * and typed through.
935
+ *
936
+ * After the `:hover` rule, and at the same specificity: that order is what makes
937
+ * this the one that wins. The component writes and clears the attribute — see
938
+ * `useFieldLight`.
939
+ */
940
+ .plass-glow[data-quiet]::before {
941
+ opacity: 0;
942
+ }
943
+
944
+ /* ---------------------------------------------------------------------------
945
+ * A fill that comes and goes with a state
946
+ *
947
+ * A `solid` toggle, a tick, a radio's ring, a switch's track, a chosen day, a
948
+ * step's bullet and the current page are glass, a groove or nothing while they
949
+ * are off and the family's gradient while they are on, and no browser eases a
950
+ * gradient to or from nothing. Set on the element itself, the gradient arrived
951
+ * in one frame and left in one. So it is a layer of its own, there in both
952
+ * states and faded by its opacity, which is the one thing about it a browser
953
+ * can ease — the way a `PlProgressBox` plate breathes.
954
+ *
955
+ * The component says when it is on with `--p-fill-on`, 0 or 1, from the state
956
+ * variants that used to set the gradient, and a control with an edge says how
957
+ * wide the edge is with `--p-fill-edge`, so the fill runs under the edge it
958
+ * turns transparent, as a background does. Both are only read here, never
959
+ * declared: this is a real class, which a consumer's own Tailwind build keeps
960
+ * outside the layer it puts utilities in, so a value declared here would beat
961
+ * the component's. Left unset, the fill is off and has no edge.
962
+ *
963
+ * Under what is drawn on the control and over its own background, which is what
964
+ * the negative depth in a box of its own is for, as the bloom's is above. It is
965
+ * in CSS rather than in Tailwind for the bloom's reason too: it is a gradient
966
+ * on a pseudo-element.
967
+ * ------------------------------------------------------------------------- */
968
+
969
+ .plass-fill {
970
+ isolation: isolate;
971
+ }
972
+
973
+ .plass-fill::before,
974
+ .plass-fill-layer {
975
+ position: absolute;
976
+ inset: calc(-1 * var(--p-fill-edge, 0px));
977
+ z-index: -1;
978
+ /* An edge as wide as the control's, and as clear, so the gradient is laid out
979
+ inside it and drawn under it exactly as the control's own background was. */
980
+ border: var(--p-fill-edge, 0px) solid transparent;
981
+ border-radius: inherit;
982
+ background-image: var(--p-fill);
983
+ opacity: var(--p-fill-on, 0);
984
+ pointer-events: none;
985
+ transition: opacity var(--plass-duration) var(--plass-ease);
986
+ }
987
+
988
+ .plass-fill::before {
989
+ content: '';
990
+ }
991
+
992
+ /*
993
+ * The same layer as an element, for a control whose two pseudo-elements are
994
+ * already the light: a `solid` `PlToggle` and a `PlPagination` page. The bloom
995
+ * is the `::before` of the same surface, which comes first, so the fill goes
996
+ * one step further down to stay under it. The surface's `.plass-glow` gives
997
+ * both depths a box of their own.
998
+ */
999
+ .plass-fill-layer {
1000
+ z-index: -2;
1001
+ }
1002
+
886
1003
  /* ---------------------------------------------------------------------------
887
1004
  * The three dots in a bubble somebody is typing into
888
1005
  *
@@ -1079,18 +1196,25 @@
1079
1196
  * a writing direction, so the measurement is turned round once, here, rather
1080
1197
  * than in four places that could disagree.
1081
1198
  *
1199
+ * A tab brought into view stops the fade's length short of the edge, through
1200
+ * `scroll-padding-inline`. The reveal is not this sheet's — the browser does it
1201
+ * for a focused tab and Base UI for the chosen one and the next one along — but
1202
+ * both honour the padding, and without it the tab they brought into view would
1203
+ * end flush with the edge, which is exactly where the fade is strongest.
1204
+ *
1082
1205
  * The mask is dropped entirely while something inside holds a visible focus
1083
- * ring. Focusing a tab scrolls it flush against the edge it came from, which is
1084
- * exactly where the fade is strongest — so the one control whose outline has to
1085
- * be legible would be the one drawn half transparent. `:focus-visible` and not
1086
- * `:focus-within`: a tab that was clicked has the focus and no ring, and a bar
1087
- * that stopped fading for the rest of the session because somebody pressed a
1088
- * tab would have lost the signal at the first interaction.
1206
+ * ring, as well: a reader walking the strip with the arrow keys is looking at
1207
+ * the ring, and the one outline on the bar that has to be legible whole should
1208
+ * not be one a fade can reach. `:focus-visible` and not `:focus-within`: a tab
1209
+ * that was clicked has the focus and no ring, and a bar that stopped fading for
1210
+ * the rest of the session because somebody pressed a tab would have lost the
1211
+ * signal at the first interaction.
1089
1212
  * ------------------------------------------------------------------------- */
1090
1213
 
1091
1214
  .plass-fade-x {
1092
1215
  --p-fade: 1.5rem;
1093
1216
 
1217
+ scroll-padding-inline: var(--p-fade);
1094
1218
  scrollbar-width: none;
1095
1219
  mask-image: linear-gradient(
1096
1220
  to right,
@@ -2110,10 +2234,11 @@
2110
2234
  * theme below declares its `fg` and `bg` on that same element — so the derived
2111
2235
  * five follow whichever theme won without being restated fourteen times.
2112
2236
  *
2113
- * The two dark palettes at the top are written twice on purpose — once for
2114
- * `dark`, once for `auto` inside a dark page — because a media query cannot be
2115
- * folded into a selector list. It is the same repetition the theme roots at the
2116
- * top of this file make, for the same reason.
2237
+ * The two house palettes are written more than once on purpose: once on the
2238
+ * block for `light` and `dark`, and again on the theme roots for `auto`, where
2239
+ * the dark one is there twice because a media query cannot be folded into a
2240
+ * selector list. It is the same repetition the theme roots at the top of this
2241
+ * file make, for the same reason.
2117
2242
  *
2118
2243
  * Every hue in the house themes is solved against its own background rather
2119
2244
  * than flipped: the light set runs dark and saturated on near-white, the dark
@@ -2125,7 +2250,8 @@
2125
2250
  * ------------------------------------------------------------------------- */
2126
2251
 
2127
2252
  .plass-code {
2128
- /* The light set, which is also what `auto` and `light` start from. */
2253
+ /* The light set, which is what `light` is and what a theme that fills only
2254
+ some of the slots starts from. */
2129
2255
  --p-code-bg: oklch(98.4% 0.003 262);
2130
2256
  --p-code-fg: oklch(30% 0.016 262);
2131
2257
 
@@ -2156,8 +2282,7 @@
2156
2282
  --p-code-mark-edge: color-mix(in oklab, var(--p-code-fg) 45%, transparent);
2157
2283
  }
2158
2284
 
2159
- .plass-code[data-code-theme='dark'],
2160
- :where(.dark, [data-theme='dark']) .plass-code[data-code-theme='auto'] {
2285
+ .plass-code[data-code-theme='dark'] {
2161
2286
  --p-code-bg: oklch(19.5% 0.014 262);
2162
2287
  --p-code-fg: oklch(90% 0.012 262);
2163
2288
 
@@ -2175,31 +2300,92 @@
2175
2300
  --p-code-del: oklch(75% 0.15 25);
2176
2301
  }
2177
2302
 
2178
- /* Both ways of forcing light are named, the same pair the token block above
2179
- answers to. `auto` means "whatever the page is", so a page that has said it
2180
- is light with `.light` and one that has said it with `[data-theme='light']`
2181
- have to leave the block light alike — otherwise the page is white and the
2182
- code on it is the one dark rectangle nobody asked for. */
2303
+ /* `auto` is the palette of the nearest element that says which theme it is in,
2304
+ however deep the nesting goes: a light preview box inside a dark page, or a
2305
+ dark panel inside that. A selector can name a dark ancestor or a light one
2306
+ but not which of the two is nearer, so the palette `auto` reads is declared
2307
+ on every theme root instead, the way the tokens at the top of this file are,
2308
+ and inheritance is what picks the nearest. The system preference is the
2309
+ root's answer when the page has not given one, and both ways of forcing
2310
+ light are named, so a page that has said it is light leaves the block light
2311
+ either way. */
2312
+ :root,
2313
+ .light,
2314
+ [data-theme='light'] {
2315
+ --p-code-auto-bg: oklch(98.4% 0.003 262);
2316
+ --p-code-auto-fg: oklch(30% 0.016 262);
2317
+
2318
+ --p-code-auto-comment: oklch(58% 0.022 262);
2319
+ --p-code-auto-keyword: oklch(48% 0.19 322);
2320
+ --p-code-auto-string: oklch(46% 0.12 148);
2321
+ --p-code-auto-number: oklch(50% 0.14 48);
2322
+ --p-code-auto-function: oklch(48% 0.17 264);
2323
+ --p-code-auto-type: oklch(45% 0.1 214);
2324
+ --p-code-auto-variable: oklch(45% 0.12 28);
2325
+ --p-code-auto-tag: oklch(48% 0.18 22);
2326
+ --p-code-auto-attr: oklch(47% 0.13 82);
2327
+ --p-code-auto-meta: oklch(52% 0.05 262);
2328
+ --p-code-auto-add: oklch(45% 0.14 152);
2329
+ --p-code-auto-del: oklch(48% 0.18 25);
2330
+ }
2331
+
2183
2332
  @media (prefers-color-scheme: dark) {
2184
- :root:not(.light):not([data-theme='light']) .plass-code[data-code-theme='auto'] {
2185
- --p-code-bg: oklch(19.5% 0.014 262);
2186
- --p-code-fg: oklch(90% 0.012 262);
2333
+ :root:not(.light):not([data-theme='light']) {
2334
+ --p-code-auto-bg: oklch(19.5% 0.014 262);
2335
+ --p-code-auto-fg: oklch(90% 0.012 262);
2187
2336
 
2188
- --p-code-comment: oklch(60% 0.024 262);
2189
- --p-code-keyword: oklch(76% 0.13 324);
2190
- --p-code-string: oklch(80% 0.13 148);
2191
- --p-code-number: oklch(81% 0.12 62);
2192
- --p-code-function: oklch(78% 0.12 258);
2193
- --p-code-type: oklch(82% 0.1 210);
2194
- --p-code-variable: oklch(82% 0.09 32);
2195
- --p-code-tag: oklch(77% 0.13 22);
2196
- --p-code-attr: oklch(85% 0.11 92);
2197
- --p-code-meta: oklch(70% 0.05 262);
2198
- --p-code-add: oklch(80% 0.14 152);
2199
- --p-code-del: oklch(75% 0.15 25);
2337
+ --p-code-auto-comment: oklch(60% 0.024 262);
2338
+ --p-code-auto-keyword: oklch(76% 0.13 324);
2339
+ --p-code-auto-string: oklch(80% 0.13 148);
2340
+ --p-code-auto-number: oklch(81% 0.12 62);
2341
+ --p-code-auto-function: oklch(78% 0.12 258);
2342
+ --p-code-auto-type: oklch(82% 0.1 210);
2343
+ --p-code-auto-variable: oklch(82% 0.09 32);
2344
+ --p-code-auto-tag: oklch(77% 0.13 22);
2345
+ --p-code-auto-attr: oklch(85% 0.11 92);
2346
+ --p-code-auto-meta: oklch(70% 0.05 262);
2347
+ --p-code-auto-add: oklch(80% 0.14 152);
2348
+ --p-code-auto-del: oklch(75% 0.15 25);
2200
2349
  }
2201
2350
  }
2202
2351
 
2352
+ .dark,
2353
+ [data-theme='dark'] {
2354
+ --p-code-auto-bg: oklch(19.5% 0.014 262);
2355
+ --p-code-auto-fg: oklch(90% 0.012 262);
2356
+
2357
+ --p-code-auto-comment: oklch(60% 0.024 262);
2358
+ --p-code-auto-keyword: oklch(76% 0.13 324);
2359
+ --p-code-auto-string: oklch(80% 0.13 148);
2360
+ --p-code-auto-number: oklch(81% 0.12 62);
2361
+ --p-code-auto-function: oklch(78% 0.12 258);
2362
+ --p-code-auto-type: oklch(82% 0.1 210);
2363
+ --p-code-auto-variable: oklch(82% 0.09 32);
2364
+ --p-code-auto-tag: oklch(77% 0.13 22);
2365
+ --p-code-auto-attr: oklch(85% 0.11 92);
2366
+ --p-code-auto-meta: oklch(70% 0.05 262);
2367
+ --p-code-auto-add: oklch(80% 0.14 152);
2368
+ --p-code-auto-del: oklch(75% 0.15 25);
2369
+ }
2370
+
2371
+ .plass-code[data-code-theme='auto'] {
2372
+ --p-code-bg: var(--p-code-auto-bg);
2373
+ --p-code-fg: var(--p-code-auto-fg);
2374
+
2375
+ --p-code-comment: var(--p-code-auto-comment);
2376
+ --p-code-keyword: var(--p-code-auto-keyword);
2377
+ --p-code-string: var(--p-code-auto-string);
2378
+ --p-code-number: var(--p-code-auto-number);
2379
+ --p-code-function: var(--p-code-auto-function);
2380
+ --p-code-type: var(--p-code-auto-type);
2381
+ --p-code-variable: var(--p-code-auto-variable);
2382
+ --p-code-tag: var(--p-code-auto-tag);
2383
+ --p-code-attr: var(--p-code-auto-attr);
2384
+ --p-code-meta: var(--p-code-auto-meta);
2385
+ --p-code-add: var(--p-code-auto-add);
2386
+ --p-code-del: var(--p-code-auto-del);
2387
+ }
2388
+
2203
2389
  /*
2204
2390
  * `mono` is the one theme that follows the page, and the only one with no hue
2205
2391
  * in it at all: the structure is carried by weight and by how far a run is
@@ -2611,6 +2797,138 @@
2611
2797
  flex-basis: 0;
2612
2798
  }
2613
2799
 
2800
+ /* ---------------------------------------------------------------------------
2801
+ * The float label
2802
+ *
2803
+ * `labelPlacement="float"`: a notched field whose label rests inside the
2804
+ * control, where the value would be written, while the control is empty,
2805
+ * nothing in the field has the focus and no popup of its is open. At rest it is
2806
+ * set the way that placeholder is — the value's size, the regular weight and
2807
+ * the muted ink — and the moment any of the three stops being true, the label
2808
+ * rises into the notch at the notch's own weight and the placeholder comes
2809
+ * back.
2810
+ *
2811
+ * `internal/notch.tsx` draws the same fieldset and legend a `notch` does and
2812
+ * hands this block its numbers as custom properties on the frame. It is CSS
2813
+ * rather than Tailwind because the condition is a relation between three
2814
+ * elements — the frame's focus, the control's emptiness and a trigger's popup
2815
+ * — and because an input can say it is empty through `:placeholder-shown`
2816
+ * before any script has run, so a server-rendered field is right on its first
2817
+ * frame.
2818
+ *
2819
+ * **The label moves on `top`, `inset-inline-start`, `font-size` and
2820
+ * `font-weight`,** never on a transform: it is set again at every size on the
2821
+ * way rather than scaled, so no frame of it is a resampled picture of the word.
2822
+ * How smoothly the weight goes is the font's to say: a variable font passes
2823
+ * through every weight between, and a font with a few fixed faces steps
2824
+ * between them. Its line box is held at the notch's height throughout, which
2825
+ * is what keeps the legend, and the edge drawn across its middle, where they
2826
+ * are while the word grows and shrinks.
2827
+ *
2828
+ * **The gap folds rather than fades.** A legend cannot fill its own gap, so the
2829
+ * legend is folded to nothing under a resting label and the fieldset draws its
2830
+ * whole top edge again. It opens at once as the label starts to rise, so the
2831
+ * word never crosses a line on its way up, and closes only once the label has
2832
+ * come all the way down, so the line never runs through it on the way down.
2833
+ * ------------------------------------------------------------------------- */
2834
+
2835
+ .plass-notch-float > fieldset > legend {
2836
+ max-width: 100%;
2837
+ white-space: nowrap;
2838
+ transition: max-width 0s;
2839
+ }
2840
+
2841
+ .plass-notch-float > fieldset > legend > * {
2842
+ display: block;
2843
+ position: relative;
2844
+ top: 0;
2845
+ inset-inline-start: 0;
2846
+ margin-inline: var(--p-notch-pad);
2847
+ line-height: var(--p-notch-leading);
2848
+ transition-property: top, inset-inline-start, font-size, font-weight, color;
2849
+ transition-duration: var(--plass-duration);
2850
+ transition-timing-function: var(--plass-ease);
2851
+ }
2852
+
2853
+ /*
2854
+ * At rest. Three ways to know the control is empty, one for each kind of
2855
+ * control: an input's `:placeholder-shown`, a select trigger's
2856
+ * `data-placeholder`, and `data-empty` on the frame from a component that knows
2857
+ * and has no control that can say so, a picker's trigger. Autofill counts as a
2858
+ * value before the reader has accepted it, since its text is already drawn where
2859
+ * the label would rest.
2860
+ *
2861
+ * The same condition is written out in front of each of the three rules below,
2862
+ * since the stylesheet ships to projects whose own build may not lower nesting.
2863
+ */
2864
+ .plass-notch-float:not(:focus-within):not(:has([data-popup-open])):is(
2865
+ [data-empty],
2866
+ :has(.plass-float-control:placeholder-shown:not(:autofill)),
2867
+ :has(.plass-float-control[data-placeholder])
2868
+ )
2869
+ > fieldset
2870
+ > legend {
2871
+ max-width: 0.01px;
2872
+ transition-delay: var(--p-float-fold, var(--plass-duration));
2873
+ /* A press on the words lands on the control under them, as it would on the
2874
+ placeholder they stand in for. A select opens on the pointer going down on
2875
+ its trigger, which a label in front of it would swallow. */
2876
+ pointer-events: none;
2877
+ }
2878
+
2879
+ .plass-notch-float:not(:focus-within):not(:has([data-popup-open])):is(
2880
+ [data-empty],
2881
+ :has(.plass-float-control:placeholder-shown:not(:autofill)),
2882
+ :has(.plass-float-control[data-placeholder])
2883
+ )
2884
+ > fieldset
2885
+ > legend
2886
+ > * {
2887
+ top: var(--p-float-y);
2888
+ inset-inline-start: var(--p-float-x, 0px);
2889
+ font-size: var(--p-float-text);
2890
+ font-weight: 400;
2891
+ color: var(--plass-muted-fg);
2892
+ }
2893
+
2894
+ .plass-notch-float:not(:focus-within):not(:has([data-popup-open])):is(
2895
+ [data-empty],
2896
+ :has(.plass-float-control:placeholder-shown:not(:autofill)),
2897
+ :has(.plass-float-control[data-placeholder])
2898
+ )
2899
+ .plass-float-control::placeholder,
2900
+ .plass-notch-float:not(:focus-within):not(:has([data-popup-open])):is(
2901
+ [data-empty],
2902
+ :has(.plass-float-control:placeholder-shown:not(:autofill)),
2903
+ :has(.plass-float-control[data-placeholder])
2904
+ )
2905
+ .plass-float-placeholder {
2906
+ color: transparent;
2907
+ }
2908
+
2909
+ /* The placeholder comes back as the label leaves, over the same time. */
2910
+ .plass-notch-float .plass-float-control::placeholder,
2911
+ .plass-notch-float .plass-float-placeholder {
2912
+ transition: color var(--plass-duration) var(--plass-ease);
2913
+ }
2914
+
2915
+ /*
2916
+ * A press that went down on the control comes up on it. The focus the press
2917
+ * hands the control ends the rest before the button is let go, so the label is
2918
+ * back in reach of the pointer while it is still lying over the words, and a
2919
+ * quick click on them came up on the label. The browser then sent the click to
2920
+ * the frame round both, and a picker that opens on a click, such as
2921
+ * `PlTreeSelect`, stayed shut. The label lets the pointer through until that
2922
+ * press is over.
2923
+ *
2924
+ * Only a press on the control: one on the label itself leaves the control out
2925
+ * of the chain `:active` marks, so clicking a risen label still focuses the
2926
+ * field.
2927
+ */
2928
+ .plass-notch-float:has(> :not(fieldset):active) > fieldset > legend {
2929
+ pointer-events: none;
2930
+ }
2931
+
2614
2932
  /* ---------------------------------------------------------------------------
2615
2933
  * Reduced motion
2616
2934
  *
@@ -2618,7 +2936,9 @@
2618
2936
  * transitions: someone who has asked for less movement is asking for state
2619
2937
  * changes to *arrive*, not to be taken away. The colours still change; they
2620
2938
  * simply stop easing, and the light stops trailing the pointer across the
2621
- * surface — it is either on the control or it is not.
2939
+ * surface — it is either on the control or it is not. The colours are the house
2940
+ * transition's, which is a set of utilities rather than a class, so it says so
2941
+ * beside itself in `internal/styles.ts`.
2622
2942
  * ------------------------------------------------------------------------- */
2623
2943
 
2624
2944
  @media (prefers-reduced-motion: reduce) {
@@ -2627,6 +2947,25 @@
2627
2947
  transition-duration: 1ms;
2628
2948
  }
2629
2949
 
2950
+ /* A fill that comes with a state arrives with it, as the colours round it
2951
+ do. */
2952
+ .plass-fill::before,
2953
+ .plass-fill-layer {
2954
+ transition-duration: 0ms;
2955
+ }
2956
+
2957
+ /* A float label arrives where it is going, and the gap under it opens and
2958
+ closes with it rather than a moment after. */
2959
+ .plass-notch-float {
2960
+ --p-float-fold: 0ms;
2961
+ }
2962
+
2963
+ .plass-notch-float > fieldset > legend > *,
2964
+ .plass-notch-float .plass-float-control::placeholder,
2965
+ .plass-notch-float .plass-float-placeholder {
2966
+ transition-duration: 0ms;
2967
+ }
2968
+
2630
2969
  /* The highlight stops travelling and the placeholder pulses in place. It is
2631
2970
  kept running rather than stopped, because a skeleton that holds still is
2632
2971
  indistinguishable from an empty box that finished loading with nothing in
@@ -2666,16 +3005,41 @@
2666
3005
  /*
2667
3006
  * The `PlAnimate*` components go the other way from the indicators above, and
2668
3007
  * the difference is what each of them is saying. A spinner that stops is
2669
- * lying about whether anything is happening; an entrance that does not play
2670
- * has still delivered its content, which is the only thing it was ever
2671
- * carrying.
3008
+ * lying about whether anything is happening; an effect that does not move has
3009
+ * still delivered what it was carrying — which for an entrance is the content
3010
+ * and for an exit is its absence.
2672
3011
  *
2673
- * `animation: none` rather than a zero duration, because the shorthand also
2674
- * clears `fill-mode` — and the fill is what was holding an untriggered
2675
- * element on its own first frame at `opacity: 0`. Left in place, respecting a
2676
- * reader's preference would blank the page.
3012
+ * So an effect is not switched off but run in no time at all. Nothing changes
3013
+ * until the moment it would have started, its `delay` included, and then it
3014
+ * is on its last frame: an exit has gone, a turn has turned, and
3015
+ * `animationend` arrives for a caller waiting on it. Until that moment the
3016
+ * element is as it is, because the fill runs forwards only — an effect
3017
+ * waiting for its trigger is held at the start of its delay, which with no
3018
+ * backwards fill draws nothing, rather than on a first frame at `opacity: 0`
3019
+ * that would blank the page. The delay is a millisecond at the least, which
3020
+ * is what keeps a waiting effect there: with no delay and no duration, a run
3021
+ * held at its very start has already finished.
3022
+ *
3023
+ * A count of `infinite` is one pass here, which `--p-anim-still-repeat`
3024
+ * says: an endless run has no last frame of its own. And a scroll-linked
3025
+ * effect goes back to the clock, because a zero duration spread over a scroll
3026
+ * range is an effect that snaps at one point of the scroll.
2677
3027
  */
2678
- .plass-anim,
3028
+ .plass-anim {
3029
+ animation-duration: 0s;
3030
+ animation-delay: max(1ms, var(--p-anim-delay, 0ms));
3031
+ animation-iteration-count: var(--p-anim-still-repeat, var(--p-anim-repeat, 1));
3032
+ animation-fill-mode: forwards;
3033
+ animation-timeline: auto;
3034
+ }
3035
+
3036
+ /* The one effect whose last frame is not the element's own: before it has
3037
+ run, a turn stands at the angle it turns to, which is what it is waiting to
3038
+ deliver. The keyframe outranks this once the run has begun. */
3039
+ .plass-anim-rotate {
3040
+ rotate: var(--p-anim-angle-to, 0deg);
3041
+ }
3042
+
2679
3043
  .plass-marquee-track,
2680
3044
  .plass-headline-item,
2681
3045
  .plass-caret {