@pathscale/ui 3.1.0 → 3.2.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 (60) hide show
  1. package/README.md +13 -2
  2. package/dist/components/accordion/Accordion.css +24 -1
  3. package/dist/components/alert/Alert.css +11 -1
  4. package/dist/components/button/Button.css +33 -6
  5. package/dist/components/calendar/Calendar.generated.d.ts +19 -2
  6. package/dist/components/calendar/Calendar.generated.js +30 -23
  7. package/dist/components/calendar/index.d.ts +1 -1
  8. package/dist/components/card/Card.generated.d.ts +17 -0
  9. package/dist/components/card/Card.generated.js +99 -45
  10. package/dist/components/card/Card.interactions.d.ts +70 -0
  11. package/dist/components/card/Card.interactions.js +19 -0
  12. package/dist/components/collapsible/Collapsible.css +17 -1
  13. package/dist/components/color-wheel-flower/ColorWheelFlower.generated.d.ts +8 -0
  14. package/dist/components/color-wheel-flower/ColorWheelFlower.generated.js +14 -1
  15. package/dist/components/color-wheel-flower/colorWheelFlowerContext.d.ts +9 -2
  16. package/dist/components/color-wheel-flower/colorWheelFlowerContext.js +2 -4
  17. package/dist/components/date-picker/DatePicker.generated.d.ts +3 -1
  18. package/dist/components/date-picker/DatePicker.generated.js +8 -5
  19. package/dist/components/date-range-picker/DateRangePicker.generated.d.ts +3 -1
  20. package/dist/components/date-range-picker/DateRangePicker.generated.js +9 -6
  21. package/dist/components/drawer/Drawer.generated.d.ts +24 -0
  22. package/dist/components/drawer/Drawer.generated.js +48 -18
  23. package/dist/components/icon/Icon.generated.d.ts +15 -0
  24. package/dist/components/icon/Icon.generated.js +11 -2
  25. package/dist/components/immersive-landing/ImmersiveLanding.css +1 -1
  26. package/dist/components/immersive-landing/components/CookieConsent.interactions.d.ts +24 -0
  27. package/dist/components/immersive-landing/components/CookieConsent.interactions.js +2 -0
  28. package/dist/components/immersive-landing/components/CookieConsent.js +52 -47
  29. package/dist/components/immersive-landing/components/FirefoxPWABanner.js +10 -10
  30. package/dist/components/immersive-landing/types.d.ts +15 -0
  31. package/dist/components/language-switcher/LanguageSwitcher.generated.js +1 -1
  32. package/dist/components/live-chat/LiveChatPanel.generated.js +2 -6
  33. package/dist/components/live-chat/LiveChatPanel.interactions.d.ts +21 -0
  34. package/dist/components/live-chat/LiveChatPanel.interactions.js +10 -0
  35. package/dist/components/popover/Popover.a11y.d.ts +47 -0
  36. package/dist/components/popover/Popover.a11y.js +19 -0
  37. package/dist/components/popover/Popover.generated.d.ts +26 -0
  38. package/dist/components/popover/Popover.generated.js +105 -35
  39. package/dist/components/range-calendar/RangeCalendar.generated.d.ts +3 -1
  40. package/dist/components/range-calendar/RangeCalendar.generated.js +4 -1
  41. package/dist/components/table/MobileListView.generated.js +1 -1
  42. package/dist/components/text/Text.generated.d.ts +26 -1
  43. package/dist/components/text/Text.generated.js +13 -8
  44. package/dist/components/text/index.d.ts +1 -1
  45. package/dist/components/theme-color-picker/ThemeColorPicker.generated.js +1 -1
  46. package/dist/hooks/date/date.names.d.ts +107 -0
  47. package/dist/hooks/date/date.names.js +74 -0
  48. package/dist/hooks/date/date.utils.d.ts +11 -1
  49. package/dist/hooks/date/date.utils.js +3 -6
  50. package/dist/hooks/date/index.d.ts +1 -0
  51. package/dist/hooks/date/index.js +1 -0
  52. package/dist/hooks/date/useCalendarState.d.ts +12 -5
  53. package/dist/hooks/date/useCalendarState.js +7 -19
  54. package/dist/hooks/form/createForm.d.ts +4 -4
  55. package/dist/hooks/form/createForm.js +7 -9
  56. package/dist/index.d.ts +3 -3
  57. package/dist/index.js +1 -1
  58. package/dist/layouts.manifest.json +4 -1
  59. package/dist/responsive-classes.txt +450 -0
  60. package/package.json +10 -5
