@blakesteve/roster 4.8.0 → 4.8.1

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.
package/README.md CHANGED
@@ -152,6 +152,12 @@ makes no difference, because the portal is still a descendant. If you scope
152
152
  the field and carries it across the portal, so the menu follows the same scope
153
153
  the trigger is in.
154
154
 
155
+ That mechanism carries the `.dark` CLASS across the portal. It does not carry
156
+ custom properties: `--roster-popover-*` and any other variable you scope to a
157
+ container reach the trigger and stop at the portal boundary, because the panel
158
+ is not a descendant of your container. Set those at `:root`. See
159
+ [Floating surface colors](#floating-surface-colors).
160
+
155
161
  `Navbar`'s `themeMode` prop is a different thing: it describes what palette the
156
162
  bar paints _itself_ with. Pair them with `themeMode="auto"` and the nav follows
157
163
  whatever `ThemeToggle` sets.
@@ -403,6 +409,56 @@ One caveat worth knowing before you lean on these: like `--roster-card-*`,
403
409
  inside `@layer base` is outranked, and an override scoped to a subtree rather
404
410
  than the document root will not reach them.
405
411
 
412
+ ### Floating surface colors
413
+
414
+ `Select`'s menu, `Dialog`'s `white` variant and `Tooltip`'s `themed` variant
415
+ read these, so one palette covers every panel that floats over the page.
416
+
417
+ ```css
418
+ :root {
419
+ --roster-popover-bg: #fff;
420
+ --roster-popover-border: #e7e5e4;
421
+ --roster-popover-text: #1c1917;
422
+ }
423
+ .dark {
424
+ --roster-popover-bg: #292524;
425
+ --roster-popover-border: #44403c;
426
+ --roster-popover-text: #f5f5f4;
427
+ }
428
+ ```
429
+
430
+ Separate from `--roster-control-*` on purpose, and the default is the reason:
431
+ `--roster-control-bg` is `transparent`, which is right for a field drawn on a
432
+ page and actively broken for a panel drawn over one. A control and the menu it
433
+ opens are also legitimately different surfaces in plenty of palettes.
434
+
435
+ **Set these at `:root`, not on a container.** The menu and the tooltip bubble
436
+ are portaled to `<body>`, so they are not descendants of whatever you rendered
437
+ the component inside: properties set on a wrapper reach the trigger and stop
438
+ there. Any ancestor of `<body>` works — `:root` is simply the one that always
439
+ is, which is also why the `.dark` block below reaches a menu whose `.dark`
440
+ scope `Select` copies across the portal. The result is a themed trigger opening an unthemed panel, which is the
441
+ exact problem this family exists to fix. Set them in both scopes too, for the
442
+ same reason the control family needs both.
443
+
444
+ Where each component takes them, and why not everywhere:
445
+
446
+ - **`Select`'s menu** has no variants, so it reads all three outright — panel
447
+ fill, hairline, and the option labels, which are `text-inherit` so the text
448
+ token actually reaches the only text in the panel.
449
+ - **`Dialog`** takes them in `white` only. `slate`, `primary` and `glass` each
450
+ name a specific surface, and a token that meant something different inside
451
+ each name would not be a token. The defaults are `white`'s previous values
452
+ exactly, in both schemes, so nothing moves.
453
+ - **`Tooltip`** has a `themed` variant that reads them. Its `dark` and `light`
454
+ variants are untouched: `dark` is the default, an inverted bubble that
455
+ deliberately reads the same on a light or a dark page, and pointing that at a
456
+ token whose light default is white would not theme it, it would delete it.
457
+
458
+ One appearance change ships with this: `Select`'s menu ring moves from
459
+ `black/5` to `--roster-gray-200` in light mode, which is the hairline the rest
460
+ of the library already draws.
461
+
406
462
  ### Reaching the control
407
463
 
408
464
  `className` on a field component lands on the outer `Field` wrapper. That is
@@ -411,12 +467,20 @@ cannot reach the element that draws the border, the height or the font.
411
467
 
412
468
  Every field therefore has a second prop, **named for the element it reaches**:
413
469
 
414
- | Component | Wrapper | The control itself |
415
- | -------------- | ----------- | -------------------- |
416
- | `Input` | `className` | `inputClassName` |
417
- | `PasswordInput`| `className` | `inputClassName` |
418
- | `Select` | `className` | `triggerClassName` |
419
- | `Textarea` | `className` | `textareaClassName` |
470
+ | Component | Wrapper | The control itself | Other inner parts |
471
+ | -------------- | ----------- | -------------------- | ------------------- |
472
+ | `Input` | `className` | `inputClassName` | — |
473
+ | `PasswordInput`| `className` | `inputClassName` | — |
474
+ | `Select` | `className` | `triggerClassName` | `optionsClassName` |
475
+ | `Textarea` | `className` | `textareaClassName` | — |
476
+
477
+ `Select` is the first component with two styleable inner parts, which is the
478
+ case the naming scheme was chosen for: `optionsClassName` reaches the popup
479
+ panel. One caveat that is a property of Headless UI rather than of this prop —
480
+ the panel's `max-height` and `overflow` are written inline by its `size`
481
+ middleware, so a height passed here lands in the class list and is outranked.
482
+ To cap the menu, set the variable that inline rule reads:
483
+ `optionsClassName="rst:[--anchor-max-height:20rem]"`.
420
484
 
421
485
  The names differ on purpose. A single `controlClassName` would name a concept
422
486
  rather than an element, and it breaks the first time a component has two
@@ -23,6 +23,22 @@ export interface SelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
23
23
  * is the escape hatch for the rest. Mirrors `Input`'s `inputClassName`.
24
24
  */
25
25
  triggerClassName?: string;
26
+ /**
27
+ * Classes for the popup panel.
28
+ *
29
+ * The escape-hatch rule already covers the wrapper (`className`) and the
30
+ * control (`triggerClassName`); the panel was the one styleable element with
31
+ * no way in. Mirrors `Input`'s `inputClassName`.
32
+ */
33
+ optionsClassName?: string;
34
+ /** Supporting text under the trigger. */
35
+ helperText?: string;
36
+ /**
37
+ * The message for an invalid selection. Implies `error`, so a caller cannot
38
+ * set the red ring and forget to say why — which is what `error` on its own
39
+ * did: a red outline and no text anywhere for anyone.
40
+ */
41
+ errorMessage?: string;
26
42
  }
