@funstack/ui 0.1.0-alpha.3 → 0.1.0-alpha.5
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/dist/accordion/accordion-root.mjs +2 -1
- package/dist/accordion/accordion-root.mjs.map +1 -1
- package/dist/combobox/combobox-clear.mjs +2 -1
- package/dist/combobox/combobox-clear.mjs.map +1 -1
- package/dist/combobox/combobox-list.mjs +2 -1
- package/dist/combobox/combobox-list.mjs.map +1 -1
- package/dist/combobox/combobox-popup.d.mts.map +1 -1
- package/dist/combobox/combobox-popup.mjs +7 -2
- package/dist/combobox/combobox-popup.mjs.map +1 -1
- package/dist/combobox/combobox-root.mjs +1 -1
- package/dist/combobox/combobox-trigger.mjs +2 -1
- package/dist/combobox/combobox-trigger.mjs.map +1 -1
- package/dist/dialog/dialog-close.mjs +2 -1
- package/dist/dialog/dialog-close.mjs.map +1 -1
- package/dist/dialog/dialog-form.d.mts +14 -8
- package/dist/dialog/dialog-form.d.mts.map +1 -1
- package/dist/dialog/dialog-form.mjs +36 -5
- package/dist/dialog/dialog-form.mjs.map +1 -1
- package/dist/dialog/dialog-popup.d.mts.map +1 -1
- package/dist/dialog/dialog-popup.mjs +13 -5
- package/dist/dialog/dialog-popup.mjs.map +1 -1
- package/dist/dialog/dialog-root.mjs +1 -1
- package/dist/dialog/dialog-trigger.mjs +2 -1
- package/dist/dialog/dialog-trigger.mjs.map +1 -1
- package/dist/field/field-root.mjs +5 -3
- package/dist/field/field-root.mjs.map +1 -1
- package/dist/form/form-root.mjs +2 -1
- package/dist/form/form-root.mjs.map +1 -1
- package/dist/form/form-submit.mjs +2 -1
- package/dist/form/form-submit.mjs.map +1 -1
- package/dist/index.d.mts +27 -1
- package/dist/index.mjs +6 -1
- package/dist/internal/announce.mjs +53 -0
- package/dist/internal/announce.mjs.map +1 -0
- package/dist/internal/decimal.mjs +27 -0
- package/dist/internal/decimal.mjs.map +1 -0
- package/dist/internal/dev-warn.mjs +17 -0
- package/dist/internal/dev-warn.mjs.map +1 -0
- package/dist/internal/field-context.mjs.map +1 -1
- package/dist/internal/range-value.mjs +51 -0
- package/dist/internal/range-value.mjs.map +1 -0
- package/dist/internal/render-element.mjs +54 -0
- package/dist/internal/render-element.mjs.map +1 -0
- package/dist/internal/toolbar-context.mjs +17 -0
- package/dist/internal/toolbar-context.mjs.map +1 -0
- package/dist/internal/use-exit-animation.mjs +26 -6
- package/dist/internal/use-exit-animation.mjs.map +1 -1
- package/dist/internal/use-field-control.mjs +5 -3
- package/dist/internal/use-field-control.mjs.map +1 -1
- package/dist/internal/use-popover-popup.mjs +3 -2
- package/dist/internal/use-popover-popup.mjs.map +1 -1
- package/dist/internal/use-popover-trigger.mjs +1 -1
- package/dist/internal/use-render.mjs +11 -34
- package/dist/internal/use-render.mjs.map +1 -1
- package/dist/internal/use-roving-focus.mjs +301 -0
- package/dist/internal/use-roving-focus.mjs.map +1 -0
- package/dist/menu/menu-checkbox-item.mjs +2 -1
- package/dist/menu/menu-checkbox-item.mjs.map +1 -1
- package/dist/menu/menu-item.mjs +2 -1
- package/dist/menu/menu-item.mjs.map +1 -1
- package/dist/menu/menu-popup.d.mts.map +1 -1
- package/dist/menu/menu-popup.mjs +7 -2
- package/dist/menu/menu-popup.mjs.map +1 -1
- package/dist/menu/menu-radio-item.mjs +2 -1
- package/dist/menu/menu-radio-item.mjs.map +1 -1
- package/dist/menu/menu-root.mjs +1 -1
- package/dist/menu/menu-trigger.d.mts +2 -1
- package/dist/menu/menu-trigger.d.mts.map +1 -1
- package/dist/menu/menu-trigger.mjs +15 -4
- package/dist/menu/menu-trigger.mjs.map +1 -1
- package/dist/meter/index.d.mts +24 -0
- package/dist/meter/index.d.mts.map +1 -0
- package/dist/meter/index.mjs +23 -0
- package/dist/meter/index.mjs.map +1 -0
- package/dist/meter/meter-context.mjs +13 -0
- package/dist/meter/meter-context.mjs.map +1 -0
- package/dist/meter/meter-indicator.d.mts +19 -0
- package/dist/meter/meter-indicator.d.mts.map +1 -0
- package/dist/meter/meter-indicator.mjs +25 -0
- package/dist/meter/meter-indicator.mjs.map +1 -0
- package/dist/meter/meter-label.d.mts +19 -0
- package/dist/meter/meter-label.d.mts.map +1 -0
- package/dist/meter/meter-label.mjs +28 -0
- package/dist/meter/meter-label.mjs.map +1 -0
- package/dist/meter/meter-region.d.mts +4 -0
- package/dist/meter/meter-region.d.mts.map +1 -0
- package/dist/meter/meter-region.mjs +39 -0
- package/dist/meter/meter-region.mjs.map +1 -0
- package/dist/meter/meter-root.d.mts +71 -0
- package/dist/meter/meter-root.d.mts.map +1 -0
- package/dist/meter/meter-root.mjs +83 -0
- package/dist/meter/meter-root.mjs.map +1 -0
- package/dist/meter/meter-track.d.mts +19 -0
- package/dist/meter/meter-track.d.mts.map +1 -0
- package/dist/meter/meter-track.mjs +25 -0
- package/dist/meter/meter-track.mjs.map +1 -0
- package/dist/meter/meter-value.d.mts +20 -0
- package/dist/meter/meter-value.d.mts.map +1 -0
- package/dist/meter/meter-value.mjs +29 -0
- package/dist/meter/meter-value.mjs.map +1 -0
- package/dist/number-field/index.d.mts +26 -0
- package/dist/number-field/index.d.mts.map +1 -0
- package/dist/number-field/index.mjs +26 -0
- package/dist/number-field/index.mjs.map +1 -0
- package/dist/number-field/number-field-arithmetic.mjs +78 -0
- package/dist/number-field/number-field-arithmetic.mjs.map +1 -0
- package/dist/number-field/number-field-context.d.mts +2 -0
- package/dist/number-field/number-field-context.mjs +13 -0
- package/dist/number-field/number-field-context.mjs.map +1 -0
- package/dist/number-field/number-field-decrement.d.mts +16 -0
- package/dist/number-field/number-field-decrement.d.mts.map +1 -0
- package/dist/number-field/number-field-decrement.mjs +19 -0
- package/dist/number-field/number-field-decrement.mjs.map +1 -0
- package/dist/number-field/number-field-format.mjs +279 -0
- package/dist/number-field/number-field-format.mjs.map +1 -0
- package/dist/number-field/number-field-increment.d.mts +32 -0
- package/dist/number-field/number-field-increment.d.mts.map +1 -0
- package/dist/number-field/number-field-increment.mjs +68 -0
- package/dist/number-field/number-field-increment.mjs.map +1 -0
- package/dist/number-field/number-field-input.d.mts +29 -0
- package/dist/number-field/number-field-input.d.mts.map +1 -0
- package/dist/number-field/number-field-input.mjs +163 -0
- package/dist/number-field/number-field-input.mjs.map +1 -0
- package/dist/number-field/number-field-label.d.mts +23 -0
- package/dist/number-field/number-field-label.d.mts.map +1 -0
- package/dist/number-field/number-field-label.mjs +47 -0
- package/dist/number-field/number-field-label.mjs.map +1 -0
- package/dist/number-field/number-field-root.d.mts +108 -0
- package/dist/number-field/number-field-root.d.mts.map +1 -0
- package/dist/number-field/number-field-root.mjs +523 -0
- package/dist/number-field/number-field-root.mjs.map +1 -0
- package/dist/number-field/use-step-button.mjs +107 -0
- package/dist/number-field/use-step-button.mjs.map +1 -0
- package/dist/popover/popover-close.mjs +2 -1
- package/dist/popover/popover-close.mjs.map +1 -1
- package/dist/popover/popover-popup.d.mts.map +1 -1
- package/dist/popover/popover-popup.mjs +7 -2
- package/dist/popover/popover-popup.mjs.map +1 -1
- package/dist/popover/popover-root.mjs +1 -1
- package/dist/progress/index.d.mts +24 -0
- package/dist/progress/index.d.mts.map +1 -0
- package/dist/progress/index.mjs +24 -0
- package/dist/progress/index.mjs.map +1 -0
- package/dist/progress/progress-context.mjs +13 -0
- package/dist/progress/progress-context.mjs.map +1 -0
- package/dist/progress/progress-indicator.d.mts +19 -0
- package/dist/progress/progress-indicator.d.mts.map +1 -0
- package/dist/progress/progress-indicator.mjs +29 -0
- package/dist/progress/progress-indicator.mjs.map +1 -0
- package/dist/progress/progress-label.d.mts +19 -0
- package/dist/progress/progress-label.d.mts.map +1 -0
- package/dist/progress/progress-label.mjs +30 -0
- package/dist/progress/progress-label.mjs.map +1 -0
- package/dist/progress/progress-root.d.mts +68 -0
- package/dist/progress/progress-root.d.mts.map +1 -0
- package/dist/progress/progress-root.mjs +80 -0
- package/dist/progress/progress-root.mjs.map +1 -0
- package/dist/progress/progress-track.d.mts +19 -0
- package/dist/progress/progress-track.d.mts.map +1 -0
- package/dist/progress/progress-track.mjs +29 -0
- package/dist/progress/progress-track.mjs.map +1 -0
- package/dist/progress/progress-value.d.mts +20 -0
- package/dist/progress/progress-value.d.mts.map +1 -0
- package/dist/progress/progress-value.mjs +33 -0
- package/dist/progress/progress-value.mjs.map +1 -0
- package/dist/slider/slider-arithmetic.mjs +1 -17
- package/dist/slider/slider-arithmetic.mjs.map +1 -1
- package/dist/slider/slider-root.mjs +3 -2
- package/dist/slider/slider-root.mjs.map +1 -1
- package/dist/slider/slider-thumb.mjs +2 -1
- package/dist/slider/slider-thumb.mjs.map +1 -1
- package/dist/slider/slider-track.mjs +2 -1
- package/dist/slider/slider-track.mjs.map +1 -1
- package/dist/tabs/tabs-indicator.mjs +2 -1
- package/dist/tabs/tabs-indicator.mjs.map +1 -1
- package/dist/tabs/tabs-tab.mjs +2 -1
- package/dist/tabs/tabs-tab.mjs.map +1 -1
- package/dist/toast/toast-action.mjs +2 -1
- package/dist/toast/toast-action.mjs.map +1 -1
- package/dist/toast/toast-close.mjs +2 -1
- package/dist/toast/toast-close.mjs.map +1 -1
- package/dist/toast/toast-root.mjs +3 -2
- package/dist/toast/toast-root.mjs.map +1 -1
- package/dist/toast/toast-viewport.d.mts.map +1 -1
- package/dist/toast/toast-viewport.mjs +30 -7
- package/dist/toast/toast-viewport.mjs.map +1 -1
- package/dist/toast/toast.d.mts.map +1 -1
- package/dist/toast/toast.mjs +5 -1
- package/dist/toast/toast.mjs.map +1 -1
- package/dist/toggle/toggle.mjs +2 -1
- package/dist/toggle/toggle.mjs.map +1 -1
- package/dist/toggle-group/index.d.mts +16 -0
- package/dist/toggle-group/index.d.mts.map +1 -0
- package/dist/toggle-group/index.mjs +15 -0
- package/dist/toggle-group/index.mjs.map +1 -0
- package/dist/toggle-group/toggle-group-context.d.mts +4 -0
- package/dist/toggle-group/toggle-group-context.d.mts.map +1 -0
- package/dist/toggle-group/toggle-group-context.mjs +13 -0
- package/dist/toggle-group/toggle-group-context.mjs.map +1 -0
- package/dist/toggle-group/toggle-group-item.d.mts +47 -0
- package/dist/toggle-group/toggle-group-item.d.mts.map +1 -0
- package/dist/toggle-group/toggle-group-item.mjs +63 -0
- package/dist/toggle-group/toggle-group-item.mjs.map +1 -0
- package/dist/toggle-group/toggle-group-root.d.mts +95 -0
- package/dist/toggle-group/toggle-group-root.d.mts.map +1 -0
- package/dist/toggle-group/toggle-group-root.mjs +211 -0
- package/dist/toggle-group/toggle-group-root.mjs.map +1 -0
- package/dist/toolbar/index.d.mts +18 -0
- package/dist/toolbar/index.d.mts.map +1 -0
- package/dist/toolbar/index.mjs +18 -0
- package/dist/toolbar/index.mjs.map +1 -0
- package/dist/toolbar/toolbar-button.d.mts +42 -0
- package/dist/toolbar/toolbar-button.d.mts.map +1 -0
- package/dist/toolbar/toolbar-button.mjs +50 -0
- package/dist/toolbar/toolbar-button.mjs.map +1 -0
- package/dist/toolbar/toolbar-root.d.mts +38 -0
- package/dist/toolbar/toolbar-root.d.mts.map +1 -0
- package/dist/toolbar/toolbar-root.mjs +66 -0
- package/dist/toolbar/toolbar-root.mjs.map +1 -0
- package/dist/toolbar/toolbar-separator.d.mts +25 -0
- package/dist/toolbar/toolbar-separator.d.mts.map +1 -0
- package/dist/toolbar/toolbar-separator.mjs +31 -0
- package/dist/toolbar/toolbar-separator.mjs.map +1 -0
- package/dist/tooltip/tooltip-popup.mjs +2 -1
- package/dist/tooltip/tooltip-popup.mjs.map +1 -1
- package/dist/tooltip/tooltip-root.mjs +18 -2
- package/dist/tooltip/tooltip-root.mjs.map +1 -1
- package/dist/tooltip/tooltip-trigger.mjs +2 -1
- package/dist/tooltip/tooltip-trigger.mjs.map +1 -1
- package/package.json +6 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
|
-
import { resolveStateValue
|
|
3
|
+
import { resolveStateValue } from "../internal/render-element.mjs";
|
|
4
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
4
5
|
import { useTabsContext } from "./tabs-context.mjs";
|
|
5
6
|
import { anchorName } from "./tabs-ids.mjs";
|
|
6
7
|
//#region src/tabs/tabs-indicator.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs-indicator.mjs","names":[],"sources":["../../src/tabs/tabs-indicator.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport { useTabsContext } from \"./tabs-context.js\";\nimport type { TabsOrientation } from \"./tabs-context.js\";\nimport { anchorName } from \"./tabs-ids.js\";\n\nexport interface TabsIndicatorState {\n /** Optimistic selected value, or `null` (the indicator is then `hidden`). */\n readonly value: string | null;\n readonly pending: boolean;\n readonly orientation: TabsOrientation;\n}\n\nexport interface TabsIndicatorProps extends Omit<\n ComponentPropsWithRef<\"span\">,\n \"hidden\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, TabsIndicatorState>;\n style?: StateValue<CSSProperties | undefined, TabsIndicatorState>;\n children?: StateValue<ReactNode, TabsIndicatorState>;\n render?: RenderProp<ComponentPropsWithRef<\"span\">, TabsIndicatorState>;\n}\n\n/**\n * A decorative marker that follows the optimistic selection. Positioned by CSS Anchor\n * Positioning: it sets `position-anchor` to the selected Tab's `anchor-name`; the consumer's CSS\n * gives it `position: absolute` and `anchor()` insets, and a CSS `transition` on those insets\n * slides it. It must come after the Tabs inside `Tabs.List` (an anchor must precede the\n * positioned element in tree order). No `<ViewTransition>`: it changes only in optimistic (sync)\n * commits, which never start a view transition (design 10.1).\n *\n * Owned keys (conventions 1.2): `aria-hidden`, `hidden`, `data-selected`, `data-pending`.\n */\nexport function TabsIndicator({ className, style, children, render, ...rest }: TabsIndicatorProps) {\n const ctx = useTabsContext(\"Tabs.Indicator\");\n const value = ctx.optimistic;\n const state: TabsIndicatorState = {\n value,\n pending: ctx.pending,\n orientation: ctx.orientation,\n };\n const anchor = value === null ? undefined : anchorName(ctx.rootId, value);\n\n return useRender<ComponentPropsWithRef<\"span\">, TabsIndicatorState>({\n defaultElement: \"span\",\n render,\n state,\n className,\n // `position-anchor` sits under the consumer's style: the consumer wins.\n style: (s) => ({ positionAnchor: anchor, ...resolveStateValue(style, s) }),\n children,\n props: rest,\n libraryProps: {\n \"aria-hidden\": true,\n hidden: value === null,\n \"data-selected\": dataAttr(value !== null),\n \"data-pending\": dataAttr(ctx.pending),\n },\n });\n}\n\nTabsIndicator.displayName = \"TabsIndicator\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tabs-indicator.mjs","names":[],"sources":["../../src/tabs/tabs-indicator.tsx"],"sourcesContent":["\"use client\";\nimport type { ComponentPropsWithRef, CSSProperties, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport { useTabsContext } from \"./tabs-context.js\";\nimport type { TabsOrientation } from \"./tabs-context.js\";\nimport { anchorName } from \"./tabs-ids.js\";\n\nexport interface TabsIndicatorState {\n /** Optimistic selected value, or `null` (the indicator is then `hidden`). */\n readonly value: string | null;\n readonly pending: boolean;\n readonly orientation: TabsOrientation;\n}\n\nexport interface TabsIndicatorProps extends Omit<\n ComponentPropsWithRef<\"span\">,\n \"hidden\" | \"className\" | \"style\" | \"children\"\n> {\n className?: StateValue<string | undefined, TabsIndicatorState>;\n style?: StateValue<CSSProperties | undefined, TabsIndicatorState>;\n children?: StateValue<ReactNode, TabsIndicatorState>;\n render?: RenderProp<ComponentPropsWithRef<\"span\">, TabsIndicatorState>;\n}\n\n/**\n * A decorative marker that follows the optimistic selection. Positioned by CSS Anchor\n * Positioning: it sets `position-anchor` to the selected Tab's `anchor-name`; the consumer's CSS\n * gives it `position: absolute` and `anchor()` insets, and a CSS `transition` on those insets\n * slides it. It must come after the Tabs inside `Tabs.List` (an anchor must precede the\n * positioned element in tree order). No `<ViewTransition>`: it changes only in optimistic (sync)\n * commits, which never start a view transition (design 10.1).\n *\n * Owned keys (conventions 1.2): `aria-hidden`, `hidden`, `data-selected`, `data-pending`.\n */\nexport function TabsIndicator({ className, style, children, render, ...rest }: TabsIndicatorProps) {\n const ctx = useTabsContext(\"Tabs.Indicator\");\n const value = ctx.optimistic;\n const state: TabsIndicatorState = {\n value,\n pending: ctx.pending,\n orientation: ctx.orientation,\n };\n const anchor = value === null ? undefined : anchorName(ctx.rootId, value);\n\n return useRender<ComponentPropsWithRef<\"span\">, TabsIndicatorState>({\n defaultElement: \"span\",\n render,\n state,\n className,\n // `position-anchor` sits under the consumer's style: the consumer wins.\n style: (s) => ({ positionAnchor: anchor, ...resolveStateValue(style, s) }),\n children,\n props: rest,\n libraryProps: {\n \"aria-hidden\": true,\n hidden: value === null,\n \"data-selected\": dataAttr(value !== null),\n \"data-pending\": dataAttr(ctx.pending),\n },\n });\n}\n\nTabsIndicator.displayName = \"TabsIndicator\";\n"],"mappings":";;;;;;;;;;;;;;;;;AAoCA,SAAgB,cAAc,EAAE,WAAW,OAAO,UAAU,QAAQ,GAAG,QAA4B;CACjG,MAAM,MAAM,eAAe,gBAAgB;CAC3C,MAAM,QAAQ,IAAI;CAClB,MAAM,QAA4B;EAChC;EACA,SAAS,IAAI;EACb,aAAa,IAAI;CACnB;CACA,MAAM,SAAS,UAAU,OAAO,KAAA,IAAY,WAAW,IAAI,QAAQ,KAAK;CAExE,OAAO,UAA6D;EAClE,gBAAgB;EAChB;EACA;EACA;EAEA,QAAQ,OAAO;GAAE,gBAAgB;GAAQ,GAAG,kBAAkB,OAAO,CAAC;EAAE;EACxE;EACA,OAAO;EACP,cAAc;GACZ,eAAe;GACf,QAAQ,UAAU;GAClB,iBAAiB,SAAS,UAAU,IAAI;GACxC,gBAAgB,SAAS,IAAI,OAAO;EACtC;CACF,CAAC;AACH;AAEA,cAAc,cAAc"}
|
package/dist/tabs/tabs-tab.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useTransitionBoundary } from "../internal/transition-boundary.mjs";
|
|
3
3
|
import { dataAttr } from "../internal/data-attr.mjs";
|
|
4
|
-
import { rendersButton, resolveStateValue
|
|
4
|
+
import { rendersButton, resolveStateValue } from "../internal/render-element.mjs";
|
|
5
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
5
6
|
import { TabsListContext, useTabsContext } from "./tabs-context.mjs";
|
|
6
7
|
import { anchorName, panelId, tabId } from "./tabs-ids.mjs";
|
|
7
8
|
import { use } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs-tab.mjs","names":[],"sources":["../../src/tabs/tabs-tab.tsx"],"sourcesContent":["\"use client\";\nimport { use } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n ViewTransitionClass,\n} from \"react\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport { TabsListContext, useTabsContext } from \"./tabs-context.js\";\nimport type { TabsOrientation } from \"./tabs-context.js\";\nimport { anchorName, panelId, tabId } from \"./tabs-ids.js\";\n\nexport interface TabsTabState {\n readonly value: string;\n /** Optimistic: true as soon as the user selects this tab, before the action settles. */\n readonly selected: boolean;\n /** The Root is pending and this tab is the optimistic target. */\n readonly pending: boolean;\n readonly disabled: boolean;\n readonly orientation: TabsOrientation;\n}\n\nexport interface TabsTabProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"onKeyDown\" | \"onFocus\" | \"id\" | \"value\" | \"className\" | \"style\" | \"children\"\n> {\n /** The value this tab selects. Must be unique within the Root. */\n value: string;\n /** Focusable but inert: `aria-disabled=\"true\"`, never dispatches. */\n disabled?: boolean;\n /**\n * Forwarded to the Tab's `<ViewTransition default>`. Default: no boundary. Fires only on the commit\n * that settles the action (or rolls it back), never on the optimistic selection; animate the\n * selection itself with a CSS `transition` on `[data-selected]`.\n *\n * Static: without `transition` the part renders no `<ViewTransition>`; changing it between\n * `undefined` and a value remounts the element. Any value, `\"none\"` included, makes a mount or\n * `<Activity>` reveal of this part inside a transition start a document view transition: the\n * page cross-fades for about 250 ms and the next transition commit waits for it (issue #35).\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, TabsTabState>;\n style?: StateValue<CSSProperties | undefined, TabsTabState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, TabsTabState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, TabsTabState>;\n}\n\nfunction isActivationKey(event: KeyboardEvent): boolean {\n return (\n (event.key === \"Enter\" || event.key === \" \") &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey\n );\n}\n\n/** Focus came from another element inside the tab's own tablist (not from the list itself). */\nfunction movedWithinList(event: FocusEvent<HTMLElement>): boolean {\n const list = event.currentTarget.closest('[role=\"tablist\"]');\n const from = event.relatedTarget;\n return list !== null && from instanceof Node && from !== list && list.contains(from);\n}\n\n/**\n * A `button[role=tab]`. Renders the optimistic selection (`aria-selected`, `data-selected`,\n * roving `tabindex`) and carries `anchor-name` for the Indicator.\n *\n * Owned keys (conventions 1.2): `role`, `id`, `aria-selected`, `aria-controls` (token-merged),\n * `aria-disabled`, `tabIndex`, `focusgroupstart` (with `experimental_focusgroup`), `data-selected`, `data-pending`, `data-disabled`,\n * `data-orientation`, `onClick`, `onKeyDown`, `onFocus`.\n */\nexport function TabsTab({\n value,\n disabled: disabledProp = false,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: TabsTabProps) {\n const ctx = useTabsContext(\"Tabs.Tab\");\n const listCtx = use(TabsListContext);\n const selected = ctx.optimistic === value;\n const pending = ctx.pending && selected;\n const disabled = ctx.disabled || disabledProp;\n const anchor = anchorName(ctx.rootId, value);\n\n const state: TabsTabState = {\n value,\n selected,\n pending,\n disabled,\n orientation: ctx.orientation,\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, TabsTabState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n // `anchor-name` sits under the consumer's style: the consumer wins (design 13.5).\n style: (s) => ({ anchorName: anchor, ...resolveStateValue(style, s) }),\n children,\n // `type=\"button\"` only on a real button (no form submission); an `<a>` must not get it.\n props: rendersButton(render) ? { ...rest, type: \"button\" } : rest,\n libraryProps: {\n role: \"tab\",\n id: tabId(ctx.rootId, value),\n \"aria-selected\": selected,\n \"aria-controls\": panelId(ctx.rootId, value),\n \"aria-disabled\": disabled ? true : undefined,\n // Roving tabindex, except on the native `focusgroup` path, where the browser owns the tab\n // stop and a negative tabindex would take the Tab out of the group (TabsListContextValue).\n tabIndex: selected ? 0 : listCtx?.nativeFocusgroup ? undefined : -1,\n // Always rendered with the flag (inert where unsupported), so markup is stable.\n ...(listCtx?.focusgroup === true && { focusgroupstart: selected ? \"\" : undefined }),\n \"data-selected\": dataAttr(selected),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n \"data-orientation\": ctx.orientation,\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n // Enter and Space are handled on keydown so a `render`ed non-button element (a link)\n // behaves the same; `preventDefault` also stops the native click / navigation.\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => {\n if (!isActivationKey(event)) return;\n event.preventDefault();\n if (disabled) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n // Automatic activation is selection-follows-focus (design 4.1), but only for focus that\n // moves between tabs inside this list (the arrow-key path, the native `focusgroup` path,\n // programmatic movement). Focus entering from outside never selects: the Tab key, window\n // re-activation, focus restore, `autoFocus`, and the List's own redirect when no tab is the\n // tab stop. A click still selects through `onClick`.\n onFocus: (event: FocusEvent<HTMLButtonElement>) => {\n if (ctx.activationMode !== \"automatic\" || disabled || selected) return;\n if (!movedWithinList(event)) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n },\n });\n\n return useTransitionBoundary(\"Tabs.Tab\", transition, element);\n}\n\nTabsTab.displayName = \"TabsTab\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tabs-tab.mjs","names":[],"sources":["../../src/tabs/tabs-tab.tsx"],"sourcesContent":["\"use client\";\nimport { use } from \"react\";\nimport type {\n ComponentPropsWithRef,\n CSSProperties,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n ViewTransitionClass,\n} from \"react\";\nimport { useTransitionBoundary } from \"../internal/transition-boundary.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport { TabsListContext, useTabsContext } from \"./tabs-context.js\";\nimport type { TabsOrientation } from \"./tabs-context.js\";\nimport { anchorName, panelId, tabId } from \"./tabs-ids.js\";\n\nexport interface TabsTabState {\n readonly value: string;\n /** Optimistic: true as soon as the user selects this tab, before the action settles. */\n readonly selected: boolean;\n /** The Root is pending and this tab is the optimistic target. */\n readonly pending: boolean;\n readonly disabled: boolean;\n readonly orientation: TabsOrientation;\n}\n\nexport interface TabsTabProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"onKeyDown\" | \"onFocus\" | \"id\" | \"value\" | \"className\" | \"style\" | \"children\"\n> {\n /** The value this tab selects. Must be unique within the Root. */\n value: string;\n /** Focusable but inert: `aria-disabled=\"true\"`, never dispatches. */\n disabled?: boolean;\n /**\n * Forwarded to the Tab's `<ViewTransition default>`. Default: no boundary. Fires only on the commit\n * that settles the action (or rolls it back), never on the optimistic selection; animate the\n * selection itself with a CSS `transition` on `[data-selected]`.\n *\n * Static: without `transition` the part renders no `<ViewTransition>`; changing it between\n * `undefined` and a value remounts the element. Any value, `\"none\"` included, makes a mount or\n * `<Activity>` reveal of this part inside a transition start a document view transition: the\n * page cross-fades for about 250 ms and the next transition commit waits for it (issue #35).\n */\n transition?: ViewTransitionClass;\n className?: StateValue<string | undefined, TabsTabState>;\n style?: StateValue<CSSProperties | undefined, TabsTabState>;\n /** Rendered from optimistic state; must not suspend. */\n children?: StateValue<ReactNode, TabsTabState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, TabsTabState>;\n}\n\nfunction isActivationKey(event: KeyboardEvent): boolean {\n return (\n (event.key === \"Enter\" || event.key === \" \") &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey\n );\n}\n\n/** Focus came from another element inside the tab's own tablist (not from the list itself). */\nfunction movedWithinList(event: FocusEvent<HTMLElement>): boolean {\n const list = event.currentTarget.closest('[role=\"tablist\"]');\n const from = event.relatedTarget;\n return list !== null && from instanceof Node && from !== list && list.contains(from);\n}\n\n/**\n * A `button[role=tab]`. Renders the optimistic selection (`aria-selected`, `data-selected`,\n * roving `tabindex`) and carries `anchor-name` for the Indicator.\n *\n * Owned keys (conventions 1.2): `role`, `id`, `aria-selected`, `aria-controls` (token-merged),\n * `aria-disabled`, `tabIndex`, `focusgroupstart` (with `experimental_focusgroup`), `data-selected`, `data-pending`, `data-disabled`,\n * `data-orientation`, `onClick`, `onKeyDown`, `onFocus`.\n */\nexport function TabsTab({\n value,\n disabled: disabledProp = false,\n transition,\n className,\n style,\n children,\n render,\n ...rest\n}: TabsTabProps) {\n const ctx = useTabsContext(\"Tabs.Tab\");\n const listCtx = use(TabsListContext);\n const selected = ctx.optimistic === value;\n const pending = ctx.pending && selected;\n const disabled = ctx.disabled || disabledProp;\n const anchor = anchorName(ctx.rootId, value);\n\n const state: TabsTabState = {\n value,\n selected,\n pending,\n disabled,\n orientation: ctx.orientation,\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, TabsTabState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n // `anchor-name` sits under the consumer's style: the consumer wins (design 13.5).\n style: (s) => ({ anchorName: anchor, ...resolveStateValue(style, s) }),\n children,\n // `type=\"button\"` only on a real button (no form submission); an `<a>` must not get it.\n props: rendersButton(render) ? { ...rest, type: \"button\" } : rest,\n libraryProps: {\n role: \"tab\",\n id: tabId(ctx.rootId, value),\n \"aria-selected\": selected,\n \"aria-controls\": panelId(ctx.rootId, value),\n \"aria-disabled\": disabled ? true : undefined,\n // Roving tabindex, except on the native `focusgroup` path, where the browser owns the tab\n // stop and a negative tabindex would take the Tab out of the group (TabsListContextValue).\n tabIndex: selected ? 0 : listCtx?.nativeFocusgroup ? undefined : -1,\n // Always rendered with the flag (inert where unsupported), so markup is stable.\n ...(listCtx?.focusgroup === true && { focusgroupstart: selected ? \"\" : undefined }),\n \"data-selected\": dataAttr(selected),\n \"data-pending\": dataAttr(pending),\n \"data-disabled\": dataAttr(disabled),\n \"data-orientation\": ctx.orientation,\n onClick: (event: MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n // Enter and Space are handled on keydown so a `render`ed non-button element (a link)\n // behaves the same; `preventDefault` also stops the native click / navigation.\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => {\n if (!isActivationKey(event)) return;\n event.preventDefault();\n if (disabled) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n // Automatic activation is selection-follows-focus (design 4.1), but only for focus that\n // moves between tabs inside this list (the arrow-key path, the native `focusgroup` path,\n // programmatic movement). Focus entering from outside never selects: the Tab key, window\n // re-activation, focus restore, `autoFocus`, and the List's own redirect when no tab is the\n // tab stop. A click still selects through `onClick`.\n onFocus: (event: FocusEvent<HTMLButtonElement>) => {\n if (ctx.activationMode !== \"automatic\" || disabled || selected) return;\n if (!movedWithinList(event)) return;\n ctx.select(value, event.nativeEvent, \"activate\");\n },\n },\n });\n\n return useTransitionBoundary(\"Tabs.Tab\", transition, element);\n}\n\nTabsTab.displayName = \"TabsTab\";\n"],"mappings":";;;;;;;;;AAuDA,SAAS,gBAAgB,OAA+B;CACtD,QACG,MAAM,QAAQ,WAAW,MAAM,QAAQ,QACxC,CAAC,MAAM,UACP,CAAC,MAAM,WACP,CAAC,MAAM;AAEX;;AAGA,SAAS,gBAAgB,OAAyC;CAChE,MAAM,OAAO,MAAM,cAAc,QAAQ,oBAAkB;CAC3D,MAAM,OAAO,MAAM;CACnB,OAAO,SAAS,QAAQ,gBAAgB,QAAQ,SAAS,QAAQ,KAAK,SAAS,IAAI;AACrF;;;;;;;;;AAUA,SAAgB,QAAQ,EACtB,OACA,UAAU,eAAe,OACzB,YACA,WACA,OACA,UACA,QACA,GAAG,QACY;CACf,MAAM,MAAM,eAAe,UAAU;CACrC,MAAM,UAAU,IAAI,eAAe;CACnC,MAAM,WAAW,IAAI,eAAe;CACpC,MAAM,UAAU,IAAI,WAAW;CAC/B,MAAM,WAAW,IAAI,YAAY;CACjC,MAAM,SAAS,WAAW,IAAI,QAAQ,KAAK;CAE3C,MAAM,QAAsB;EAC1B;EACA;EACA;EACA;EACA,aAAa,IAAI;CACnB;CAEA,MAAM,UAAU,UAAyD;EACvE,gBAAgB;EAChB;EACA;EACA;EAEA,QAAQ,OAAO;GAAE,YAAY;GAAQ,GAAG,kBAAkB,OAAO,CAAC;EAAE;EACpE;EAEA,OAAO,cAAc,MAAM,IAAI;GAAE,GAAG;GAAM,MAAM;EAAS,IAAI;EAC7D,cAAc;GACZ,MAAM;GACN,IAAI,MAAM,IAAI,QAAQ,KAAK;GAC3B,iBAAiB;GACjB,iBAAiB,QAAQ,IAAI,QAAQ,KAAK;GAC1C,iBAAiB,WAAW,OAAO,KAAA;GAGnC,UAAU,WAAW,IAAI,SAAS,mBAAmB,KAAA,IAAY;GAEjE,GAAI,SAAS,eAAe,QAAQ,EAAE,iBAAiB,WAAW,KAAK,KAAA,EAAU;GACjF,iBAAiB,SAAS,QAAQ;GAClC,gBAAgB,SAAS,OAAO;GAChC,iBAAiB,SAAS,QAAQ;GAClC,oBAAoB,IAAI;GACxB,UAAU,UAAyC;IACjD,IAAI,UAAU;IACd,IAAI,OAAO,OAAO,MAAM,aAAa,UAAU;GACjD;GAGA,YAAY,UAA4C;IACtD,IAAI,CAAC,gBAAgB,KAAK,GAAG;IAC7B,MAAM,eAAe;IACrB,IAAI,UAAU;IACd,IAAI,OAAO,OAAO,MAAM,aAAa,UAAU;GACjD;GAMA,UAAU,UAAyC;IACjD,IAAI,IAAI,mBAAmB,eAAe,YAAY,UAAU;IAChE,IAAI,CAAC,gBAAgB,KAAK,GAAG;IAC7B,IAAI,OAAO,OAAO,MAAM,aAAa,UAAU;GACjD;EACF;CACF,CAAC;CAED,OAAO,sBAAsB,YAAY,YAAY,OAAO;AAC9D;AAEA,QAAQ,cAAc"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createActionDetails } from "../internal/action-details.mjs";
|
|
3
3
|
import { dataAttr } from "../internal/data-attr.mjs";
|
|
4
|
-
import { rendersButton
|
|
4
|
+
import { rendersButton } from "../internal/render-element.mjs";
|
|
5
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
5
6
|
import { useActionTrigger } from "../internal/use-action-trigger.mjs";
|
|
6
7
|
import { useToastRootContext } from "./toast-context.mjs";
|
|
7
8
|
import { useLayoutEffect, useState } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-action.mjs","names":[],"sources":["../../src/toast/toast-action.tsx"],"sourcesContent":["\"use client\";\nimport { useLayoutEffect, useState } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { Action, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useActionTrigger } from \"../internal/use-action-trigger.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastActionDetails, ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastActionState {\n /** This part's action is in flight. */\n readonly pending: boolean;\n readonly toast: ToastItem;\n}\n\nexport interface ToastActionProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n /**\n * Runs in this part's own transition: `data-pending` on the Action and the Root, the toast's\n * timer paused. When it resolves the toast closes with `reason: \"activate\"` (unless\n * `closeOnSettle` is `false`); a rejection keeps the toast and reaches the nearest Error\n * Boundary above the Viewport. A caught error counts as success and closes the toast: rethrow\n * after `toast.update`, or use `closeOnSettle={false}`. Default: the toast's `action.action`.\n */\n action?: Action<[details: ToastActionDetails]>;\n /** Close the toast when the action resolves. Default `true`. */\n closeOnSettle?: boolean;\n /** Default: the toast's `action.label`. */\n children?: StateValue<ReactNode, ToastActionState>;\n className?: StateValue<string | undefined, ToastActionState>;\n style?: StateValue<CSSProperties | undefined, ToastActionState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastActionState>;\n}\n\n/**\n * The toast's action button (Undo, Retry, View): a `button type=\"button\"` whose `action` runs as\n * a transition. Renders nothing when neither the part nor the toast has an action. Never disabled\n * while pending (a second click is a second dispatch, latest wins).\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`, `data-pending`.\n */\nexport function ToastAction({\n action,\n closeOnSettle = true,\n children,\n className,\n style,\n render,\n ...rest\n}: ToastActionProps) {\n const root = useToastRootContext(\"Toast.Action\");\n const { pending, run } = useActionTrigger();\n const [token] = useState(() => ({}));\n const effective = action ?? root.toast.action?.action;\n const { setActionPending } = root;\n\n // The Root (and through it the Viewport's timer) sees this part's pending state.\n useLayoutEffect(() => {\n if (!pending) return;\n setActionPending(token, true);\n return () => setActionPending(token, false);\n }, [pending, setActionPending, token]);\n\n const state: ToastActionState = { pending, toast: root.toast };\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (effective === undefined || rest.disabled === true) return;\n const native = event.nativeEvent;\n const details = createActionDetails(native, { id: root.toast.id });\n run(\n () => effective(details),\n () => {\n // A second resolve finds the toast already closed (closing is idempotent).\n if (closeOnSettle) root.close(\"activate\", native);\n },\n );\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n \"data-pending\": dataAttr(pending),\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToastActionState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children: children ?? root.toast.action?.label,\n props: rest,\n libraryProps,\n });\n return effective === undefined ? null : element;\n}\n\nToastAction.displayName = \"ToastAction\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"toast-action.mjs","names":[],"sources":["../../src/toast/toast-action.tsx"],"sourcesContent":["\"use client\";\nimport { useLayoutEffect, useState } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { Action, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useActionTrigger } from \"../internal/use-action-trigger.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastActionDetails, ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastActionState {\n /** This part's action is in flight. */\n readonly pending: boolean;\n readonly toast: ToastItem;\n}\n\nexport interface ToastActionProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n /**\n * Runs in this part's own transition: `data-pending` on the Action and the Root, the toast's\n * timer paused. When it resolves the toast closes with `reason: \"activate\"` (unless\n * `closeOnSettle` is `false`); a rejection keeps the toast and reaches the nearest Error\n * Boundary above the Viewport. A caught error counts as success and closes the toast: rethrow\n * after `toast.update`, or use `closeOnSettle={false}`. Default: the toast's `action.action`.\n */\n action?: Action<[details: ToastActionDetails]>;\n /** Close the toast when the action resolves. Default `true`. */\n closeOnSettle?: boolean;\n /** Default: the toast's `action.label`. */\n children?: StateValue<ReactNode, ToastActionState>;\n className?: StateValue<string | undefined, ToastActionState>;\n style?: StateValue<CSSProperties | undefined, ToastActionState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastActionState>;\n}\n\n/**\n * The toast's action button (Undo, Retry, View): a `button type=\"button\"` whose `action` runs as\n * a transition. Renders nothing when neither the part nor the toast has an action. Never disabled\n * while pending (a second click is a second dispatch, latest wins).\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`, `data-pending`.\n */\nexport function ToastAction({\n action,\n closeOnSettle = true,\n children,\n className,\n style,\n render,\n ...rest\n}: ToastActionProps) {\n const root = useToastRootContext(\"Toast.Action\");\n const { pending, run } = useActionTrigger();\n const [token] = useState(() => ({}));\n const effective = action ?? root.toast.action?.action;\n const { setActionPending } = root;\n\n // The Root (and through it the Viewport's timer) sees this part's pending state.\n useLayoutEffect(() => {\n if (!pending) return;\n setActionPending(token, true);\n return () => setActionPending(token, false);\n }, [pending, setActionPending, token]);\n\n const state: ToastActionState = { pending, toast: root.toast };\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (effective === undefined || rest.disabled === true) return;\n const native = event.nativeEvent;\n const details = createActionDetails(native, { id: root.toast.id });\n run(\n () => effective(details),\n () => {\n // A second resolve finds the toast already closed (closing is idempotent).\n if (closeOnSettle) root.close(\"activate\", native);\n },\n );\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n \"data-pending\": dataAttr(pending),\n };\n\n const element = useRender<ComponentPropsWithRef<\"button\">, ToastActionState>({\n defaultElement: \"button\",\n render,\n state,\n className,\n style,\n children: children ?? root.toast.action?.label,\n props: rest,\n libraryProps,\n });\n return effective === undefined ? null : element;\n}\n\nToastAction.displayName = \"ToastAction\";\n"],"mappings":";;;;;;;;;;;;;;;;AA8CA,SAAgB,YAAY,EAC1B,QACA,gBAAgB,MAChB,UACA,WACA,OACA,QACA,GAAG,QACgB;CACnB,MAAM,OAAO,oBAAoB,cAAc;CAC/C,MAAM,EAAE,SAAS,QAAQ,iBAAiB;CAC1C,MAAM,CAAC,SAAS,gBAAgB,CAAC,EAAE;CACnC,MAAM,YAAY,UAAU,KAAK,MAAM,QAAQ;CAC/C,MAAM,EAAE,qBAAqB;CAG7B,sBAAsB;EACpB,IAAI,CAAC,SAAS;EACd,iBAAiB,OAAO,IAAI;EAC5B,aAAa,iBAAiB,OAAO,KAAK;CAC5C,GAAG;EAAC;EAAS;EAAkB;CAAK,CAAC;CAErC,MAAM,QAA0B;EAAE;EAAS,OAAO,KAAK;CAAM;CAE7D,MAAM,WAAW,UAAyC;EACxD,IAAI,cAAc,KAAA,KAAa,KAAK,aAAa,MAAM;EACvD,MAAM,SAAS,MAAM;EACrB,MAAM,UAAU,oBAAoB,QAAQ,EAAE,IAAI,KAAK,MAAM,GAAG,CAAC;EACjE,UACQ,UAAU,OAAO,SACjB;GAEJ,IAAI,eAAe,KAAK,MAAM,YAAY,MAAM;EAClD,CACF;CACF;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD;EACA,gBAAgB,SAAS,OAAO;CAClC;CAEA,MAAM,UAAU,UAA6D;EAC3E,gBAAgB;EAChB;EACA;EACA;EACA;EACA,UAAU,YAAY,KAAK,MAAM,QAAQ;EACzC,OAAO;EACP;CACF,CAAC;CACD,OAAO,cAAc,KAAA,IAAY,OAAO;AAC1C;AAEA,YAAY,cAAc"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { rendersButton
|
|
2
|
+
import { rendersButton } from "../internal/render-element.mjs";
|
|
3
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
3
4
|
import { useToastRootContext } from "./toast-context.mjs";
|
|
4
5
|
import { useCallback } from "react";
|
|
5
6
|
//#region src/toast/toast-close.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-close.mjs","names":[],"sources":["../../src/toast/toast-close.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastCloseState {\n readonly toast: ToastItem;\n}\n\nexport interface ToastCloseProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n children?: StateValue<ReactNode, ToastCloseState>;\n className?: StateValue<string | undefined, ToastCloseState>;\n style?: StateValue<CSSProperties | undefined, ToastCloseState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastCloseState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Dismisses the toast (`reason: \"dismiss\"`, the same as Escape). Label it yourself (`aria-label`\n * or text). No Invoker Command: `hide-popover` would hide the whole region.\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`.\n */\nexport function ToastClose({ children, className, style, render, ...rest }: ToastCloseProps) {\n const root = useToastRootContext(\"Toast.Close\");\n\n const devRef = useCallback((element: HTMLElement) => {\n if (isDev) {\n // After the commit: the text may come from children rendered in the same commit.\n queueMicrotask(() => {\n if (!element.isConnected) return;\n const named =\n element.hasAttribute(\"aria-label\") ||\n element.hasAttribute(\"aria-labelledby\") ||\n (element.textContent ?? \"\").trim() !== \"\";\n if (!named) {\n console.error(\n \"Toast.Close: the button has no accessible name. Give it text or an `aria-label`.\",\n );\n }\n });\n }\n return () => {};\n }, []);\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (rest.disabled === true) return;\n root.close(\"dismiss\", event.nativeEvent);\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, ToastCloseState>({\n defaultElement: \"button\",\n render,\n state: { toast: root.toast },\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: devRef,\n });\n}\n\nToastClose.displayName = \"ToastClose\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"toast-close.mjs","names":[],"sources":["../../src/toast/toast-close.tsx"],"sourcesContent":["\"use client\";\nimport { useCallback } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { rendersButton, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastItem } from \"./toast.js\";\nimport { useToastRootContext } from \"./toast-context.js\";\n\nexport interface ToastCloseState {\n readonly toast: ToastItem;\n}\n\nexport interface ToastCloseProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"onClick\" | \"className\" | \"style\" | \"children\"\n> {\n children?: StateValue<ReactNode, ToastCloseState>;\n className?: StateValue<string | undefined, ToastCloseState>;\n style?: StateValue<CSSProperties | undefined, ToastCloseState>;\n render?: RenderProp<ComponentPropsWithRef<\"button\">, ToastCloseState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Dismisses the toast (`reason: \"dismiss\"`, the same as Escape). Label it yourself (`aria-label`\n * or text). No Invoker Command: `hide-popover` would hide the whole region.\n *\n * Owned keys (conventions 1.2): `type` (on a `<button>` only), `onClick`.\n */\nexport function ToastClose({ children, className, style, render, ...rest }: ToastCloseProps) {\n const root = useToastRootContext(\"Toast.Close\");\n\n const devRef = useCallback((element: HTMLElement) => {\n if (isDev) {\n // After the commit: the text may come from children rendered in the same commit.\n queueMicrotask(() => {\n if (!element.isConnected) return;\n const named =\n element.hasAttribute(\"aria-label\") ||\n element.hasAttribute(\"aria-labelledby\") ||\n (element.textContent ?? \"\").trim() !== \"\";\n if (!named) {\n console.error(\n \"Toast.Close: the button has no accessible name. Give it text or an `aria-label`.\",\n );\n }\n });\n }\n return () => {};\n }, []);\n\n const onClick = (event: MouseEvent<HTMLElement>): void => {\n if (rest.disabled === true) return;\n root.close(\"dismiss\", event.nativeEvent);\n };\n\n const libraryProps: ComponentPropsWithRef<\"button\"> & DataAttributes = {\n ...(rendersButton(render) && { type: \"button\" as const }),\n onClick,\n };\n\n return useRender<ComponentPropsWithRef<\"button\">, ToastCloseState>({\n defaultElement: \"button\",\n render,\n state: { toast: root.toast },\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: devRef,\n });\n}\n\nToastClose.displayName = \"ToastClose\";\n"],"mappings":";;;;;;AAuBA,MAAM,QAAQ,QAAQ,IAAI,aAAa;;;;;;;AAQvC,SAAgB,WAAW,EAAE,UAAU,WAAW,OAAO,QAAQ,GAAG,QAAyB;CAC3F,MAAM,OAAO,oBAAoB,aAAa;CAE9C,MAAM,SAAS,aAAa,YAAyB;EACnD,IAAI,OAEF,qBAAqB;GACnB,IAAI,CAAC,QAAQ,aAAa;GAK1B,IAAI,EAHF,QAAQ,aAAa,YAAY,KACjC,QAAQ,aAAa,iBAAiB,MACrC,QAAQ,eAAe,GAAA,CAAI,KAAK,MAAM,KAEvC,QAAQ,MACN,kFACF;EAEJ,CAAC;EAEH,aAAa,CAAC;CAChB,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,UAAyC;EACxD,IAAI,KAAK,aAAa,MAAM;EAC5B,KAAK,MAAM,WAAW,MAAM,WAAW;CACzC;CAEA,MAAM,eAAiE;EACrE,GAAI,cAAc,MAAM,KAAK,EAAE,MAAM,SAAkB;EACvD;CACF;CAEA,OAAO,UAA4D;EACjE,gBAAgB;EAChB;EACA,OAAO,EAAE,OAAO,KAAK,MAAM;EAC3B;EACA;EACA;EACA,OAAO;EACP;EACA,KAAK;CACP,CAAC;AACH;AAEA,WAAW,cAAc"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { dataAttr } from "../internal/data-attr.mjs";
|
|
3
3
|
import { useLatest } from "../internal/use-latest.mjs";
|
|
4
|
-
import { resolveStateValue
|
|
4
|
+
import { resolveStateValue } from "../internal/render-element.mjs";
|
|
5
|
+
import { useRender } from "../internal/use-render.mjs";
|
|
5
6
|
import { exitAnimations } from "../internal/use-exit-animation.mjs";
|
|
6
7
|
import { ToastRootContext, useToastRootContext, useToastViewportContext } from "./toast-context.mjs";
|
|
7
8
|
import { Suspense, useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
@@ -140,7 +141,7 @@ function ToastRoot({ toast: item, children, className, style, render, fallback =
|
|
|
140
141
|
if (!item.ending) return;
|
|
141
142
|
const element = elementRef.current;
|
|
142
143
|
const baseline = viewport.exitBaseline(item.id);
|
|
143
|
-
const animations = element === null ? [] : exitAnimations(element
|
|
144
|
+
const animations = element === null ? [] : exitAnimations(element, baseline);
|
|
144
145
|
if (animations.length === 0) {
|
|
145
146
|
viewport.drop(item.id);
|
|
146
147
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-root.mjs","names":[],"sources":["../../src/toast/toast-root.tsx"],"sourcesContent":["\"use client\";\nimport { Suspense, useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, KeyboardEvent, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { exitAnimations } from \"../internal/use-exit-animation.js\";\nimport { useLatest } from \"../internal/use-latest.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastItem, ToastPriority } from \"./toast.js\";\nimport { ToastRootContext, useToastRootContext, useToastViewportContext } from \"./toast-context.js\";\nimport type { ToastRootContextValue } from \"./toast-context.js\";\n\nexport interface ToastRootState {\n readonly toast: ToastItem;\n /** `toast.pending`: its promise is unsettled or its Action runs. */\n readonly pending: boolean;\n /** `toast.ending`: closed, kept for its exit animation. */\n readonly ending: boolean;\n readonly type: string | undefined;\n readonly priority: ToastPriority;\n}\n\nexport interface ToastRootProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"role\" | \"className\" | \"style\" | \"children\" | \"onKeyDown\"\n> {\n /** The toast to render: an item of the Viewport's `state.toasts`. */\n toast: ToastItem;\n children?: StateValue<ReactNode, ToastRootState>;\n className?: StateValue<string | undefined, ToastRootState>;\n style?: StateValue<CSSProperties | undefined, ToastRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ToastRootState>;\n /**\n * Rendered by the Root's own Suspense guard while `children` suspend, in place of the\n * invisible default. The toast's timer and announcement wait for the reveal either way.\n * Parts inside it (a visually hidden `<Toast.Title>` giving the toast a name) gate nothing.\n */\n fallback?: ReactNode;\n}\n\n/**\n * The Suspense guard's fallback: renders the Root's `fallback` (nothing by default) and tells\n * the Root its content is suspended, so the timer and the announcement wait for the reveal\n * (design 3.5, 21).\n */\nfunction SuspenseGuard({ children }: { children: ReactNode }) {\n const { setSuspended } = useToastRootContext(\"Toast.Root\");\n useLayoutEffect(() => {\n setSuspended(true);\n return () => setSuspended(false);\n }, [setSuspended]);\n return children;\n}\n\n/**\n * One toast: a focusable `div[role=dialog]` (`alertdialog` for `priority: \"high\"`) named by its\n * Title and described by its Description. Escape dismisses it, ArrowDown / ArrowUp move to the\n * next / previous toast. Its children render inside a Suspense guard whose fallback is the\n * `fallback` prop (invisible by default), so a toast whose content suspends does not pull the whole Viewport into a boundary above it.\n * When the toast closes it stays with `data-ending` (and `inert`) until its exit animations end.\n *\n * Owned keys (conventions 1.2): `role`, `tabIndex`, `aria-labelledby`, `aria-describedby`,\n * `inert`, `data-type`, `data-pending`, `data-ending`, `onKeyDown`.\n */\nexport function ToastRoot({\n toast: item,\n children,\n className,\n style,\n render,\n fallback = null,\n ...rest\n}: ToastRootProps) {\n const viewport = useToastViewportContext(\"Toast.Root\");\n const id = item.id;\n const baseId = useId();\n const ids = useMemo(\n () => ({ title: `${baseId}title`, description: `${baseId}description` }),\n [baseId],\n );\n const elementRef = useRef<HTMLElement | null>(null);\n const titleRef = useRef<HTMLElement | null>(null);\n const descriptionRef = useRef<HTMLElement | null>(null);\n\n // Action pending, aggregated over the Action parts inside (normally one).\n const pendingTokens = useRef(new Set<object>());\n const [actionPending, setActionPendingState] = useState(false);\n // Suspended content behind the guard: a ref for effects of the same commit, state to re-run\n // the announcement once it reveals.\n const suspendedRef = useRef(false);\n const [suspended, setSuspendedState] = useState(false);\n\n const idRef = useLatest(id);\n // The Root's announcement effect has run once: later Title / Description commits are reveals.\n const announcedOnce = useRef(false);\n const revealQueued = useRef(false);\n\n const setActionPending = useCallback(\n (token: object, pending: boolean) => {\n const tokens = pendingTokens.current;\n if (pending) tokens.add(token);\n else tokens.delete(token);\n const any = tokens.size > 0;\n setActionPendingState(any);\n viewport.setActionPending(idRef.current, any);\n },\n [viewport, idRef],\n );\n\n const setSuspended = useCallback(\n (value: boolean) => {\n suspendedRef.current = value;\n setSuspendedState(value);\n viewport.setSuspended(idRef.current, value);\n },\n [viewport, idRef],\n );\n\n const close = useCallback(\n (reason: Parameters<ToastRootContextValue[\"close\"]>[0], event: Event | undefined) =>\n viewport.close([idRef.current], reason, event),\n [viewport, idRef],\n );\n\n const registerTitle = useCallback((element: HTMLElement | null) => {\n titleRef.current = element;\n }, []);\n const registerDescription = useCallback((element: HTMLElement | null) => {\n descriptionRef.current = element;\n }, []);\n\n const pending = item.pending || actionPending;\n const priority = item.priority ?? \"normal\";\n\n // Announce once the content has committed un-suspended (design 5): the Title and Description\n // text exists now. The Viewport skips text it already announced for this toast and speaks the\n // batch a microtask later.\n const announceNow = (): void => {\n if (item.ending || suspendedRef.current) return;\n const resolver = item.announce ?? viewport.announcer();\n let text: string | null;\n if (resolver !== undefined) text = resolver(item);\n else {\n text = [titleRef.current?.textContent, descriptionRef.current?.textContent]\n .map((t) => (t ?? \"\").trim())\n .filter((t) => t !== \"\")\n .join(\" \");\n }\n viewport.announce(item.id, text, priority);\n };\n const announceRef = useLatest(announceNow);\n\n // A Title or Description inside the consumer's own `<Suspense>` commits after the Root (the\n // boundary's retry does not re-run the Root's effect). Read once the whole reveal committed,\n // so a Title and a Description revealed together are announced as one text.\n const contentCommitted = useCallback(() => {\n if (!announcedOnce.current || revealQueued.current) return;\n revealQueued.current = true;\n queueMicrotask(() => {\n revealQueued.current = false;\n announceRef.current();\n });\n }, [announceRef]);\n const state = useMemo<ToastRootState>(\n () => ({ toast: item, pending, ending: item.ending, type: item.type, priority }),\n [item, pending, priority],\n );\n\n const context = useMemo<ToastRootContextValue>(\n () => ({\n toast: item,\n ids,\n state,\n registerTitle,\n registerDescription,\n contentCommitted,\n setActionPending,\n setSuspended,\n close,\n }),\n [\n item,\n ids,\n state,\n registerTitle,\n registerDescription,\n contentCommitted,\n setActionPending,\n setSuspended,\n close,\n ],\n );\n\n const rootRef = useCallback(\n (element: HTMLElement) => {\n elementRef.current = element;\n viewport.registerRoot(id, element);\n return () => {\n if (elementRef.current === element) elementRef.current = null;\n viewport.registerRoot(id, null);\n };\n },\n [viewport, id],\n );\n\n // A layout effect, so toasts announce in queue order (before the Viewport's own effect\n // announces the queued ones).\n useLayoutEffect(() => {\n announcedOnce.current = true;\n announceRef.current();\n }, [item, suspended, priority, announceRef]);\n\n // Exit (design 10.2): keep the ending toast until the animations the ending state started\n // settle, then drop it. Animations that ran before (a progress bar, paused with the region or\n // not) are not waited for: the Viewport recorded them just before marking the toast ending.\n useLayoutEffect(() => {\n if (!item.ending) return;\n const element = elementRef.current;\n const baseline = viewport.exitBaseline(item.id);\n const animations =\n element === null\n ? []\n : exitAnimations(element).filter((animation) => !baseline?.has(animation));\n if (animations.length === 0) {\n viewport.drop(item.id);\n return;\n }\n let cancelled = false;\n void Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {\n if (!cancelled) viewport.drop(item.id);\n });\n return () => {\n cancelled = true;\n };\n }, [item.ending, item.id, viewport]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLElement>): void => {\n if (event.defaultPrevented || item.ending) return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(\"dismiss\", event.nativeEvent);\n } else if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n viewport.focusSibling(id, event.key === \"ArrowDown\" ? 1 : -1);\n }\n };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n role: priority === \"high\" ? \"alertdialog\" : \"dialog\",\n tabIndex: 0,\n \"aria-labelledby\": ids.title,\n \"aria-describedby\": ids.description,\n inert: item.ending || undefined,\n \"data-type\": item.type,\n \"data-pending\": dataAttr(pending),\n \"data-ending\": dataAttr(item.ending),\n onKeyDown,\n };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, ToastRootState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children: (s: ToastRootState) => (\n <Suspense fallback={<SuspenseGuard>{fallback}</SuspenseGuard>}>\n {resolveStateValue(children, s)}\n </Suspense>\n ),\n props: rest,\n libraryProps,\n ref: rootRef,\n });\n\n return <ToastRootContext value={context}>{element}</ToastRootContext>;\n}\n\nToastRoot.displayName = \"ToastRoot\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toast-root.mjs","names":[],"sources":["../../src/toast/toast-root.tsx"],"sourcesContent":["\"use client\";\nimport { Suspense, useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, KeyboardEvent, ReactNode } from \"react\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport type { RenderProp, StateValue } from \"../internal/types.js\";\nimport { exitAnimations } from \"../internal/use-exit-animation.js\";\nimport { useLatest } from \"../internal/use-latest.js\";\nimport { resolveStateValue, useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport type { ToastItem, ToastPriority } from \"./toast.js\";\nimport { ToastRootContext, useToastRootContext, useToastViewportContext } from \"./toast-context.js\";\nimport type { ToastRootContextValue } from \"./toast-context.js\";\n\nexport interface ToastRootState {\n readonly toast: ToastItem;\n /** `toast.pending`: its promise is unsettled or its Action runs. */\n readonly pending: boolean;\n /** `toast.ending`: closed, kept for its exit animation. */\n readonly ending: boolean;\n readonly type: string | undefined;\n readonly priority: ToastPriority;\n}\n\nexport interface ToastRootProps extends Omit<\n ComponentPropsWithRef<\"div\">,\n \"role\" | \"className\" | \"style\" | \"children\" | \"onKeyDown\"\n> {\n /** The toast to render: an item of the Viewport's `state.toasts`. */\n toast: ToastItem;\n children?: StateValue<ReactNode, ToastRootState>;\n className?: StateValue<string | undefined, ToastRootState>;\n style?: StateValue<CSSProperties | undefined, ToastRootState>;\n render?: RenderProp<ComponentPropsWithRef<\"div\">, ToastRootState>;\n /**\n * Rendered by the Root's own Suspense guard while `children` suspend, in place of the\n * invisible default. The toast's timer and announcement wait for the reveal either way.\n * Parts inside it (a visually hidden `<Toast.Title>` giving the toast a name) gate nothing.\n */\n fallback?: ReactNode;\n}\n\n/**\n * The Suspense guard's fallback: renders the Root's `fallback` (nothing by default) and tells\n * the Root its content is suspended, so the timer and the announcement wait for the reveal\n * (design 3.5, 21).\n */\nfunction SuspenseGuard({ children }: { children: ReactNode }) {\n const { setSuspended } = useToastRootContext(\"Toast.Root\");\n useLayoutEffect(() => {\n setSuspended(true);\n return () => setSuspended(false);\n }, [setSuspended]);\n return children;\n}\n\n/**\n * One toast: a focusable `div[role=dialog]` (`alertdialog` for `priority: \"high\"`) named by its\n * Title and described by its Description. Escape dismisses it, ArrowDown / ArrowUp move to the\n * next / previous toast. Its children render inside a Suspense guard whose fallback is the\n * `fallback` prop (invisible by default), so a toast whose content suspends does not pull the whole Viewport into a boundary above it.\n * When the toast closes it stays with `data-ending` (and `inert`) until its exit animations end.\n *\n * Owned keys (conventions 1.2): `role`, `tabIndex`, `aria-labelledby`, `aria-describedby`,\n * `inert`, `data-type`, `data-pending`, `data-ending`, `onKeyDown`.\n */\nexport function ToastRoot({\n toast: item,\n children,\n className,\n style,\n render,\n fallback = null,\n ...rest\n}: ToastRootProps) {\n const viewport = useToastViewportContext(\"Toast.Root\");\n const id = item.id;\n const baseId = useId();\n const ids = useMemo(\n () => ({ title: `${baseId}title`, description: `${baseId}description` }),\n [baseId],\n );\n const elementRef = useRef<HTMLElement | null>(null);\n const titleRef = useRef<HTMLElement | null>(null);\n const descriptionRef = useRef<HTMLElement | null>(null);\n\n // Action pending, aggregated over the Action parts inside (normally one).\n const pendingTokens = useRef(new Set<object>());\n const [actionPending, setActionPendingState] = useState(false);\n // Suspended content behind the guard: a ref for effects of the same commit, state to re-run\n // the announcement once it reveals.\n const suspendedRef = useRef(false);\n const [suspended, setSuspendedState] = useState(false);\n\n const idRef = useLatest(id);\n // The Root's announcement effect has run once: later Title / Description commits are reveals.\n const announcedOnce = useRef(false);\n const revealQueued = useRef(false);\n\n const setActionPending = useCallback(\n (token: object, pending: boolean) => {\n const tokens = pendingTokens.current;\n if (pending) tokens.add(token);\n else tokens.delete(token);\n const any = tokens.size > 0;\n setActionPendingState(any);\n viewport.setActionPending(idRef.current, any);\n },\n [viewport, idRef],\n );\n\n const setSuspended = useCallback(\n (value: boolean) => {\n suspendedRef.current = value;\n setSuspendedState(value);\n viewport.setSuspended(idRef.current, value);\n },\n [viewport, idRef],\n );\n\n const close = useCallback(\n (reason: Parameters<ToastRootContextValue[\"close\"]>[0], event: Event | undefined) =>\n viewport.close([idRef.current], reason, event),\n [viewport, idRef],\n );\n\n const registerTitle = useCallback((element: HTMLElement | null) => {\n titleRef.current = element;\n }, []);\n const registerDescription = useCallback((element: HTMLElement | null) => {\n descriptionRef.current = element;\n }, []);\n\n const pending = item.pending || actionPending;\n const priority = item.priority ?? \"normal\";\n\n // Announce once the content has committed un-suspended (design 5): the Title and Description\n // text exists now. The Viewport skips text it already announced for this toast and speaks the\n // batch a microtask later.\n const announceNow = (): void => {\n if (item.ending || suspendedRef.current) return;\n const resolver = item.announce ?? viewport.announcer();\n let text: string | null;\n if (resolver !== undefined) text = resolver(item);\n else {\n text = [titleRef.current?.textContent, descriptionRef.current?.textContent]\n .map((t) => (t ?? \"\").trim())\n .filter((t) => t !== \"\")\n .join(\" \");\n }\n viewport.announce(item.id, text, priority);\n };\n const announceRef = useLatest(announceNow);\n\n // A Title or Description inside the consumer's own `<Suspense>` commits after the Root (the\n // boundary's retry does not re-run the Root's effect). Read once the whole reveal committed,\n // so a Title and a Description revealed together are announced as one text.\n const contentCommitted = useCallback(() => {\n if (!announcedOnce.current || revealQueued.current) return;\n revealQueued.current = true;\n queueMicrotask(() => {\n revealQueued.current = false;\n announceRef.current();\n });\n }, [announceRef]);\n const state = useMemo<ToastRootState>(\n () => ({ toast: item, pending, ending: item.ending, type: item.type, priority }),\n [item, pending, priority],\n );\n\n const context = useMemo<ToastRootContextValue>(\n () => ({\n toast: item,\n ids,\n state,\n registerTitle,\n registerDescription,\n contentCommitted,\n setActionPending,\n setSuspended,\n close,\n }),\n [\n item,\n ids,\n state,\n registerTitle,\n registerDescription,\n contentCommitted,\n setActionPending,\n setSuspended,\n close,\n ],\n );\n\n const rootRef = useCallback(\n (element: HTMLElement) => {\n elementRef.current = element;\n viewport.registerRoot(id, element);\n return () => {\n if (elementRef.current === element) elementRef.current = null;\n viewport.registerRoot(id, null);\n };\n },\n [viewport, id],\n );\n\n // A layout effect, so toasts announce in queue order (before the Viewport's own effect\n // announces the queued ones).\n useLayoutEffect(() => {\n announcedOnce.current = true;\n announceRef.current();\n }, [item, suspended, priority, announceRef]);\n\n // Exit (design 10.2): keep the ending toast until the animations the ending state started\n // settle, then drop it. Animations that ran before (a progress bar, paused with the region or\n // not) are not waited for: the Viewport recorded them just before marking the toast ending.\n useLayoutEffect(() => {\n if (!item.ending) return;\n const element = elementRef.current;\n const baseline = viewport.exitBaseline(item.id);\n const animations = element === null ? [] : exitAnimations(element, baseline);\n if (animations.length === 0) {\n viewport.drop(item.id);\n return;\n }\n let cancelled = false;\n void Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {\n if (!cancelled) viewport.drop(item.id);\n });\n return () => {\n cancelled = true;\n };\n }, [item.ending, item.id, viewport]);\n\n const onKeyDown = (event: KeyboardEvent<HTMLElement>): void => {\n if (event.defaultPrevented || item.ending) return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n close(\"dismiss\", event.nativeEvent);\n } else if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n viewport.focusSibling(id, event.key === \"ArrowDown\" ? 1 : -1);\n }\n };\n\n const libraryProps: ComponentPropsWithRef<\"div\"> & DataAttributes = {\n role: priority === \"high\" ? \"alertdialog\" : \"dialog\",\n tabIndex: 0,\n \"aria-labelledby\": ids.title,\n \"aria-describedby\": ids.description,\n inert: item.ending || undefined,\n \"data-type\": item.type,\n \"data-pending\": dataAttr(pending),\n \"data-ending\": dataAttr(item.ending),\n onKeyDown,\n };\n\n const element = useRender<ComponentPropsWithRef<\"div\">, ToastRootState>({\n defaultElement: \"div\",\n render,\n state,\n className,\n style,\n children: (s: ToastRootState) => (\n <Suspense fallback={<SuspenseGuard>{fallback}</SuspenseGuard>}>\n {resolveStateValue(children, s)}\n </Suspense>\n ),\n props: rest,\n libraryProps,\n ref: rootRef,\n });\n\n return <ToastRootContext value={context}>{element}</ToastRootContext>;\n}\n\nToastRoot.displayName = \"ToastRoot\";\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-viewport.d.mts","names":[],"sources":["../../src/toast/toast-viewport.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"toast-viewport.d.mts","names":[],"sources":["../../src/toast/toast-viewport.tsx"],"mappings":";;;;iBAyCiB;;WAEN,iBAAiB;;WAEjB;;WAEA;;iBAGM,2BAA2B,KAC1C;;EAYA,UAAU;;EAEV;;EAEA;;;;;;EAMA;;;;;EAKA,YAAY,OAAO;;EAEnB,WAAW,WAAW,WAAW;EACjC,YAAY,+BAA+B;EAC3C,QAAQ,WAAW,2BAA2B;;EAE9C,SAAS,WAAW,kCAAkC;;;;;;;;;;;wBA0JxC,gBACd,SACA,OACA,UACA,QACA,UACA,UACA,WACA,OACA,WACG,QACF,qCAAkB,IAAA;yBAXL"}
|
|
@@ -5,6 +5,7 @@ import { useLatest } from "../internal/use-latest.mjs";
|
|
|
5
5
|
import { useRender } from "../internal/use-render.mjs";
|
|
6
6
|
import { useDevWarning } from "../internal/use-dev-warning.mjs";
|
|
7
7
|
import { DialogContext } from "../dialog/dialog-context.mjs";
|
|
8
|
+
import { animationBaseline } from "../internal/use-exit-animation.mjs";
|
|
8
9
|
import { getServerTopmostModal, getTopmostModal, subscribeModals } from "../internal/modal-registry.mjs";
|
|
9
10
|
import { ToastViewportContext } from "./toast-context.mjs";
|
|
10
11
|
import { toast, toastManagerInternals } from "./toast.mjs";
|
|
@@ -249,9 +250,8 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
249
250
|
const snapshotExitBaselines = (ids) => {
|
|
250
251
|
for (const id of ids) {
|
|
251
252
|
const element = roots.current.get(id);
|
|
252
|
-
if (element === void 0
|
|
253
|
-
|
|
254
|
-
exitBaselines.current.set(id, new Set(element.getAnimations({ subtree: true })));
|
|
253
|
+
if (element === void 0) continue;
|
|
254
|
+
exitBaselines.current.set(id, animationBaseline(element));
|
|
255
255
|
}
|
|
256
256
|
};
|
|
257
257
|
const clearTimer = (id) => {
|
|
@@ -301,9 +301,15 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
301
301
|
for (let i = 0; i < next.length; i++) {
|
|
302
302
|
const entry = next[i];
|
|
303
303
|
if (entry.ending) continue;
|
|
304
|
-
|
|
304
|
+
const id = entry.options.id;
|
|
305
|
+
if (command.id !== void 0 && id !== command.id) continue;
|
|
305
306
|
dismissed.push(entry);
|
|
306
|
-
next[i] = withFlags(entry, { ending: true });
|
|
307
|
+
if (roots.current.has(id)) next[i] = withFlags(entry, { ending: true });
|
|
308
|
+
else {
|
|
309
|
+
next.splice(i--, 1);
|
|
310
|
+
lastAnnounced.current.delete(id);
|
|
311
|
+
exitBaselines.current.delete(id);
|
|
312
|
+
}
|
|
307
313
|
}
|
|
308
314
|
continue;
|
|
309
315
|
}
|
|
@@ -416,10 +422,20 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
416
422
|
announced: announced.has(e.options.id) ? announced.get(e.options.id) : void 0
|
|
417
423
|
}));
|
|
418
424
|
};
|
|
425
|
+
/** Forgets the queue of the previous manager (its own copy is retained by that manager). */
|
|
426
|
+
const reset = () => {
|
|
427
|
+
moveFocusOut(new Set(entriesRef.current.filter((e) => !e.ending).map((e) => e.options.id)));
|
|
428
|
+
for (const timer of timers.current.values()) if (timer.handle !== null) clearTimeout(timer.handle);
|
|
429
|
+
timers.current.clear();
|
|
430
|
+
lastAnnounced.current.clear();
|
|
431
|
+
exitBaselines.current.clear();
|
|
432
|
+
write([]);
|
|
433
|
+
};
|
|
419
434
|
const handlers = useLatest({
|
|
420
435
|
apply,
|
|
421
436
|
restore,
|
|
422
437
|
retain,
|
|
438
|
+
reset,
|
|
423
439
|
close,
|
|
424
440
|
drop,
|
|
425
441
|
setActionPending,
|
|
@@ -450,7 +466,10 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
450
466
|
exitBaseline: (id) => exitBaselines.current.get(id),
|
|
451
467
|
announcer: () => latest.current.announce
|
|
452
468
|
}), [handlers, latest]);
|
|
469
|
+
const subscribedManager = useRef(null);
|
|
453
470
|
useEffect(() => {
|
|
471
|
+
if (subscribedManager.current !== null && subscribedManager.current !== manager) handlers.current.reset();
|
|
472
|
+
subscribedManager.current = manager;
|
|
454
473
|
const unsubscribe = toastManagerInternals(manager).subscribe(listener.current);
|
|
455
474
|
if (unsubscribe === null) {
|
|
456
475
|
setRejected(true);
|
|
@@ -459,7 +478,7 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
459
478
|
}
|
|
460
479
|
setRejected(false);
|
|
461
480
|
return unsubscribe;
|
|
462
|
-
}, [manager]);
|
|
481
|
+
}, [manager, handlers]);
|
|
463
482
|
useEffect(() => {
|
|
464
483
|
if (rejected) return;
|
|
465
484
|
mounted.current = true;
|
|
@@ -515,7 +534,10 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
515
534
|
useLayoutEffect(() => {
|
|
516
535
|
if (host === null || !portalled) return;
|
|
517
536
|
const target = container ?? anchorRef.current;
|
|
518
|
-
if (target
|
|
537
|
+
if (target === null || host.parentNode === target) return;
|
|
538
|
+
const moved = host.parentNode !== null;
|
|
539
|
+
target.append(host);
|
|
540
|
+
if (moved) setPause("hover", false);
|
|
519
541
|
});
|
|
520
542
|
useLayoutEffect(() => {
|
|
521
543
|
const region = regionRef.current;
|
|
@@ -541,6 +563,7 @@ function ToastViewport({ manager = toast, limit = 3, duration = 5e3, hotkey = DE
|
|
|
541
563
|
} else if (open) region.hidePopover();
|
|
542
564
|
} catch {}
|
|
543
565
|
}
|
|
566
|
+
if (current.length === 0 && pauses.current.hover) setPause("hover", false);
|
|
544
567
|
addedSinceEffect.current = false;
|
|
545
568
|
const { visible, queued } = partition(current, latest.current.limit);
|
|
546
569
|
for (const entry of queued) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast-viewport.mjs","names":["defaultManager"],"sources":["../../src/toast/toast-viewport.tsx"],"sourcesContent":["\"use client\";\nimport {\n use,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, FocusEvent, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { DialogContext } from \"../dialog/dialog-context.js\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport {\n getServerTopmostModal,\n getTopmostModal,\n subscribeModals,\n} from \"../internal/modal-registry.js\";\nimport type { ChangeReason, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { useLatest } from \"../internal/use-latest.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { toast as defaultManager, toastManagerInternals } from \"./toast.js\";\nimport type {\n RetainedToast,\n ToastCommand,\n ToastItem,\n ToastListener,\n ToastManager,\n ToastOptions,\n ToastPriority,\n} from \"./toast.js\";\nimport { ToastViewportContext } from \"./toast-context.js\";\nimport type { ToastViewportContextValue } from \"./toast-context.js\";\n\nexport interface ToastViewportState {\n /** Rendered toasts, chronological (oldest first), exiting ones included. */\n readonly toasts: readonly ToastItem[];\n /** Toasts waiting beyond `limit`. */\n readonly queued: number;\n /** A viewport-wide pause holds (pointer over the region, focus inside, hidden document, blurred window). */\n readonly paused: boolean;\n}\n\nexport interface ToastViewportProps extends Omit<\n ComponentPropsWithRef<\"section\">,\n | \"popover\"\n | \"className\"\n | \"style\"\n | \"children\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onBlur\"\n | \"onKeyDown\"\n> {\n /** The queue to render. Default: the module-level `toast`. */\n manager?: ToastManager;\n /** Toasts rendered at once; further ones wait in order (never dropped). Default `3`. */\n limit?: number;\n /** Default `duration` of a toast in milliseconds; `null` for persistent. Default `5000`. */\n duration?: number | null;\n /**\n * Keys that focus the newest toast: `event.code` values and modifier names (`\"altKey\"`,\n * `\"ctrlKey\"`, `\"metaKey\"`, `\"shiftKey\"`), all of which must match, with no other modifier\n * held. Default `[\"F8\"]`; `null` installs no listener.\n */\n hotkey?: readonly string[] | null;\n /**\n * The text `document.ariaNotify()` speaks for a toast (localisation); `null` announces nothing.\n * A toast's own `announce` wins. Default: the text of its Title and Description.\n */\n announce?: (toast: ToastItem) => string | null;\n /** Usually a function of the state mapping `state.toasts` to `Toast.Root`s. */\n children?: StateValue<ReactNode, ToastViewportState>;\n className?: StateValue<string | undefined, ToastViewportState>;\n style?: StateValue<CSSProperties | undefined, ToastViewportState>;\n /** Must render an element that can carry `popover` (a `<section>` by default). */\n render?: RenderProp<ComponentPropsWithRef<\"section\">, ToastViewportState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nconst DEFAULT_HOTKEY: readonly string[] = [\"F8\"];\n\nconst MODIFIER_NAMES: Readonly<Record<string, string>> = {\n altKey: \"Alt\",\n ctrlKey: \"Ctrl\",\n metaKey: \"Meta\",\n shiftKey: \"Shift\",\n};\n\n/** `[\"altKey\", \"KeyT\"]` → `\"Alt+T\"`, `[\"F8\"]` → `\"F8\"`. */\nfunction hotkeyLabel(hotkey: readonly string[]): string {\n return hotkey\n .map((key) => MODIFIER_NAMES[key] ?? key.replace(/^Key(?=[A-Z]$)/, \"\").replace(/^Digit/, \"\"))\n .join(\"+\");\n}\n\n/** The region's built-in accessible name (conventions 11): `\"Notifications (F8)\"`. */\nfunction regionLabel(hotkey: readonly string[] | null): string {\n if (hotkey === null || hotkey.length === 0) return \"Notifications\";\n return `Notifications (${hotkeyLabel(hotkey)})`;\n}\n\n/** The listed keys and modifiers, and no unlisted modifier (Ctrl+F8 is not F8). */\nfunction matchesHotkey(hotkey: readonly string[], event: KeyboardEvent): boolean {\n const flags = event as unknown as Record<string, unknown>;\n for (const modifier of Object.keys(MODIFIER_NAMES)) {\n if ((flags[modifier] === true) !== hotkey.includes(modifier)) return false;\n }\n return hotkey.every((key) => key in MODIFIER_NAMES || event.code === key);\n}\n\n/** No store: `useSyncExternalStore` only tells the hydration render from a client render. */\nconst subscribeNothing = (): (() => void) => () => {};\nconst onClient = (): boolean => true;\nconst onServerOrHydrating = (): boolean => false;\n\n/**\n * The element the region is portalled into for its whole client life. The library moves this\n * element (between its inline anchor and the topmost modal dialog); React never sees the move, so\n * the toasts keep their state (an Undo in flight stays pending). `display: contents`: no box.\n */\nfunction createHost(): HTMLElement | null {\n if (typeof document === \"undefined\") return null;\n const host = document.createElement(\"div\");\n host.style.display = \"contents\";\n return host;\n}\n\n/** One queue entry: the toast's options and the flags its `ToastItem` is built from. */\ninterface Entry {\n readonly options: ToastOptions & { readonly id: string };\n readonly promisePending: boolean;\n readonly actionPending: boolean;\n readonly ending: boolean;\n /** The public item, rebuilt whenever any of the above changes (stable identity otherwise). */\n readonly item: ToastItem;\n}\n\nfunction makeEntry(\n options: ToastOptions & { readonly id: string },\n flags: { promisePending: boolean; actionPending: boolean; ending: boolean },\n): Entry {\n return {\n options,\n ...flags,\n item: {\n ...options,\n id: options.id,\n pending: flags.promisePending || flags.actionPending,\n ending: flags.ending,\n },\n };\n}\n\nfunction withFlags(\n entry: Entry,\n flags: Partial<{ promisePending: boolean; actionPending: boolean; ending: boolean }>,\n): Entry {\n return makeEntry(entry.options, {\n promisePending: flags.promisePending ?? entry.promisePending,\n actionPending: flags.actionPending ?? entry.actionPending,\n ending: flags.ending ?? entry.ending,\n });\n}\n\n/** Rendered entries (the first `limit` open ones plus every ending one) and the queued count. */\nfunction partition(\n entries: readonly Entry[],\n limit: number,\n): { visible: Entry[]; queued: Entry[] } {\n const visible: Entry[] = [];\n const queued: Entry[] = [];\n let open = 0;\n for (const entry of entries) {\n if (entry.ending) visible.push(entry);\n else if (open < limit) {\n visible.push(entry);\n open++;\n } else queued.push(entry);\n }\n return { visible, queued };\n}\n\n/** Plain text of a `ReactNode` that is text (queued toasts have no DOM to read yet). */\nfunction plainText(node: unknown): string {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\" || typeof node === \"bigint\") return String(node);\n if (Array.isArray(node)) return node.map(plainText).join(\"\");\n return \"\";\n}\n\n/** Document order. */\nfunction byDocumentPosition(a: Element, b: Element): number {\n if (a === b) return 0;\n return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;\n}\n\ninterface Timer {\n /** The duration the timer was started with; a different effective duration restarts it. */\n readonly duration: number;\n remaining: number;\n startedAt: number;\n handle: ReturnType<typeof setTimeout> | null;\n}\n\ninterface PauseSources {\n hover: boolean;\n focus: boolean;\n hidden: boolean;\n blurred: boolean;\n}\n\nfunction anyPause(sources: PauseSources): boolean {\n return sources.hover || sources.focus || sources.hidden || sources.blurred;\n}\n\ntype DocumentWithAriaNotify = Document & {\n ariaNotify?: (announcement: string, options?: { priority?: ToastPriority }) => void;\n};\n\n/**\n * The toast region: a `<section popover=\"manual\">` named \"Notifications (F8)\", shown in the top\n * layer while it has toasts. Owns the queue (urgent state fed by `toast()`), the timers and their\n * pausing, the hotkey, focus return, announcements through `document.ariaNotify()`, and the move\n * into the topmost open modal `Dialog` (a region outside it would be inert).\n *\n * Owned keys (conventions 1.2): `popover`, `aria-label` (the consumer's own `aria-label` wins\n * verbatim), `data-paused`, `data-empty`, and the pointer / focus handlers.\n */\nexport function ToastViewport({\n manager = defaultManager,\n limit = 3,\n duration = 5000,\n hotkey = DEFAULT_HOTKEY,\n announce,\n children,\n className,\n style,\n render,\n ...rest\n}: ToastViewportProps) {\n // --- The queue: urgent state, written only from handlers, microtasks and effects -----------\n const [entries, setEntries] = useState<readonly Entry[]>([]);\n // The latest queue, written together with every `setEntries`: the dispatchers read and write\n // it synchronously so a burst of commands composes (and side effects stay out of updaters).\n const entriesRef = useRef<readonly Entry[]>(entries);\n const listener = useRef<ToastListener | null>(null);\n listener.current ??= {\n restore: (toasts: readonly RetainedToast[]) => handlers.current.restore(toasts),\n apply: (commands: readonly ToastCommand[]) => handlers.current.apply(commands),\n retain: () => handlers.current.retain(),\n };\n // A second Viewport on a taken manager renders nothing from its first render on (the effect\n // below confirms or clears it once the subscription is attempted).\n const [rejected, setRejected] = useState(() =>\n toastManagerInternals(manager).isTaken(listener.current!),\n );\n const [, startCloseTransition] = useTransition();\n\n const regionRef = useRef<HTMLElement | null>(null);\n const roots = useRef(new Map<string, HTMLElement>());\n const suspended = useRef(new Set<string>());\n const timers = useRef(new Map<string, Timer>());\n const pauses = useRef<PauseSources>({\n hover: false,\n focus: false,\n hidden: false,\n blurred: false,\n });\n const [paused, setPaused] = useState(false);\n /** Where focus goes back to once the last toast holding it leaves (design 7). */\n const returnTarget = useRef<HTMLElement | null>(null);\n const lastAnnounced = useRef(new Map<string, string | null>());\n /** Per closing toast: the animations already running before `data-ending` applied. */\n const exitBaselines = useRef(new Map<string, ReadonlySet<Animation>>());\n const announceBatch = useRef<{ text: string; priority: ToastPriority }[]>([]);\n const addedSinceEffect = useRef(false);\n const mounted = useRef(false);\n\n const latest = useLatest({ limit, duration, hotkey, announce });\n\n const container = useSyncExternalStore(subscribeModals, getTopmostModal, getServerTopmostModal);\n\n const write = (next: readonly Entry[]): void => {\n entriesRef.current = next;\n setEntries(next);\n };\n\n // --- Timers (design 6) ----------------------------------------------------------------------\n\n const effectiveDuration = (entry: Entry): number | null => {\n const own = entry.options.duration;\n if (own !== undefined) return own;\n return entry.options.action !== undefined ? null : latest.current.duration;\n };\n\n const syncTimers = (): void => {\n const map = timers.current;\n const { visible } = partition(entriesRef.current, latest.current.limit);\n const now = Date.now();\n const live = new Set<string>();\n const halted = !mounted.current || anyPause(pauses.current);\n for (const entry of visible) {\n if (entry.ending) continue;\n const id = entry.options.id;\n const ms = effectiveDuration(entry);\n if (ms === null) continue;\n live.add(id);\n let timer = map.get(id);\n if (timer === undefined || timer.duration !== ms) {\n if (timer?.handle != null) clearTimeout(timer.handle);\n timer = { duration: ms, remaining: ms, startedAt: 0, handle: null };\n map.set(id, timer);\n }\n const run = !halted && !entry.item.pending && !suspended.current.has(id);\n if (run && timer.handle === null) {\n const current = timer;\n current.startedAt = now;\n current.handle = setTimeout(\n () => {\n current.handle = null;\n current.remaining = 0;\n close([id], \"timeout\", undefined);\n },\n Math.max(0, current.remaining),\n );\n } else if (!run && timer.handle !== null) {\n clearTimeout(timer.handle);\n timer.handle = null;\n timer.remaining -= now - timer.startedAt;\n }\n }\n for (const [id, timer] of map) {\n if (live.has(id)) continue;\n if (timer.handle !== null) clearTimeout(timer.handle);\n map.delete(id);\n }\n };\n\n const setPause = (source: keyof PauseSources, value: boolean): void => {\n if (pauses.current[source] === value) return;\n pauses.current[source] = value;\n // Applied synchronously in the event, before any timer callback can run (design 14 item 9).\n syncTimers();\n setPaused(anyPause(pauses.current));\n };\n\n // --- Focus ----------------------------------------------------------------------------------\n\n /** Open toasts' Root elements in document order. */\n const sortedRoots = (exclude?: ReadonlySet<string>): { id: string; element: HTMLElement }[] => {\n const open = new Set(entriesRef.current.filter((e) => !e.ending).map((e) => e.options.id));\n const list: { id: string; element: HTMLElement }[] = [];\n for (const [id, element] of roots.current) {\n if (!open.has(id) || exclude?.has(id) || !element.isConnected) continue;\n list.push({ id, element });\n }\n return list.sort((a, b) => byDocumentPosition(a.element, b.element));\n };\n\n /**\n * Before toasts close: if focus is inside one of them, move it to the next toast, else the\n * previous one, else where it was before the region was entered, else the body (design 7).\n */\n const moveFocusOut = (closing: ReadonlySet<string>): void => {\n const doc = regionRef.current?.ownerDocument ?? document;\n const active = doc.activeElement;\n if (!(active instanceof HTMLElement)) return;\n const all = sortedRoots();\n const index = all.findIndex(({ element }) => element.contains(active));\n if (index === -1 || !closing.has(all[index]!.id)) return;\n const after = all.slice(index + 1).find(({ id }) => !closing.has(id));\n const before = all\n .slice(0, index)\n .reverse()\n .find(({ id }) => !closing.has(id));\n const target = after ?? before;\n if (target !== undefined) {\n target.element.focus();\n return;\n }\n const stored = returnTarget.current;\n if (stored !== null && stored.isConnected && !regionRef.current?.contains(stored)) {\n stored.focus();\n if (doc.activeElement === stored) return;\n }\n active.blur();\n };\n\n // --- Queue writes ---------------------------------------------------------------------------\n\n /**\n * Records the animations running in each closing toast before `data-ending` applies: the exit\n * waits only for the ones the ending state started, not for a running progress bar.\n */\n const snapshotExitBaselines = (ids: Iterable<string>): void => {\n for (const id of ids) {\n const element = roots.current.get(id);\n if (element === undefined || !element.isConnected) continue;\n if (typeof element.getAnimations !== \"function\") continue;\n exitBaselines.current.set(id, new Set(element.getAnimations({ subtree: true })));\n }\n };\n\n const clearTimer = (id: string): void => {\n const timer = timers.current.get(id);\n if (timer?.handle != null) clearTimeout(timer.handle);\n timers.current.delete(id);\n };\n\n const scheduleCloseActions = (\n closed: readonly Entry[],\n reason: ChangeReason,\n event: Event | undefined,\n ): void => {\n for (const entry of closed) {\n const closeAction = entry.options.closeAction;\n if (closeAction === undefined) continue;\n const details = createActionDetails(event, { id: entry.options.id, reason });\n // Not in the closing handler itself: the toast is gone first, then the action runs in the\n // Viewport's own transition (its rejection reaches the boundary above the Viewport).\n queueMicrotask(() => {\n if (!mounted.current) return;\n startCloseTransition(async () => {\n await closeAction(details);\n });\n });\n }\n };\n\n const close = (ids: readonly string[], reason: ChangeReason, event: Event | undefined): void => {\n const wanted = new Set(ids);\n const closing = entriesRef.current.filter((e) => !e.ending && wanted.has(e.options.id));\n if (closing.length === 0) return;\n const closingIds = new Set(closing.map((e) => e.options.id));\n moveFocusOut(closingIds);\n snapshotExitBaselines(closingIds);\n write(\n entriesRef.current.map((e) =>\n closingIds.has(e.options.id) ? withFlags(e, { ending: true }) : e,\n ),\n );\n syncTimers();\n scheduleCloseActions(closing, reason, event);\n };\n\n const drop = (id: string): void => {\n const next = entriesRef.current.filter((e) => !(e.ending && e.options.id === id));\n if (next.length === entriesRef.current.length) return;\n lastAnnounced.current.delete(id);\n exitBaselines.current.delete(id);\n write(next);\n };\n\n const apply = (commands: readonly ToastCommand[]): void => {\n const next = [...entriesRef.current];\n // Dismissals apply in order: each closes the toasts open at that point of the batch, never\n // one added after it in the same tick. Their side effects run after the loop.\n const dismissed: Entry[] = [];\n for (const command of commands) {\n if (command.kind === \"dismiss\") {\n for (let i = 0; i < next.length; i++) {\n const entry = next[i]!;\n if (entry.ending) continue;\n if (command.id !== undefined && entry.options.id !== command.id) continue;\n dismissed.push(entry);\n next[i] = withFlags(entry, { ending: true });\n }\n continue;\n }\n const index = next.findIndex((e) => e.options.id === command.id);\n const existing = index === -1 ? undefined : next[index]!;\n if (command.kind === \"add\") {\n const options = { ...command.options, id: command.id };\n if (existing !== undefined && !existing.ending) {\n // An explicit existing id is an update (\"one toast per key\").\n next[index] = makeEntry(\n { ...existing.options, ...options },\n {\n promisePending: command.pending || existing.promisePending,\n actionPending: existing.actionPending,\n ending: false,\n },\n );\n continue;\n }\n if (existing !== undefined) {\n // An ending toast replaced by a new one with its id (the keyed Root may be reused):\n // a fresh timer, a fresh announcement, no exit.\n next.splice(index, 1);\n clearTimer(command.id);\n lastAnnounced.current.delete(command.id);\n exitBaselines.current.delete(command.id);\n }\n next.push(\n makeEntry(options, {\n promisePending: command.pending,\n actionPending: false,\n ending: false,\n }),\n );\n addedSinceEffect.current = true;\n } else {\n if (existing === undefined) {\n if (isDev && !command.settle) {\n console.error(`toast.update: no toast with id \"${command.id}\"; the update is ignored.`);\n }\n continue;\n }\n if (existing.ending) continue;\n const options = command.settle\n ? { ...command.options, id: command.id }\n : { ...existing.options, ...command.options, id: command.id };\n next[index] = makeEntry(options, {\n promisePending: command.settle ? false : existing.promisePending,\n actionPending: existing.actionPending,\n ending: false,\n });\n }\n }\n if (dismissed.length === 0) {\n write(next);\n return;\n }\n // Toasts that leave the DOM: not one replaced by a later add with its id in this batch.\n const stays = new Set(next.filter((e) => !e.ending).map((e) => e.options.id));\n const leaving = new Set(dismissed.map((e) => e.options.id).filter((id) => !stays.has(id)));\n moveFocusOut(leaving);\n snapshotExitBaselines(leaving);\n write(next);\n syncTimers();\n scheduleCloseActions(dismissed, \"dismiss\", undefined);\n };\n\n const setActionPending = (id: string, pending: boolean): void => {\n const index = entriesRef.current.findIndex((e) => e.options.id === id);\n if (index === -1) return;\n const entry = entriesRef.current[index]!;\n if (entry.actionPending === pending) return;\n const next = [...entriesRef.current];\n next[index] = withFlags(entry, { actionPending: pending });\n write(next);\n };\n\n // --- Announcements (design 5) ---------------------------------------------------------------\n\n const flushAnnouncements = (): void => {\n const batch = announceBatch.current;\n announceBatch.current = [];\n if (batch.length === 0) return;\n const doc = (regionRef.current?.ownerDocument ?? document) as DocumentWithAriaNotify;\n if (typeof doc.ariaNotify !== \"function\") return;\n const priority = batch.some((a) => a.priority === \"high\") ? \"high\" : \"normal\";\n doc.ariaNotify(batch.map((a) => a.text).join(\" \"), { priority });\n };\n\n const queueAnnouncement = (id: string, text: string | null, priority: ToastPriority): void => {\n const map = lastAnnounced.current;\n if (map.has(id) && map.get(id) === text) return;\n map.set(id, text);\n if (text === null || text.trim() === \"\") return;\n if (announceBatch.current.length === 0) queueMicrotask(flushAnnouncements);\n announceBatch.current.push({ text, priority });\n };\n\n // The callbacks below read only refs, so one context value serves the Viewport's whole life.\n const restore = (toasts: readonly RetainedToast[]): void => {\n if (entriesRef.current.length > 0) return;\n // Already announced by the previous Viewport: not again on every remount.\n for (const t of toasts) {\n if (t.announced !== undefined) lastAnnounced.current.set(t.options.id, t.announced);\n }\n write(\n toasts.map((t) =>\n makeEntry(t.options, { promisePending: t.pending, actionPending: false, ending: false }),\n ),\n );\n addedSinceEffect.current = true;\n };\n\n const retain = (): readonly RetainedToast[] => {\n const announced = lastAnnounced.current;\n return entriesRef.current\n .filter((e) => !e.ending)\n .map((e) => ({\n options: e.options,\n pending: e.promisePending,\n announced: announced.has(e.options.id) ? announced.get(e.options.id) : undefined,\n }));\n };\n\n const handlers = useLatest({\n apply,\n restore,\n retain,\n close,\n drop,\n setActionPending,\n queueAnnouncement,\n setPause,\n syncTimers,\n });\n\n const context = useMemo<ToastViewportContextValue>(\n () => ({\n close: (ids, reason, event) => handlers.current.close(ids, reason, event),\n drop: (id) => handlers.current.drop(id),\n setActionPending: (id, pending) => handlers.current.setActionPending(id, pending),\n setSuspended: (id, value) => {\n if (value) suspended.current.add(id);\n else suspended.current.delete(id);\n handlers.current.syncTimers();\n },\n registerRoot: (id, element) => {\n if (element === null) roots.current.delete(id);\n else roots.current.set(id, element);\n },\n focusSibling: (id, direction) => {\n const all = sortedRoots();\n const index = all.findIndex((r) => r.id === id);\n if (index === -1) return;\n all[index + direction]?.element.focus();\n },\n announce: (id, text, priority) => handlers.current.queueAnnouncement(id, text, priority),\n exitBaseline: (id) => exitBaselines.current.get(id),\n announcer: () => latest.current.announce,\n }),\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- refs only (`sortedRoots` reads refs)\n [handlers, latest],\n );\n\n // --- Subscription ---------------------------------------------------------------------------\n\n useEffect(() => {\n const unsubscribe = toastManagerInternals(manager).subscribe(listener.current!);\n if (unsubscribe === null) {\n setRejected(true);\n if (isDev) {\n console.error(\n \"Toast.Viewport: another Toast.Viewport already renders this manager; this one renders \" +\n \"nothing. Use one Viewport per manager, or `createToastManager()` for a second queue.\",\n );\n }\n return;\n }\n setRejected(false);\n return unsubscribe;\n }, [manager]);\n\n // --- Lifecycle, pause sources, hotkey --------------------------------------------------------\n\n useEffect(() => {\n if (rejected) return;\n mounted.current = true;\n const doc = regionRef.current?.ownerDocument ?? document;\n const view = doc.defaultView ?? window;\n pauses.current.hidden = doc.visibilityState === \"hidden\";\n const onVisibility = (): void =>\n handlers.current.setPause(\"hidden\", doc.visibilityState === \"hidden\");\n // The window's own focus and blur; an element's (which do not bubble) never reach here.\n const onWindowBlur = (event: Event): void => {\n if (!(event.target instanceof Node)) handlers.current.setPause(\"blurred\", true);\n };\n const onWindowFocus = (event: Event): void => {\n if (!(event.target instanceof Node)) handlers.current.setPause(\"blurred\", false);\n };\n doc.addEventListener(\"visibilitychange\", onVisibility);\n view.addEventListener(\"blur\", onWindowBlur);\n view.addEventListener(\"focus\", onWindowFocus);\n handlers.current.syncTimers();\n setPaused(anyPause(pauses.current));\n const map = timers.current;\n return () => {\n mounted.current = false;\n doc.removeEventListener(\"visibilitychange\", onVisibility);\n view.removeEventListener(\"blur\", onWindowBlur);\n view.removeEventListener(\"focus\", onWindowFocus);\n // Unmounting stops the timers; the queue itself is retained by the manager.\n for (const timer of map.values()) if (timer.handle !== null) clearTimeout(timer.handle);\n map.clear();\n };\n }, [handlers, rejected]);\n\n const hotkeyKey = hotkey === null ? null : hotkey.join(\"\\u0000\");\n useEffect(() => {\n if (hotkeyKey === null || rejected) return;\n const keys = hotkeyKey.split(\"\\u0000\");\n const doc = regionRef.current?.ownerDocument ?? document;\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.defaultPrevented || !matchesHotkey(keys, event)) return;\n const all = sortedRoots();\n const newest = all.at(-1);\n if (newest === undefined) return;\n event.preventDefault();\n const active = doc.activeElement;\n if (active instanceof HTMLElement && !regionRef.current?.contains(active)) {\n returnTarget.current = active;\n }\n newest.element.focus();\n };\n doc.addEventListener(\"keydown\", onKeyDown);\n return () => doc.removeEventListener(\"keydown\", onKeyDown);\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- `sortedRoots` reads refs only\n }, [hotkeyKey, rejected]);\n\n // --- The portal host (design 4.3) ------------------------------------------------------------\n\n // The hydration render matches the server's inline region; every later render portals into\n // `host`, whose place the library changes without React noticing.\n const portalled = useSyncExternalStore(subscribeNothing, onClient, onServerOrHydrating);\n const [host] = useState(createHost);\n const anchorRef = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n if (host === null) return;\n return () => host.remove();\n }, [host]);\n\n // Before the region effect below: a move hides the popover (removal steps), which that effect\n // shows again in the same commit.\n useLayoutEffect(() => {\n if (host === null || !portalled) return;\n const target = container ?? anchorRef.current;\n if (target !== null && host.parentNode !== target) target.append(host);\n });\n\n // --- After every commit: region, timers, queued announcements, orphan exits ----------------\n\n useLayoutEffect(() => {\n const region = regionRef.current;\n const current = entriesRef.current;\n // Focus that left with a remount (a move into or out of a dialog) fires no `focusout`.\n if (\n pauses.current.focus &&\n (region === null || !region.contains(region.ownerDocument.activeElement))\n ) {\n returnTarget.current = null;\n setPause(\"focus\", false);\n }\n if (region !== null && region.isConnected && region.hasAttribute(\"popover\")) {\n let open = false;\n try {\n open = region.matches(\":popover-open\");\n } catch {\n open = false;\n }\n try {\n if (current.length > 0) {\n if (!open) region.showPopover();\n else if (addedSinceEffect.current) {\n // Re-raise to the top of the top layer, above a menu or popover opened since\n // (design 4.2). No style flush in between, so nothing is re-created.\n region.hidePopover();\n region.showPopover();\n }\n } else if (open) {\n region.hidePopover();\n }\n } catch {\n // A render element without popover support; nothing to show.\n }\n }\n addedSinceEffect.current = false;\n\n const { visible, queued } = partition(current, latest.current.limit);\n // Queued toasts are announced on add (design 5): from their plain-text fields, since they\n // have no DOM yet. Visible ones announce from their Root once their content committed.\n for (const entry of queued) {\n const id = entry.options.id;\n if (lastAnnounced.current.has(id)) continue;\n const resolver = entry.options.announce ?? latest.current.announce;\n const text = resolver\n ? resolver(entry.item)\n : [plainText(entry.options.title), plainText(entry.options.description)]\n .filter((t) => t !== \"\")\n .join(\" \");\n queueAnnouncement(id, text, entry.options.priority ?? \"normal\");\n }\n // An ending toast without a Root (the consumer did not render one) has nothing to animate.\n for (const entry of visible) {\n if (entry.ending && !roots.current.has(entry.options.id)) drop(entry.options.id);\n }\n syncTimers();\n });\n\n // --- Development checks ---------------------------------------------------------------------\n\n // A Viewport inside a library Dialog would close (and unmount) with it.\n const insideDialog = use(DialogContext) !== null;\n useDevWarning(\n insideDialog,\n \"Toast.Viewport: rendered inside a Dialog. The region would close with the dialog; render \" +\n \"the Viewport once near the root of the app (it moves into open modal Dialogs by itself).\",\n );\n\n // --- Render ---------------------------------------------------------------------------------\n\n const { visible, queued } = partition(entries, limit);\n const state: ToastViewportState = {\n toasts: visible.map((e) => e.item),\n queued: queued.length,\n paused,\n };\n\n const regionCallbackRef = useCallback((element: HTMLElement) => {\n regionRef.current = element;\n return () => {\n if (regionRef.current === element) regionRef.current = null;\n };\n }, []);\n\n // Touch lifts the pointer at once (`pointerleave` follows `pointerup`), so a tap never sticks.\n const onPointerEnter = (): void => setPause(\"hover\", true);\n const onPointerLeave = (): void => setPause(\"hover\", false);\n const onFocus = (event: FocusEvent<HTMLElement>): void => {\n const region = event.currentTarget;\n const from = event.relatedTarget;\n if (!(from instanceof Node) || !region.contains(from)) {\n returnTarget.current ??= from instanceof HTMLElement ? from : null;\n }\n setPause(\"focus\", true);\n };\n const onBlur = (event: FocusEvent<HTMLElement>): void => {\n const to = event.relatedTarget;\n if (to instanceof Node && event.currentTarget.contains(to)) return;\n returnTarget.current = null;\n setPause(\"focus\", false);\n };\n\n const libraryProps: ComponentPropsWithRef<\"section\"> & DataAttributes = {\n popover: \"manual\",\n \"aria-label\": rest[\"aria-label\"] ?? regionLabel(hotkey),\n \"data-paused\": dataAttr(paused),\n \"data-empty\": dataAttr(state.toasts.length === 0),\n onPointerEnter,\n onPointerLeave,\n onFocus,\n onBlur,\n };\n\n const region = useRender<ComponentPropsWithRef<\"section\">, ToastViewportState>({\n defaultElement: \"section\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: regionCallbackRef,\n });\n\n if (rejected) return null;\n const content = <ToastViewportContext value={context}>{region}</ToastViewportContext>;\n if (!portalled || host === null) return content;\n return (\n <>\n <div ref={anchorRef} style={ANCHOR_STYLE} />\n {createPortal(content, host)}\n </>\n );\n}\n\nconst ANCHOR_STYLE: CSSProperties = { display: \"contents\" };\n\nToastViewport.displayName = \"ToastViewport\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toast-viewport.mjs","names":["defaultManager"],"sources":["../../src/toast/toast-viewport.tsx"],"sourcesContent":["\"use client\";\nimport {\n use,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport type { ComponentPropsWithRef, CSSProperties, FocusEvent, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { DialogContext } from \"../dialog/dialog-context.js\";\nimport { createActionDetails } from \"../internal/action-details.js\";\nimport { dataAttr } from \"../internal/data-attr.js\";\nimport {\n getServerTopmostModal,\n getTopmostModal,\n subscribeModals,\n} from \"../internal/modal-registry.js\";\nimport type { ChangeReason, RenderProp, StateValue } from \"../internal/types.js\";\nimport { useDevWarning } from \"../internal/use-dev-warning.js\";\nimport { animationBaseline } from \"../internal/use-exit-animation.js\";\nimport { useLatest } from \"../internal/use-latest.js\";\nimport { useRender } from \"../internal/use-render.js\";\nimport type { DataAttributes } from \"../internal/use-render.js\";\nimport { toast as defaultManager, toastManagerInternals } from \"./toast.js\";\nimport type {\n RetainedToast,\n ToastCommand,\n ToastItem,\n ToastListener,\n ToastManager,\n ToastOptions,\n ToastPriority,\n} from \"./toast.js\";\nimport { ToastViewportContext } from \"./toast-context.js\";\nimport type { ToastViewportContextValue } from \"./toast-context.js\";\n\nexport interface ToastViewportState {\n /** Rendered toasts, chronological (oldest first), exiting ones included. */\n readonly toasts: readonly ToastItem[];\n /** Toasts waiting beyond `limit`. */\n readonly queued: number;\n /** A viewport-wide pause holds (pointer over the region, focus inside, hidden document, blurred window). */\n readonly paused: boolean;\n}\n\nexport interface ToastViewportProps extends Omit<\n ComponentPropsWithRef<\"section\">,\n | \"popover\"\n | \"className\"\n | \"style\"\n | \"children\"\n | \"onPointerEnter\"\n | \"onPointerLeave\"\n | \"onFocus\"\n | \"onBlur\"\n | \"onKeyDown\"\n> {\n /** The queue to render. Default: the module-level `toast`. */\n manager?: ToastManager;\n /** Toasts rendered at once; further ones wait in order (never dropped). Default `3`. */\n limit?: number;\n /** Default `duration` of a toast in milliseconds; `null` for persistent. Default `5000`. */\n duration?: number | null;\n /**\n * Keys that focus the newest toast: `event.code` values and modifier names (`\"altKey\"`,\n * `\"ctrlKey\"`, `\"metaKey\"`, `\"shiftKey\"`), all of which must match, with no other modifier\n * held. Default `[\"F8\"]`; `null` installs no listener.\n */\n hotkey?: readonly string[] | null;\n /**\n * The text `document.ariaNotify()` speaks for a toast (localisation); `null` announces nothing.\n * A toast's own `announce` wins. Default: the text of its Title and Description.\n */\n announce?: (toast: ToastItem) => string | null;\n /** Usually a function of the state mapping `state.toasts` to `Toast.Root`s. */\n children?: StateValue<ReactNode, ToastViewportState>;\n className?: StateValue<string | undefined, ToastViewportState>;\n style?: StateValue<CSSProperties | undefined, ToastViewportState>;\n /** Must render an element that can carry `popover` (a `<section>` by default). */\n render?: RenderProp<ComponentPropsWithRef<\"section\">, ToastViewportState>;\n}\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nconst DEFAULT_HOTKEY: readonly string[] = [\"F8\"];\n\nconst MODIFIER_NAMES: Readonly<Record<string, string>> = {\n altKey: \"Alt\",\n ctrlKey: \"Ctrl\",\n metaKey: \"Meta\",\n shiftKey: \"Shift\",\n};\n\n/** `[\"altKey\", \"KeyT\"]` → `\"Alt+T\"`, `[\"F8\"]` → `\"F8\"`. */\nfunction hotkeyLabel(hotkey: readonly string[]): string {\n return hotkey\n .map((key) => MODIFIER_NAMES[key] ?? key.replace(/^Key(?=[A-Z]$)/, \"\").replace(/^Digit/, \"\"))\n .join(\"+\");\n}\n\n/** The region's built-in accessible name (conventions 11): `\"Notifications (F8)\"`. */\nfunction regionLabel(hotkey: readonly string[] | null): string {\n if (hotkey === null || hotkey.length === 0) return \"Notifications\";\n return `Notifications (${hotkeyLabel(hotkey)})`;\n}\n\n/** The listed keys and modifiers, and no unlisted modifier (Ctrl+F8 is not F8). */\nfunction matchesHotkey(hotkey: readonly string[], event: KeyboardEvent): boolean {\n const flags = event as unknown as Record<string, unknown>;\n for (const modifier of Object.keys(MODIFIER_NAMES)) {\n if ((flags[modifier] === true) !== hotkey.includes(modifier)) return false;\n }\n return hotkey.every((key) => key in MODIFIER_NAMES || event.code === key);\n}\n\n/** No store: `useSyncExternalStore` only tells the hydration render from a client render. */\nconst subscribeNothing = (): (() => void) => () => {};\nconst onClient = (): boolean => true;\nconst onServerOrHydrating = (): boolean => false;\n\n/**\n * The element the region is portalled into for its whole client life. The library moves this\n * element (between its inline anchor and the topmost modal dialog); React never sees the move, so\n * the toasts keep their state (an Undo in flight stays pending). `display: contents`: no box.\n */\nfunction createHost(): HTMLElement | null {\n if (typeof document === \"undefined\") return null;\n const host = document.createElement(\"div\");\n host.style.display = \"contents\";\n return host;\n}\n\n/** One queue entry: the toast's options and the flags its `ToastItem` is built from. */\ninterface Entry {\n readonly options: ToastOptions & { readonly id: string };\n readonly promisePending: boolean;\n readonly actionPending: boolean;\n readonly ending: boolean;\n /** The public item, rebuilt whenever any of the above changes (stable identity otherwise). */\n readonly item: ToastItem;\n}\n\nfunction makeEntry(\n options: ToastOptions & { readonly id: string },\n flags: { promisePending: boolean; actionPending: boolean; ending: boolean },\n): Entry {\n return {\n options,\n ...flags,\n item: {\n ...options,\n id: options.id,\n pending: flags.promisePending || flags.actionPending,\n ending: flags.ending,\n },\n };\n}\n\nfunction withFlags(\n entry: Entry,\n flags: Partial<{ promisePending: boolean; actionPending: boolean; ending: boolean }>,\n): Entry {\n return makeEntry(entry.options, {\n promisePending: flags.promisePending ?? entry.promisePending,\n actionPending: flags.actionPending ?? entry.actionPending,\n ending: flags.ending ?? entry.ending,\n });\n}\n\n/** Rendered entries (the first `limit` open ones plus every ending one) and the queued count. */\nfunction partition(\n entries: readonly Entry[],\n limit: number,\n): { visible: Entry[]; queued: Entry[] } {\n const visible: Entry[] = [];\n const queued: Entry[] = [];\n let open = 0;\n for (const entry of entries) {\n if (entry.ending) visible.push(entry);\n else if (open < limit) {\n visible.push(entry);\n open++;\n } else queued.push(entry);\n }\n return { visible, queued };\n}\n\n/** Plain text of a `ReactNode` that is text (queued toasts have no DOM to read yet). */\nfunction plainText(node: unknown): string {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\" || typeof node === \"bigint\") return String(node);\n if (Array.isArray(node)) return node.map(plainText).join(\"\");\n return \"\";\n}\n\n/** Document order. */\nfunction byDocumentPosition(a: Element, b: Element): number {\n if (a === b) return 0;\n return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;\n}\n\ninterface Timer {\n /** The duration the timer was started with; a different effective duration restarts it. */\n readonly duration: number;\n remaining: number;\n startedAt: number;\n handle: ReturnType<typeof setTimeout> | null;\n}\n\ninterface PauseSources {\n hover: boolean;\n focus: boolean;\n hidden: boolean;\n blurred: boolean;\n}\n\nfunction anyPause(sources: PauseSources): boolean {\n return sources.hover || sources.focus || sources.hidden || sources.blurred;\n}\n\ntype DocumentWithAriaNotify = Document & {\n ariaNotify?: (announcement: string, options?: { priority?: ToastPriority }) => void;\n};\n\n/**\n * The toast region: a `<section popover=\"manual\">` named \"Notifications (F8)\", shown in the top\n * layer while it has toasts. Owns the queue (urgent state fed by `toast()`), the timers and their\n * pausing, the hotkey, focus return, announcements through `document.ariaNotify()`, and the move\n * into the topmost open modal `Dialog` (a region outside it would be inert).\n *\n * Owned keys (conventions 1.2): `popover`, `aria-label` (the consumer's own `aria-label` wins\n * verbatim), `data-paused`, `data-empty`, and the pointer / focus handlers.\n */\nexport function ToastViewport({\n manager = defaultManager,\n limit = 3,\n duration = 5000,\n hotkey = DEFAULT_HOTKEY,\n announce,\n children,\n className,\n style,\n render,\n ...rest\n}: ToastViewportProps) {\n // --- The queue: urgent state, written only from handlers, microtasks and effects -----------\n const [entries, setEntries] = useState<readonly Entry[]>([]);\n // The latest queue, written together with every `setEntries`: the dispatchers read and write\n // it synchronously so a burst of commands composes (and side effects stay out of updaters).\n const entriesRef = useRef<readonly Entry[]>(entries);\n const listener = useRef<ToastListener | null>(null);\n listener.current ??= {\n restore: (toasts: readonly RetainedToast[]) => handlers.current.restore(toasts),\n apply: (commands: readonly ToastCommand[]) => handlers.current.apply(commands),\n retain: () => handlers.current.retain(),\n };\n // A second Viewport on a taken manager renders nothing from its first render on (the effect\n // below confirms or clears it once the subscription is attempted).\n const [rejected, setRejected] = useState(() =>\n toastManagerInternals(manager).isTaken(listener.current!),\n );\n const [, startCloseTransition] = useTransition();\n\n const regionRef = useRef<HTMLElement | null>(null);\n const roots = useRef(new Map<string, HTMLElement>());\n const suspended = useRef(new Set<string>());\n const timers = useRef(new Map<string, Timer>());\n const pauses = useRef<PauseSources>({\n hover: false,\n focus: false,\n hidden: false,\n blurred: false,\n });\n const [paused, setPaused] = useState(false);\n /** Where focus goes back to once the last toast holding it leaves (design 7). */\n const returnTarget = useRef<HTMLElement | null>(null);\n const lastAnnounced = useRef(new Map<string, string | null>());\n /** Per closing toast: the animations already running before `data-ending` applied. */\n const exitBaselines = useRef(new Map<string, ReadonlySet<Animation>>());\n const announceBatch = useRef<{ text: string; priority: ToastPriority }[]>([]);\n const addedSinceEffect = useRef(false);\n const mounted = useRef(false);\n\n const latest = useLatest({ limit, duration, hotkey, announce });\n\n const container = useSyncExternalStore(subscribeModals, getTopmostModal, getServerTopmostModal);\n\n const write = (next: readonly Entry[]): void => {\n entriesRef.current = next;\n setEntries(next);\n };\n\n // --- Timers (design 6) ----------------------------------------------------------------------\n\n const effectiveDuration = (entry: Entry): number | null => {\n const own = entry.options.duration;\n if (own !== undefined) return own;\n return entry.options.action !== undefined ? null : latest.current.duration;\n };\n\n const syncTimers = (): void => {\n const map = timers.current;\n const { visible } = partition(entriesRef.current, latest.current.limit);\n const now = Date.now();\n const live = new Set<string>();\n const halted = !mounted.current || anyPause(pauses.current);\n for (const entry of visible) {\n if (entry.ending) continue;\n const id = entry.options.id;\n const ms = effectiveDuration(entry);\n if (ms === null) continue;\n live.add(id);\n let timer = map.get(id);\n if (timer === undefined || timer.duration !== ms) {\n if (timer?.handle != null) clearTimeout(timer.handle);\n timer = { duration: ms, remaining: ms, startedAt: 0, handle: null };\n map.set(id, timer);\n }\n const run = !halted && !entry.item.pending && !suspended.current.has(id);\n if (run && timer.handle === null) {\n const current = timer;\n current.startedAt = now;\n current.handle = setTimeout(\n () => {\n current.handle = null;\n current.remaining = 0;\n close([id], \"timeout\", undefined);\n },\n Math.max(0, current.remaining),\n );\n } else if (!run && timer.handle !== null) {\n clearTimeout(timer.handle);\n timer.handle = null;\n timer.remaining -= now - timer.startedAt;\n }\n }\n for (const [id, timer] of map) {\n if (live.has(id)) continue;\n if (timer.handle !== null) clearTimeout(timer.handle);\n map.delete(id);\n }\n };\n\n const setPause = (source: keyof PauseSources, value: boolean): void => {\n if (pauses.current[source] === value) return;\n pauses.current[source] = value;\n // Applied synchronously in the event, before any timer callback can run (design 14 item 9).\n syncTimers();\n setPaused(anyPause(pauses.current));\n };\n\n // --- Focus ----------------------------------------------------------------------------------\n\n /** Open toasts' Root elements in document order. */\n const sortedRoots = (exclude?: ReadonlySet<string>): { id: string; element: HTMLElement }[] => {\n const open = new Set(entriesRef.current.filter((e) => !e.ending).map((e) => e.options.id));\n const list: { id: string; element: HTMLElement }[] = [];\n for (const [id, element] of roots.current) {\n if (!open.has(id) || exclude?.has(id) || !element.isConnected) continue;\n list.push({ id, element });\n }\n return list.sort((a, b) => byDocumentPosition(a.element, b.element));\n };\n\n /**\n * Before toasts close: if focus is inside one of them, move it to the next toast, else the\n * previous one, else where it was before the region was entered, else the body (design 7).\n */\n const moveFocusOut = (closing: ReadonlySet<string>): void => {\n const doc = regionRef.current?.ownerDocument ?? document;\n const active = doc.activeElement;\n if (!(active instanceof HTMLElement)) return;\n const all = sortedRoots();\n const index = all.findIndex(({ element }) => element.contains(active));\n if (index === -1 || !closing.has(all[index]!.id)) return;\n const after = all.slice(index + 1).find(({ id }) => !closing.has(id));\n const before = all\n .slice(0, index)\n .reverse()\n .find(({ id }) => !closing.has(id));\n const target = after ?? before;\n if (target !== undefined) {\n target.element.focus();\n return;\n }\n const stored = returnTarget.current;\n if (stored !== null && stored.isConnected && !regionRef.current?.contains(stored)) {\n stored.focus();\n if (doc.activeElement === stored) return;\n }\n active.blur();\n };\n\n // --- Queue writes ---------------------------------------------------------------------------\n\n /**\n * Records the animations running in each closing toast before `data-ending` applies: the exit\n * waits only for the ones the ending state started, not for a running progress bar.\n */\n const snapshotExitBaselines = (ids: Iterable<string>): void => {\n for (const id of ids) {\n const element = roots.current.get(id);\n if (element === undefined) continue;\n exitBaselines.current.set(id, animationBaseline(element));\n }\n };\n\n const clearTimer = (id: string): void => {\n const timer = timers.current.get(id);\n if (timer?.handle != null) clearTimeout(timer.handle);\n timers.current.delete(id);\n };\n\n const scheduleCloseActions = (\n closed: readonly Entry[],\n reason: ChangeReason,\n event: Event | undefined,\n ): void => {\n for (const entry of closed) {\n const closeAction = entry.options.closeAction;\n if (closeAction === undefined) continue;\n const details = createActionDetails(event, { id: entry.options.id, reason });\n // Not in the closing handler itself: the toast is gone first, then the action runs in the\n // Viewport's own transition (its rejection reaches the boundary above the Viewport).\n queueMicrotask(() => {\n if (!mounted.current) return;\n startCloseTransition(async () => {\n await closeAction(details);\n });\n });\n }\n };\n\n const close = (ids: readonly string[], reason: ChangeReason, event: Event | undefined): void => {\n const wanted = new Set(ids);\n const closing = entriesRef.current.filter((e) => !e.ending && wanted.has(e.options.id));\n if (closing.length === 0) return;\n const closingIds = new Set(closing.map((e) => e.options.id));\n moveFocusOut(closingIds);\n snapshotExitBaselines(closingIds);\n write(\n entriesRef.current.map((e) =>\n closingIds.has(e.options.id) ? withFlags(e, { ending: true }) : e,\n ),\n );\n syncTimers();\n scheduleCloseActions(closing, reason, event);\n };\n\n const drop = (id: string): void => {\n const next = entriesRef.current.filter((e) => !(e.ending && e.options.id === id));\n if (next.length === entriesRef.current.length) return;\n lastAnnounced.current.delete(id);\n exitBaselines.current.delete(id);\n write(next);\n };\n\n const apply = (commands: readonly ToastCommand[]): void => {\n const next = [...entriesRef.current];\n // Dismissals apply in order: each closes the toasts open at that point of the batch, never\n // one added after it in the same tick. Their side effects run after the loop.\n const dismissed: Entry[] = [];\n for (const command of commands) {\n if (command.kind === \"dismiss\") {\n for (let i = 0; i < next.length; i++) {\n const entry = next[i]!;\n if (entry.ending) continue;\n const id = entry.options.id;\n if (command.id !== undefined && id !== command.id) continue;\n dismissed.push(entry);\n if (roots.current.has(id)) {\n next[i] = withFlags(entry, { ending: true });\n } else {\n // Never rendered (queued beyond `limit`, or added in this tick): nothing to\n // animate, so it leaves at once instead of mounting once as an ending Root.\n next.splice(i--, 1);\n lastAnnounced.current.delete(id);\n exitBaselines.current.delete(id);\n }\n }\n continue;\n }\n const index = next.findIndex((e) => e.options.id === command.id);\n const existing = index === -1 ? undefined : next[index]!;\n if (command.kind === \"add\") {\n const options = { ...command.options, id: command.id };\n if (existing !== undefined && !existing.ending) {\n // An explicit existing id is an update (\"one toast per key\").\n next[index] = makeEntry(\n { ...existing.options, ...options },\n {\n promisePending: command.pending || existing.promisePending,\n actionPending: existing.actionPending,\n ending: false,\n },\n );\n continue;\n }\n if (existing !== undefined) {\n // An ending toast replaced by a new one with its id (the keyed Root may be reused):\n // a fresh timer, a fresh announcement, no exit.\n next.splice(index, 1);\n clearTimer(command.id);\n lastAnnounced.current.delete(command.id);\n exitBaselines.current.delete(command.id);\n }\n next.push(\n makeEntry(options, {\n promisePending: command.pending,\n actionPending: false,\n ending: false,\n }),\n );\n addedSinceEffect.current = true;\n } else {\n if (existing === undefined) {\n if (isDev && !command.settle) {\n console.error(`toast.update: no toast with id \"${command.id}\"; the update is ignored.`);\n }\n continue;\n }\n if (existing.ending) continue;\n const options = command.settle\n ? { ...command.options, id: command.id }\n : { ...existing.options, ...command.options, id: command.id };\n next[index] = makeEntry(options, {\n promisePending: command.settle ? false : existing.promisePending,\n actionPending: existing.actionPending,\n ending: false,\n });\n }\n }\n if (dismissed.length === 0) {\n write(next);\n return;\n }\n // Toasts that leave the DOM: not one replaced by a later add with its id in this batch.\n const stays = new Set(next.filter((e) => !e.ending).map((e) => e.options.id));\n const leaving = new Set(dismissed.map((e) => e.options.id).filter((id) => !stays.has(id)));\n moveFocusOut(leaving);\n snapshotExitBaselines(leaving);\n write(next);\n syncTimers();\n scheduleCloseActions(dismissed, \"dismiss\", undefined);\n };\n\n const setActionPending = (id: string, pending: boolean): void => {\n const index = entriesRef.current.findIndex((e) => e.options.id === id);\n if (index === -1) return;\n const entry = entriesRef.current[index]!;\n if (entry.actionPending === pending) return;\n const next = [...entriesRef.current];\n next[index] = withFlags(entry, { actionPending: pending });\n write(next);\n };\n\n // --- Announcements (design 5) ---------------------------------------------------------------\n\n const flushAnnouncements = (): void => {\n const batch = announceBatch.current;\n announceBatch.current = [];\n if (batch.length === 0) return;\n const doc = (regionRef.current?.ownerDocument ?? document) as DocumentWithAriaNotify;\n if (typeof doc.ariaNotify !== \"function\") return;\n const priority = batch.some((a) => a.priority === \"high\") ? \"high\" : \"normal\";\n doc.ariaNotify(batch.map((a) => a.text).join(\" \"), { priority });\n };\n\n const queueAnnouncement = (id: string, text: string | null, priority: ToastPriority): void => {\n const map = lastAnnounced.current;\n if (map.has(id) && map.get(id) === text) return;\n map.set(id, text);\n if (text === null || text.trim() === \"\") return;\n if (announceBatch.current.length === 0) queueMicrotask(flushAnnouncements);\n announceBatch.current.push({ text, priority });\n };\n\n // The callbacks below read only refs, so one context value serves the Viewport's whole life.\n const restore = (toasts: readonly RetainedToast[]): void => {\n if (entriesRef.current.length > 0) return;\n // Already announced by the previous Viewport: not again on every remount.\n for (const t of toasts) {\n if (t.announced !== undefined) lastAnnounced.current.set(t.options.id, t.announced);\n }\n write(\n toasts.map((t) =>\n makeEntry(t.options, { promisePending: t.pending, actionPending: false, ending: false }),\n ),\n );\n addedSinceEffect.current = true;\n };\n\n const retain = (): readonly RetainedToast[] => {\n const announced = lastAnnounced.current;\n return entriesRef.current\n .filter((e) => !e.ending)\n .map((e) => ({\n options: e.options,\n pending: e.promisePending,\n announced: announced.has(e.options.id) ? announced.get(e.options.id) : undefined,\n }));\n };\n\n /** Forgets the queue of the previous manager (its own copy is retained by that manager). */\n const reset = (): void => {\n moveFocusOut(new Set(entriesRef.current.filter((e) => !e.ending).map((e) => e.options.id)));\n for (const timer of timers.current.values()) {\n if (timer.handle !== null) clearTimeout(timer.handle);\n }\n timers.current.clear();\n lastAnnounced.current.clear();\n exitBaselines.current.clear();\n write([]);\n };\n\n const handlers = useLatest({\n apply,\n restore,\n retain,\n reset,\n close,\n drop,\n setActionPending,\n queueAnnouncement,\n setPause,\n syncTimers,\n });\n\n const context = useMemo<ToastViewportContextValue>(\n () => ({\n close: (ids, reason, event) => handlers.current.close(ids, reason, event),\n drop: (id) => handlers.current.drop(id),\n setActionPending: (id, pending) => handlers.current.setActionPending(id, pending),\n setSuspended: (id, value) => {\n if (value) suspended.current.add(id);\n else suspended.current.delete(id);\n handlers.current.syncTimers();\n },\n registerRoot: (id, element) => {\n if (element === null) roots.current.delete(id);\n else roots.current.set(id, element);\n },\n focusSibling: (id, direction) => {\n const all = sortedRoots();\n const index = all.findIndex((r) => r.id === id);\n if (index === -1) return;\n all[index + direction]?.element.focus();\n },\n announce: (id, text, priority) => handlers.current.queueAnnouncement(id, text, priority),\n exitBaseline: (id) => exitBaselines.current.get(id),\n announcer: () => latest.current.announce,\n }),\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- refs only (`sortedRoots` reads refs)\n [handlers, latest],\n );\n\n // --- Subscription ---------------------------------------------------------------------------\n\n const subscribedManager = useRef<ToastManager | null>(null);\n useEffect(() => {\n // A new `manager`: the previous one kept its toasts on unsubscribe (the previous run's\n // cleanup); start empty so the new one's retained toasts are restored and no command of\n // one queue reaches the other's toasts. The same manager again (StrictMode, Activity) keeps\n // the entries.\n if (subscribedManager.current !== null && subscribedManager.current !== manager) {\n handlers.current.reset();\n }\n subscribedManager.current = manager;\n const unsubscribe = toastManagerInternals(manager).subscribe(listener.current!);\n if (unsubscribe === null) {\n setRejected(true);\n if (isDev) {\n console.error(\n \"Toast.Viewport: another Toast.Viewport already renders this manager; this one renders \" +\n \"nothing. Use one Viewport per manager, or `createToastManager()` for a second queue.\",\n );\n }\n return;\n }\n setRejected(false);\n return unsubscribe;\n }, [manager, handlers]);\n\n // --- Lifecycle, pause sources, hotkey --------------------------------------------------------\n\n useEffect(() => {\n if (rejected) return;\n mounted.current = true;\n const doc = regionRef.current?.ownerDocument ?? document;\n const view = doc.defaultView ?? window;\n pauses.current.hidden = doc.visibilityState === \"hidden\";\n const onVisibility = (): void =>\n handlers.current.setPause(\"hidden\", doc.visibilityState === \"hidden\");\n // The window's own focus and blur; an element's (which do not bubble) never reach here.\n const onWindowBlur = (event: Event): void => {\n if (!(event.target instanceof Node)) handlers.current.setPause(\"blurred\", true);\n };\n const onWindowFocus = (event: Event): void => {\n if (!(event.target instanceof Node)) handlers.current.setPause(\"blurred\", false);\n };\n doc.addEventListener(\"visibilitychange\", onVisibility);\n view.addEventListener(\"blur\", onWindowBlur);\n view.addEventListener(\"focus\", onWindowFocus);\n handlers.current.syncTimers();\n setPaused(anyPause(pauses.current));\n const map = timers.current;\n return () => {\n mounted.current = false;\n doc.removeEventListener(\"visibilitychange\", onVisibility);\n view.removeEventListener(\"blur\", onWindowBlur);\n view.removeEventListener(\"focus\", onWindowFocus);\n // Unmounting stops the timers; the queue itself is retained by the manager.\n for (const timer of map.values()) if (timer.handle !== null) clearTimeout(timer.handle);\n map.clear();\n };\n }, [handlers, rejected]);\n\n const hotkeyKey = hotkey === null ? null : hotkey.join(\"\\u0000\");\n useEffect(() => {\n if (hotkeyKey === null || rejected) return;\n const keys = hotkeyKey.split(\"\\u0000\");\n const doc = regionRef.current?.ownerDocument ?? document;\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.defaultPrevented || !matchesHotkey(keys, event)) return;\n const all = sortedRoots();\n const newest = all.at(-1);\n if (newest === undefined) return;\n event.preventDefault();\n const active = doc.activeElement;\n if (active instanceof HTMLElement && !regionRef.current?.contains(active)) {\n returnTarget.current = active;\n }\n newest.element.focus();\n };\n doc.addEventListener(\"keydown\", onKeyDown);\n return () => doc.removeEventListener(\"keydown\", onKeyDown);\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- `sortedRoots` reads refs only\n }, [hotkeyKey, rejected]);\n\n // --- The portal host (design 4.3) ------------------------------------------------------------\n\n // The hydration render matches the server's inline region; every later render portals into\n // `host`, whose place the library changes without React noticing.\n const portalled = useSyncExternalStore(subscribeNothing, onClient, onServerOrHydrating);\n const [host] = useState(createHost);\n const anchorRef = useRef<HTMLDivElement | null>(null);\n\n useLayoutEffect(() => {\n if (host === null) return;\n return () => host.remove();\n }, [host]);\n\n // Before the region effect below: a move hides the popover (removal steps), which that effect\n // shows again in the same commit.\n useLayoutEffect(() => {\n if (host === null || !portalled) return;\n const target = container ?? anchorRef.current;\n if (target === null || host.parentNode === target) return;\n const moved = host.parentNode !== null;\n target.append(host);\n // A moved region gets no `pointerleave` (review L3): drop the hover pause; a pointer still\n // over it enters it again on its next move.\n if (moved) setPause(\"hover\", false);\n });\n\n // --- After every commit: region, timers, queued announcements, orphan exits ----------------\n\n useLayoutEffect(() => {\n const region = regionRef.current;\n const current = entriesRef.current;\n // Focus that left with a remount (a move into or out of a dialog) fires no `focusout`.\n if (\n pauses.current.focus &&\n (region === null || !region.contains(region.ownerDocument.activeElement))\n ) {\n returnTarget.current = null;\n setPause(\"focus\", false);\n }\n if (region !== null && region.isConnected && region.hasAttribute(\"popover\")) {\n let open = false;\n try {\n open = region.matches(\":popover-open\");\n } catch {\n open = false;\n }\n try {\n if (current.length > 0) {\n if (!open) region.showPopover();\n else if (addedSinceEffect.current) {\n // Re-raise to the top of the top layer, above a menu or popover opened since\n // (design 4.2). No style flush in between, so nothing is re-created.\n region.hidePopover();\n region.showPopover();\n }\n } else if (open) {\n region.hidePopover();\n }\n } catch {\n // A render element without popover support; nothing to show.\n }\n }\n // An emptied region is hidden, often right under the pointer (its last toast's Close), and\n // a hidden element gets no `pointerleave` (review L3): the next toast must not start paused.\n if (current.length === 0 && pauses.current.hover) setPause(\"hover\", false);\n addedSinceEffect.current = false;\n\n const { visible, queued } = partition(current, latest.current.limit);\n // Queued toasts are announced on add (design 5): from their plain-text fields, since they\n // have no DOM yet. Visible ones announce from their Root once their content committed.\n for (const entry of queued) {\n const id = entry.options.id;\n if (lastAnnounced.current.has(id)) continue;\n const resolver = entry.options.announce ?? latest.current.announce;\n const text = resolver\n ? resolver(entry.item)\n : [plainText(entry.options.title), plainText(entry.options.description)]\n .filter((t) => t !== \"\")\n .join(\" \");\n queueAnnouncement(id, text, entry.options.priority ?? \"normal\");\n }\n // An ending toast without a Root (the consumer did not render one) has nothing to animate.\n for (const entry of visible) {\n if (entry.ending && !roots.current.has(entry.options.id)) drop(entry.options.id);\n }\n syncTimers();\n });\n\n // --- Development checks ---------------------------------------------------------------------\n\n // A Viewport inside a library Dialog would close (and unmount) with it.\n const insideDialog = use(DialogContext) !== null;\n useDevWarning(\n insideDialog,\n \"Toast.Viewport: rendered inside a Dialog. The region would close with the dialog; render \" +\n \"the Viewport once near the root of the app (it moves into open modal Dialogs by itself).\",\n );\n\n // --- Render ---------------------------------------------------------------------------------\n\n const { visible, queued } = partition(entries, limit);\n const state: ToastViewportState = {\n toasts: visible.map((e) => e.item),\n queued: queued.length,\n paused,\n };\n\n const regionCallbackRef = useCallback((element: HTMLElement) => {\n regionRef.current = element;\n return () => {\n if (regionRef.current === element) regionRef.current = null;\n };\n }, []);\n\n // Touch lifts the pointer at once (`pointerleave` follows `pointerup`), so a tap never sticks.\n const onPointerEnter = (): void => setPause(\"hover\", true);\n const onPointerLeave = (): void => setPause(\"hover\", false);\n const onFocus = (event: FocusEvent<HTMLElement>): void => {\n const region = event.currentTarget;\n const from = event.relatedTarget;\n if (!(from instanceof Node) || !region.contains(from)) {\n returnTarget.current ??= from instanceof HTMLElement ? from : null;\n }\n setPause(\"focus\", true);\n };\n const onBlur = (event: FocusEvent<HTMLElement>): void => {\n const to = event.relatedTarget;\n if (to instanceof Node && event.currentTarget.contains(to)) return;\n returnTarget.current = null;\n setPause(\"focus\", false);\n };\n\n const libraryProps: ComponentPropsWithRef<\"section\"> & DataAttributes = {\n popover: \"manual\",\n \"aria-label\": rest[\"aria-label\"] ?? regionLabel(hotkey),\n \"data-paused\": dataAttr(paused),\n \"data-empty\": dataAttr(state.toasts.length === 0),\n onPointerEnter,\n onPointerLeave,\n onFocus,\n onBlur,\n };\n\n const region = useRender<ComponentPropsWithRef<\"section\">, ToastViewportState>({\n defaultElement: \"section\",\n render,\n state,\n className,\n style,\n children,\n props: rest,\n libraryProps,\n ref: regionCallbackRef,\n });\n\n if (rejected) return null;\n const content = <ToastViewportContext value={context}>{region}</ToastViewportContext>;\n if (!portalled || host === null) return content;\n return (\n <>\n <div ref={anchorRef} style={ANCHOR_STYLE} />\n {createPortal(content, host)}\n </>\n );\n}\n\nconst ANCHOR_STYLE: CSSProperties = { display: \"contents\" };\n\nToastViewport.displayName = \"ToastViewport\";\n"],"mappings":"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"}
|