@@ -0,0 +1,70 @@
1
+ /**
2
+ * What an interactive card *is*, as one function.
3
+ *
4
+ * `isInteractive` gave a card `role="button"` and `tabindex="0"` with no way
5
+ * off either. That is right for a card that is the only activatable thing in
6
+ * its box, and wrong the moment a card is put inside a link, which is the
7
+ * ordinary way to make a whole card navigate. Measured on one site: every card
8
+ * on it was a `button` inside a `link`, same name, same box. Nested
9
+ * interactive content is invalid HTML, a reader hears the card twice, and a
10
+ * press by coordinate lands on whichever of the two is on top.
11
+ *
12
+ * Three things come out of this, and the first is what fixes the sites without
13
+ * anyone editing a call site. A card is announced as a button when it looks
14
+ * pressable *and has something to press*: `<a href><Card isInteractive /></a>`
15
+ * hands the card no handler, because the anchor is what navigates, so the card
16
+ * stops claiming to be a button and the nesting goes away where it stands.
17
+ * `isInteractive` was doing two jobs at once and only one of them survives
18
+ * inside a link: it is how a card asks for hover and press affordance, which is
19
+ * exactly what a card inside a link wants, and all it wants.
20
+ *
21
+ * The second is `href`: a card that navigates should *be* the anchor rather
22
+ * than sit inside one, exactly as `Button` already does. The third is an
23
+ * explicit `role`, which was accepted and then half-ignored --
24
+ * `role="presentation"` left `tabindex="0"` behind, so the escape hatch
25
+ * produced a presentational element that was still in the tab order and still
26
+ * announced as focusable.
27
+ *
28
+ * A `.layout.tsx` binds free identifiers to props, so the rule lives beside
29
+ * the markup rather than inside it, and the repository's tests are pure.
30
+ */
31
+ import type { JSX } from "@solidjs/web";
32
+ type RoleAttribute = JSX.HTMLAttributes<HTMLElement>["role"];
33
+ type TabIndexAttribute = JSX.HTMLAttributes<HTMLElement>["tabindex"];
34
+ type Role = Exclude<RoleAttribute, false | undefined>;
35
+ type TabIndex = Exclude<TabIndexAttribute, false | undefined>;
36
+ export type CardSemanticsInput = {
37
+ href?: string | false;
38
+ isInteractive?: boolean;
39
+ /**
40
+ * Whether the card has an activation of its own.
41
+ *
42
+ * This is the half that fixes the fleet without anyone editing a call site.
43
+ * `<a href><Card isInteractive /></a>` gives the card no handler: the anchor
44
+ * is what navigates. A card with nothing to activate is not a button, so it
45
+ * stops claiming to be one, and the nesting goes away where it is.
46
+ *
47
+ * `isInteractive` alone was read as "announce this as a button", and it
48
+ * cannot be: it is also how a card asks for hover and press *affordance*,
49
+ * which is exactly what a card inside a link wants and all it wants.
50
+ */
51
+ hasActivation?: boolean;
52
+ /** An explicit `role` from the call site. Wins outright. */
53
+ role?: RoleAttribute;
54
+ /** An explicit `tabindex` from the call site. Wins outright. */
55
+ tabindex?: TabIndexAttribute;
56
+ };
57
+ export type CardSemantics = {
58
+ element: "a" | "div";
59
+ role: Role | undefined;
60
+ tabindex: TabIndex | undefined;
61
+ /**
62
+ * Whether the card has to implement Enter and Space itself.
63
+ *
64
+ * Only a `div` wearing `role="button"` does. An anchor activates on Enter
65
+ * natively, and a presentational card activates on nothing.
66
+ */
67
+ handlesKeyboardActivation: boolean;
68
+ };
69
+ export declare const cardSemantics: (input: CardSemanticsInput) => CardSemantics;
70
+ export {};
@@ -0,0 +1,19 @@
1
+ const given = (value)=>false === value || void 0 === value ? void 0 : value;
2
+ const cardSemantics = (input)=>{
3
+ const role = given(input.role);
4
+ const tabindex = given(input.tabindex);
5
+ if ("string" == typeof input.href) return {
6
+ element: "a",
7
+ role,
8
+ tabindex,
9
+ handlesKeyboardActivation: false
10
+ };
11
+ const resolvedRole = role ?? (input.isInteractive && input.hasActivation ? "button" : void 0);
12
+ return {
13
+ element: "div",
14
+ role: resolvedRole,
15
+ tabindex: tabindex ?? ("button" === resolvedRole ? 0 : void 0),
16
+ handlesKeyboardActivation: "button" === resolvedRole
17
+ };
18
+ };
19
+ export { cardSemantics };
@@ -50,19 +50,35 @@
50
50
  transform: rotate(-180deg);