27
- declare const Select: ({ options, value, onChange, placeholder, disabled, variant, size, error, className, triggerClassName, label, ...props }: SelectProps) => import("react/jsx-runtime").JSX.Element;
43
+ declare const Select: ({ options, value, onChange, placeholder, disabled, variant, size, error, className, triggerClassName, optionsClassName, helperText, errorMessage, label, ...props }: SelectProps) => import("react/jsx-runtime").JSX.Element;
28
44
  export { Select };
@@ -1,6 +1,14 @@
1
1
  import * as React from "react";
2
2
  export type TooltipPlacement = "top" | "bottom" | "left" | "right";
3
- export type TooltipVariant = "dark" | "light";
3
+ /**
4
+ * `dark` is an inverted bubble that deliberately reads the same on a light or
5
+ * a dark page, and `light` is its counterpart — both NAME a surface, so
6
+ * neither can be repointed at a consumer token without becoming something
7
+ * else. `themed` is the opt-in third: it reads `--roster-popover-*`, the same
8
+ * family Select's menu and Dialog's `white` variant read, so a host palette
9
+ * covers every floating surface at once.
10
+ */
11
+ export type TooltipVariant = "dark" | "light" | "themed";
4
12
  export interface TooltipProps {
5
13
  /** The tooltip's popup content. Accepts a string or any React node. */
6
14
  content: React.ReactNode;
package/dist/meta.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.8.0",
3
- "tests": 1100,
2
+ "version": "4.8.1",
3
+ "tests": 1117,
4
4
  "testFiles": 93
5
5
  }