51
51
  }
52
52
 
53
+ /*
54
+ * A closed panel is out of the page, not merely flattened. Same fault and
55
+ * same fix as `.accordion__content`: `keepMounted` is the default, so a
56
+ * closed panel stays in the document carrying `aria-hidden="true"` while
57
+ * everything inside it kept `visibility: visible` and stayed in the tab
58
+ * order. Tab moved focus into a panel nobody can see, inside an
59
+ * `aria-hidden` subtree, which is the one thing `aria-hidden` must never
60
+ * contain.
61
+ */
53
62
  .collapsible__content {
54
63
  display: grid;
55
64
  grid-template-rows: 0fr;
56
65
  opacity: 0;
57
66
  overflow: hidden;
67
+ visibility: hidden;
58
68
  transition:
59
69
  grid-template-rows 200ms ease,
60
- opacity 200ms ease;
70
+ opacity 200ms ease,
71
+ visibility 0s linear 200ms;
61
72
  }
62
73
 
63
74
  .collapsible__content[data-expanded="true"] {
64
75
  grid-template-rows: 1fr;
65
76
  opacity: 1;
77
+ visibility: visible;
78
+ transition:
79
+ grid-template-rows 200ms ease,
80
+ opacity 200ms ease,
81
+ visibility 0s linear 0s;
66
82
  }
67
83
 
68
84
  .collapsible__body {
@@ -1,5 +1,6 @@
1
1
  import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./ColorWheelFlower.css";
3
+ import { type ColorValue } from "./ColorUtils";
3
4
  import { type ColorWheelFlowerMode } from "./ColorWheelFlower.palette";
4
5
  export interface ColorWheelFlowerProps {
5
6
  /** Stable base for the flower and each interactive petal. */
@@ -9,6 +10,13 @@ export interface ColorWheelFlowerProps {
9
10
  mode?: ColorWheelFlowerMode;
10
11
  /** Exactly 31 literal colors, ordered outer ring, middle ring, inner ring, center. */
11
12
  palette?: readonly string[];
13
+ /** Controlled selection. A hex, `rgb()` or `hsl()` string, or a parsed value. */
14
+ color?: ColorValue | string;
15
+ /** Initial selection when uncontrolled. */
16
+ defaultColor?: ColorValue | string;
17
+ disabled?: boolean;
18
+ /** The colour a petal was clicked to choose. */
19
+ onChange?: (color: ColorValue) => void;
12
20
  }
13
21
  declare const ColorWheelFlower: __LayoutComponent<ColorWheelFlowerProps>;
14
22
  export default ColorWheelFlower;
@@ -231,7 +231,20 @@ function buildColors(palette) {
231
231
  }
232
232
  const CENTER_INDEX = LAYOUT.findIndex((l)=>l.isCenter);
233
233
  const __solidLayoutColorWheelFlower = (_stable, p)=>{
234
- const context = useColorPickerContext();
234
+ const providedContext = useColorPickerContext();
235
+ const toColorValue = (value)=>void 0 === value ? null : "string" == typeof value ? parseColor(value) : value;
236
+ const WHITE = createColorFromHsl(0, 0, 100, 1);
237
+ const [standaloneColor, setStandaloneColor] = createSignal(toColorValue(p.defaultColor) ?? WHITE);
238
+ const context = providedContext ?? {
239
+ color: ()=>toColorValue(p.color) ?? standaloneColor(),
240
+ format: ()=>"hex",
241
+ disabled: ()=>Boolean(p.disabled),
242
+ onChange: (next)=>{
243
+ if (void 0 === p.color) setStandaloneColor(next);
244
+ p.onChange?.(next);
245
+ },
246
+ onFormatChange: ()=>{}
247
+ };
235
248
  const [selectedIndex, setSelectedIndex] = createSignal(null);
236
249
  const [pulseState, setPulseState] = createSignal(null);
237
250
  const [currentTheme, setCurrentTheme] = createSignal("u" > typeof document && "dark" === document.documentElement.getAttribute("data-theme") ? "dark" : "light");
@@ -7,5 +7,12 @@ export interface ColorPickerContextType {
7
7
  onChange: (color: ColorValue) => void;
8
8
  onFormatChange: (format: ColorFormat) => void;
9
9
  }
10
- export declare const ColorPickerContext: import("solid-js").Context<ColorPickerContextType | undefined>;
11
- export declare function useColorPickerContext(): ColorPickerContextType;
10
+ export declare const ColorPickerContext: import("solid-js").Context<ColorPickerContextType | null>;
11
+ /**
12
+ * The surrounding picker's state, or `null` when there is no picker.
13
+ *
14
+ * Returning `null` rather than throwing is deliberate: a consumer that can
15
+ * stand alone decides for itself what to do without a provider, and one that
16
+ * genuinely cannot say so in its own words.
17
+ */
18
+ export declare function useColorPickerContext(): ColorPickerContextType | null;
@@ -1,8 +1,6 @@
1
1
  import { createContext, useContext } from "solid-js";
2
- const ColorPickerContext = createContext(void 0);
2
+ const ColorPickerContext = createContext(null);
3
3
  function useColorPickerContext() {
4
- const context = useContext(ColorPickerContext);
5
- if (!context) throw new Error("useColorPickerContext must be used within a ColorPickerContext.Provider");
6
- return context;
4
+ return useContext(ColorPickerContext);
7
5
  }
8
6
  export { ColorPickerContext, useColorPickerContext };
@@ -1,7 +1,7 @@
1
1
  import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./DatePicker.css";
3
3
  import type { JSX } from "@solidjs/web";
4
- import { type CalendarWeekdayFormat } from "../calendar";
4
+ import { type CalendarWeekdayFormat, type DateNames } from "../calendar";
5
5
  import type { UIBaseProps, State } from "../vocabulary";
6
6
  type DatePickerBaseProps = {
7
7
  value?: Date;
@@ -13,6 +13,8 @@ type DatePickerBaseProps = {
13
13
  name?: string;
14
14
  placeholder?: string;
15
15
  locale?: string;
16
+ /** Month and weekday names for a language other than English. See `Calendar`. */
17
+ dateNames?: DateNames;
16
18
  weekdayFormat?: CalendarWeekdayFormat;
17
19
  minValue?: Date;
18
20
  maxValue?: Date;
@@ -3,12 +3,12 @@ import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./DatePicker.css";
4
4
  import { Show, createMemo, createUniqueId, omit } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
- import { formatDate, toISODate, useDateSelection, usePickerOpenState } from "../../hooks/date/index.js";
6
+ import { formatDate, resolveDateNames, toISODate, useDateSelection, usePickerOpenState } from "../../hooks/date/index.js";
7
7
  import calendar from "../calendar/index.js";
8
8
  import { CLASSES, componentRecipe } from "./DatePicker.recipe.js";
9
9
  var _tmpl$ = /*#__PURE__*/ template("<input type=hidden>"), _tmpl$2 = /*#__PURE__*/ template("<div>"), _tmpl$3 = /*#__PURE__*/ template("<div><button><span></span><span><svg><rect x=3 y=4 width=18 height=18 rx=2 ry=2></rect><line x1=16 y1=2 x2=16 y2=6></line><line x1=8 y1=2 x2=8 y2=6></line><line x1=3 y1=10 x2=21 y2=10></line></svg></span></button><!>");
10
10
  const __solidLayoutDatePicker = (_stable, p)=>{
11
- const others = omit(p, "class", "dataTheme", "style", "ref", "value", "defaultValue", "onChange", "open", "defaultOpen", "onOpenChange", "name", "placeholder", "locale", "weekdayFormat", "minValue", "maxValue", "isDateUnavailable", "state", "disabled");
11
+ const others = omit(p, "class", "dataTheme", "style", "ref", "value", "defaultValue", "onChange", "open", "defaultOpen", "onOpenChange", "name", "placeholder", "locale", "dateNames", "weekdayFormat", "minValue", "maxValue", "isDateUnavailable", "state", "disabled");
12
12
  const isDisabled = createMemo(()=>Boolean("disabled" === p.state) || Boolean(p.disabled));
13
13
  const selection = useDateSelection({
14
14
  value: ()=>p.value,
@@ -21,11 +21,11 @@ const __solidLayoutDatePicker = (_stable, p)=>{
21
21
  onOpenChange: ()=>p.onOpenChange,
22
22
  isDisabled
23
23
  });
24
- const locale = createMemo(()=>p.locale ?? "en-US");
24
+ const dateNames = createMemo(()=>resolveDateNames(p.locale, p.dateNames).names);
25
25
  const displayValue = createMemo(()=>{
26
26
  const selectedDate = selection.selectedDate();
27
27
  if (!selectedDate) return p.placeholder ?? "Select date";
28
- return formatDate(selectedDate, locale());
28
+ return formatDate(selectedDate, dateNames());
29
29
  });
30
30
  const uniqueId = createUniqueId();
31
31
  const popoverId = `date-picker-popover-${uniqueId}`;
@@ -154,7 +154,10 @@ const __solidLayoutDatePicker = (_stable, p)=>{
154
154
  },
155
155
  onChange: handleDateChange,
156
156
  get locale () {
157
- return locale();
157
+ return p.locale;
158
+ },
159
+ get dateNames () {
160
+ return p.dateNames;
158
161
  },
159
162
  get weekdayFormat () {
160
163
  return p.weekdayFormat;
@@ -2,7 +2,7 @@ import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./DateRangePicker.css";
3
3
  import type { JSX } from "@solidjs/web";
4
4
  import { type ControlledDateRangeValue } from "../../hooks/date";
5
- import { type CalendarWeekdayFormat } from "../calendar";
5
+ import { type CalendarWeekdayFormat, type DateNames } from "../calendar";
6
6
  import type { UIBaseProps, State } from "../vocabulary";
7
7
  export type DateRangeValue = ControlledDateRangeValue;
8
8
  type DateRangePickerBaseProps = {
@@ -17,6 +17,8 @@ type DateRangePickerBaseProps = {
17
17
  startPlaceholder?: string;
18
18
  endPlaceholder?: string;
19
19
  locale?: string;
20
+ /** Month and weekday names for a language other than English. See `Calendar`. */
21
+ dateNames?: DateNames;
20
22
  weekdayFormat?: CalendarWeekdayFormat;
21
23
  minValue?: Date;
22
24
  maxValue?: Date;
@@ -3,12 +3,12 @@ import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./DateRangePicker.css";
4
4
  import { Show, createMemo, createTrackedEffect, createUniqueId, omit } from "solid-js";
5
5
  import { twMerge } from "../../lib/twMerge.js";
6
- import { formatDate, toISODate, usePickerOpenState, useRangeSelection } from "../../hooks/date/index.js";
6
+ import { formatDate, resolveDateNames, toISODate, usePickerOpenState, useRangeSelection } from "../../hooks/date/index.js";
7
7
  import calendar from "../calendar/index.js";
8
8
  import { CLASSES, componentRecipe } from "./DateRangePicker.recipe.js";
9
9
  var _tmpl$ = /*#__PURE__*/ template("<input type=hidden>"), _tmpl$2 = /*#__PURE__*/ template("<div>"), _tmpl$3 = /*#__PURE__*/ template("<div><!><button><span></span><span>-</span><span></span><span><svg><rect x=3 y=4 width=18 height=18 rx=2 ry=2></rect><line x1=16 y1=2 x2=16 y2=6></line><line x1=8 y1=2 x2=8 y2=6></line><line x1=3 y1=10 x2=21 y2=10></line></svg></span></button><!>");
10
10
  const __solidLayoutDateRangePicker = (_stable, p)=>{
11
- const others = omit(p, "class", "dataTheme", "style", "ref", "value", "defaultValue", "onChange", "open", "defaultOpen", "onOpenChange", "startName", "endName", "startPlaceholder", "endPlaceholder", "locale", "weekdayFormat", "minValue", "maxValue", "isDateUnavailable", "state", "disabled");
11
+ const others = omit(p, "class", "dataTheme", "style", "ref", "value", "defaultValue", "onChange", "open", "defaultOpen", "onOpenChange", "startName", "endName", "startPlaceholder", "endPlaceholder", "locale", "dateNames", "weekdayFormat", "minValue", "maxValue", "isDateUnavailable", "state", "disabled");
12
12
  const isDisabled = createMemo(()=>Boolean("disabled" === p.state) || Boolean(p.disabled));
13
13
  const rangeSelection = useRangeSelection({
14
14
  value: ()=>p.value,
@@ -25,17 +25,17 @@ const __solidLayoutDateRangePicker = (_stable, p)=>{
25
25
  if (openState.isOpen()) return;
26
26
  rangeSelection.clearPendingSelection();
27
27
  });
28
- const locale = createMemo(()=>p.locale ?? "en-US");
28
+ const dateNames = createMemo(()=>resolveDateNames(p.locale, p.dateNames).names);
29
29
  const startValue = createMemo(()=>rangeSelection.rangeStart());
30
30
  const endValue = createMemo(()=>rangeSelection.rangeEnd());
31
31
  const focusDate = createMemo(()=>rangeSelection.focusDate());
32
32
  const startDisplay = createMemo(()=>{
33
33
  if (!startValue()) return p.startPlaceholder ?? "Start date";
34
- return formatDate(startValue(), locale());
34
+ return formatDate(startValue(), dateNames());
35
35
  });
36
36
  const endDisplay = createMemo(()=>{
37
37
  if (!endValue()) return p.endPlaceholder ?? "End date";
38
- return formatDate(endValue(), locale());
38
+ return formatDate(endValue(), dateNames());
39
39
  });
40
40
  const handleDateSelect = (date)=>{
41
41
  const wasSelectingEnd = rangeSelection.isSelectingEnd();
@@ -208,7 +208,10 @@ const __solidLayoutDateRangePicker = (_stable, p)=>{
208
208
  return rangeSelection.setHoverDate;
209
209
  },
210
210
  get locale () {
211
- return locale();
211
+ return p.locale;
212
+ },
213
+ get dateNames () {
214
+ return p.dateNames;
212
215
  },
213
216
  get weekdayFormat () {
214
217
  return p.weekdayFormat;
@@ -1,5 +1,6 @@
1
1
  import type { Component as __LayoutComponent } from "solid-js";
2
2
  import "./Drawer.css";
3
+ import { type ValidComponent } from "solid-js";
3
4
  import { type JSX } from "@solidjs/web";
4
5
  import "../_shared/material.css";
5
6
  import type { Material, UIBaseProps } from "../vocabulary";
@@ -22,6 +23,29 @@ export type DrawerRootProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, "children
22
23
  };
23
24
  export type DrawerTriggerProps = Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, "children"> & UIBaseProps & {
24
25
  children: JSX.Element;
26
+ /**
27
+ * The component to be the trigger, instead of a bare button.
28
+ *
29
+ * `Drawer.Trigger` renders a `button`, which is right when the trigger is
30
+ * a word or a glyph and wrong when the call site hands it a control:
31
+ * `<Drawer.Trigger><Button>Menu</Button></Drawer.Trigger>` produced a
32
+ * `button` wrapping a `button` at an identical box with an identical name,
33
+ * so every trigger was announced twice and the press by coordinate landed
34
+ * on the outer one rather than on the control that was written. Nested
35
+ * interactive content is also invalid HTML.
36
+ *
37
+ * `as` makes the control *be* the trigger, so there is one element:
38
+ *
39
+ * ```tsx
40
+ * <Drawer.Trigger as={Button} variant="ghost">Menu</Drawer.Trigger>
41
+ * ```
42
+ *
43
+ * The wiring and anything else written here go to the delegate. The
44
+ * trigger's own class is a button reset and is dropped, because a control
45
+ * does not want one; so is `data-slot="drawer-trigger"`, since the
46
+ * delegate's recipe owns that attribute.
47
+ */
48
+ as?: ValidComponent;
25
49
  };
26
50
  export type DrawerBackdropProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, "children"> & UIBaseProps & {
27
51
  children: JSX.Element;
@@ -1,4 +1,4 @@
1
- import { Portal, className, createComponent, delegateEvents, effect, insert, memo, mergeProps, ref, spread, template } from "@solidjs/web";
1
+ import { Dynamic, Portal, className, createComponent, delegateEvents, effect, insert, memo, mergeProps, ref, spread, template } from "@solidjs/web";
2
2
  import { defineComponent } from "solid-layouts/solid-2/application-boundary";
3
3
  import "./Drawer.css";
4
4
  import { Show, createSignal, createTrackedEffect, createUniqueId, omit, onCleanup } from "solid-js";
@@ -179,36 +179,66 @@ const DrawerRoot = defineComponent({
179
179
  ]
180
180
  });
181
181
  const __solidLayoutDrawerTrigger = (_stable, p)=>{
182
- const others = omit(p, "children", "class", "dataTheme", "style", "onClick");
182
+ const others = omit(p, "children", "class", "dataTheme", "style", "onClick", "as");
183
183
  const ctx = useDrawerContext();
184
184
  const handleClick = (event)=>{
185
185
  ctx.setIsOpen(true);
186
186
  if ("function" == typeof p.onClick) p.onClick(event);
187
187
  };
188
- var _el$2 = _tmpl$2();
189
- spread(_el$2, mergeProps(others, {
190
- type: "button",
191
- get ["class"] () {
192
- return twMerge(CLASSES.Trigger.base, p.class);
193
- },
194
- "data-slot": "drawer-trigger",
195
- get ["data-theme"] () {
196
- return p.dataTheme;
188
+ return createComponent(Show, {
189
+ get when () {
190
+ return p.as;
197
191
  },
198
- get style () {
199
- return p.style;
192
+ get fallback () {
193
+ var _el$2 = _tmpl$2();
194
+ spread(_el$2, mergeProps(others, {
195
+ type: "button",
196
+ get ["class"] () {
197
+ return twMerge(CLASSES.Trigger.base, p.class);
198
+ },
199
+ "data-slot": "drawer-trigger",
200
+ get ["data-theme"] () {
201
+ return p.dataTheme;
202
+ },
203
+ get style () {
204
+ return p.style;
205
+ },
206
+ onClick: handleClick
207
+ }), true);
208
+ insert(_el$2, ()=>p.children);
209
+ return _el$2;
200
210
  },
201
- onClick: handleClick
202
- }), true);
203
- insert(_el$2, ()=>p.children);
204
- return _el$2;
211
+ get children () {
212
+ return createComponent(Dynamic, mergeProps({
213
+ get component () {
214
+ return p.as;
215
+ }
216
+ }, others, {
217
+ type: "button",
218
+ get ["class"] () {
219
+ return p.class;
220
+ },
221
+ get ["data-theme"] () {
222
+ return p.dataTheme;
223
+ },
224
+ get style () {
225
+ return p.style;
226
+ },
227
+ onClick: handleClick,
228
+ get children () {
229
+ return p.children;
230
+ }
231
+ }));
232
+ }
233
+ });
205
234
  };
206
235
  const DrawerTrigger = defineComponent({
207
236
  recipe: componentRecipe,
208
237
  layout: __solidLayoutDrawerTrigger,
209
238
  embedded: true,
210
239
  behaviour: [
211
- "children"
240
+ "children",
241
+ "as"
212
242
  ]
213
243
  });
214
244
  const __solidLayoutDrawerContent = (_stable, p)=>{
@@ -19,5 +19,20 @@ export type IconProps = UIBaseProps & {
19
19
  width?: number;
20
20
  height?: number;
21
21
  flavor?: Flavor;
22
+ /**
23
+ * What this icon means, for an icon that carries meaning on its own.
24
+ *
25
+ * Most icons sit beside a label that already says it, and repeating it makes
26
+ * a reader hear the same thing twice; those stay hidden, which is the
27
+ * default and stays the default. The ones that need this are the icons that
28
+ * *are* the label: a status glyph in a table cell, a lone mark in a square
29
+ * button, a trend arrow next to a bare number.
30
+ *
31
+ * Setting it swaps `aria-hidden="true"` for `role="img"` and this name. The
32
+ * default was right and there was simply no way off it: `aria-hidden` was
33
+ * written straight into the markup, so it survived any `aria-label` a call
34
+ * site passed through and the icon stayed out of the tree regardless.
35
+ */
36
+ label?: string;
22
37
  };
23
38
  export declare const IconLayout: __LayoutComponent<IconProps>;
@@ -21,7 +21,15 @@ const __solidLayoutIconLayout = (_stable, p)=>(()=>{
21
21
  get ["data-source"] () {
22
22
  return "string" == typeof p.src ? "preload" : "svg";
23
23
  },
24
- "aria-hidden": "true"
24
+ get role () {
25
+ return p.label ? "img" : void 0;
26
+ },
27
+ get ["aria-label"] () {
28
+ return p.label;
29
+ },
30
+ get ["aria-hidden"] () {
31
+ return p.label ? void 0 : "true";
32
+ }
25
33
  }), true);
26
34
  insert(_el$, createComponent(Show, {
27
35
  get when () {
@@ -53,7 +61,8 @@ const IconLayout = defineComponent({
53
61
  "src",
54
62
  "width",
55
63
  "height",
56
- "flavor"
64
+ "flavor",
65
+ "label"
57
66
  ]
58
67
  });
59
68
  export { IconLayout };
@@ -358,7 +358,7 @@
358
358
  .immersive-landing-cookie__manage-button {
359
359
  border: 0;
360
360
  background: transparent;
361
- color: color-mix(in oklab, var(--color-base-content) 70%, transparent);
361
+ color: var(--color-base-content);
362
362
  font-size: 0.875rem;
363
363
  text-decoration: underline;
364
364
  cursor: pointer;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Whether a press on the preferences backdrop should dismiss the dialog.
3
+ *
4
+ * The backdrop closes the dialog and is an ancestor of the panel, so every
5
+ * press inside the panel reaches it too. The panel guarded itself the usual
6
+ * way, with `stopPropagation()` on its own click handler, and that guard does
7
+ * not hold in the browser engine the fleet ships: `stopPropagation` is defined
8
+ * there, but event dispatch is deferred, so the host has finished propagating
9
+ * before it calls into the page and the call is a no-op. The engine expresses
10
+ * the same intent as a flag fixed when the listener is registered, which means
11
+ * no runtime call can ever express it. Measured on two sites: pressing
12
+ * Analytics or Marketing closed the whole dialog, so no category could be
13
+ * changed at all.
14
+ *
15
+ * Comparing the press target against the element the handler is bound to needs
16
+ * nothing from the engine beyond the two properties every event already
17
+ * carries. A press that started inside the panel reports the panel, or
18
+ * something under it, as its target, and only a press that landed on the
19
+ * backdrop itself reports the backdrop.
20
+ */
21
+ export declare const dismissesOnBackdropPress: (event: {
22
+ target: EventTarget | null;
23
+ currentTarget: EventTarget | null;
24
+ }) => boolean;
@@ -0,0 +1,2 @@
1
+ const dismissesOnBackdropPress = (event)=>event.target === event.currentTarget;
2
+ export { dismissesOnBackdropPress };