@primitiv-ui/web 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -3
- package/dist/cdn/chunks/chunk-PKW6AKXD.js +1 -0
- package/dist/cdn/modal.js +1 -1
- package/dist/cdn/popover.js +1 -0
- package/dist/cdn/tooltip.js +1 -0
- package/dist/custom-elements.json +840 -104
- package/dist/define/index.d.ts +2 -0
- package/dist/define/index.js +2 -0
- package/dist/define/popover.d.ts +1 -0
- package/dist/define/popover.js +11 -0
- package/dist/define/tooltip.d.ts +1 -0
- package/dist/define/tooltip.js +11 -0
- package/dist/frameworks/events.d.ts +8 -0
- package/dist/frameworks/react.d.ts +31 -2
- package/dist/frameworks/svelte.d.ts +26 -1
- package/dist/frameworks/vue.d.ts +26 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/popover/PopoverController.d.ts +55 -0
- package/dist/popover/PopoverController.js +100 -0
- package/dist/popover/elements.d.ts +98 -0
- package/dist/popover/elements.js +230 -0
- package/dist/popover/index.d.ts +2 -0
- package/dist/popover/index.js +2 -0
- package/dist/primitiv-web.js +1 -1
- package/dist/tags.d.ts +14 -0
- package/dist/tooltip/TooltipController.d.ts +66 -0
- package/dist/tooltip/TooltipController.js +115 -0
- package/dist/tooltip/TooltipGroup.d.ts +23 -0
- package/dist/tooltip/TooltipGroup.js +44 -0
- package/dist/tooltip/elements.d.ts +83 -0
- package/dist/tooltip/elements.js +222 -0
- package/dist/tooltip/index.d.ts +3 -0
- package/dist/tooltip/index.js +3 -0
- package/package.json +18 -2
package/dist/define/index.d.ts
CHANGED
package/dist/define/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect entry: importing this module defines the seven Popover elements
|
|
3
|
+
* (`<primitiv-popover>`, `-trigger`, `-anchor`, `-content`, `-title`,
|
|
4
|
+
* `-description`, `-close`) on the global `customElements` registry.
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script type="module">import "@primitiv-ui/web/define/popover";</script>
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
import { definePopover } from "../popover/elements.js";
|
|
11
|
+
definePopover();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect entry: importing this module defines the five Tooltip elements
|
|
3
|
+
* (`<primitiv-tooltip>`, `-provider`, `-trigger`, `-content`, `-arrow`) on the
|
|
4
|
+
* global `customElements` registry.
|
|
5
|
+
*
|
|
6
|
+
* ```html
|
|
7
|
+
* <script type="module">import "@primitiv-ui/web/define/tooltip";</script>
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
import { defineTooltip } from "../tooltip/elements.js";
|
|
11
|
+
defineTooltip();
|
|
@@ -19,3 +19,11 @@ export type PrimitivCollapsibleChangeEvent = CustomEvent<{
|
|
|
19
19
|
export type PrimitivModalChangeEvent = CustomEvent<{
|
|
20
20
|
open: boolean;
|
|
21
21
|
}>;
|
|
22
|
+
/** The `primitiv-popover-change` event: bubbles, cancelable, fired before the change applies, with the open state afterwards. */
|
|
23
|
+
export type PrimitivPopoverChangeEvent = CustomEvent<{
|
|
24
|
+
open: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
/** The `primitiv-tooltip-change` event: bubbles, cancelable, fired before the change applies, with the open state afterwards. */
|
|
27
|
+
export type PrimitivTooltipChangeEvent = CustomEvent<{
|
|
28
|
+
open: boolean;
|
|
29
|
+
}>;
|
|
@@ -21,13 +21,15 @@ import type { DetailedHTMLProps, HTMLAttributes } from "react";
|
|
|
21
21
|
import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
|
|
22
22
|
import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
|
|
23
23
|
import type { PrimitivModalCloseElement, PrimitivModalContentElement, PrimitivModalDescriptionElement, PrimitivModalElement, PrimitivModalTitleElement, PrimitivModalTriggerElement } from "../modal/elements.js";
|
|
24
|
+
import type { PrimitivPopoverAnchorElement, PrimitivPopoverCloseElement, PrimitivPopoverContentElement, PrimitivPopoverDescriptionElement, PrimitivPopoverElement, PrimitivPopoverTitleElement, PrimitivPopoverTriggerElement } from "../popover/elements.js";
|
|
24
25
|
import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
|
|
25
|
-
import type {
|
|
26
|
+
import type { PrimitivTooltipArrowElement, PrimitivTooltipContentElement, PrimitivTooltipElement, PrimitivTooltipProviderElement, PrimitivTooltipTriggerElement } from "../tooltip/elements.js";
|
|
27
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent, PrimitivTooltipChangeEvent } from "./events.js";
|
|
26
28
|
/** React's own props for an element, plus `class`, which React 19 passes to custom elements. */
|
|
27
29
|
type ElementProps<E extends HTMLElement> = DetailedHTMLProps<HTMLAttributes<E>, E> & {
|
|
28
30
|
class?: string;
|
|
29
31
|
};
|
|
30
|
-
export type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent, };
|
|
32
|
+
export type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent, PrimitivTooltipChangeEvent, };
|
|
31
33
|
declare module "react" {
|
|
32
34
|
namespace JSX {
|
|
33
35
|
interface IntrinsicElements {
|
|
@@ -69,6 +71,18 @@ declare module "react" {
|
|
|
69
71
|
"primitiv-modal-title": ElementProps<PrimitivModalTitleElement>;
|
|
70
72
|
"primitiv-modal-description": ElementProps<PrimitivModalDescriptionElement>;
|
|
71
73
|
"primitiv-modal-close": ElementProps<PrimitivModalCloseElement>;
|
|
74
|
+
"primitiv-popover": ElementProps<PrimitivPopoverElement> & {
|
|
75
|
+
open?: boolean;
|
|
76
|
+
"onprimitiv-popover-change"?: (event: PrimitivPopoverChangeEvent) => void;
|
|
77
|
+
};
|
|
78
|
+
"primitiv-popover-trigger": ElementProps<PrimitivPopoverTriggerElement>;
|
|
79
|
+
"primitiv-popover-anchor": ElementProps<PrimitivPopoverAnchorElement>;
|
|
80
|
+
"primitiv-popover-title": ElementProps<PrimitivPopoverTitleElement>;
|
|
81
|
+
"primitiv-popover-description": ElementProps<PrimitivPopoverDescriptionElement>;
|
|
82
|
+
"primitiv-popover-close": ElementProps<PrimitivPopoverCloseElement>;
|
|
83
|
+
"primitiv-popover-content": ElementProps<PrimitivPopoverContentElement> & {
|
|
84
|
+
popover?: "auto" | "manual" | "";
|
|
85
|
+
};
|
|
72
86
|
"primitiv-tabs": ElementProps<PrimitivTabsElement> & {
|
|
73
87
|
value?: string;
|
|
74
88
|
orientation?: "horizontal" | "vertical";
|
|
@@ -86,6 +100,21 @@ declare module "react" {
|
|
|
86
100
|
value: string;
|
|
87
101
|
"onprimitiv-tabs-show"?: (event: CustomEvent) => void;
|
|
88
102
|
};
|
|
103
|
+
"primitiv-tooltip": ElementProps<PrimitivTooltipElement> & {
|
|
104
|
+
open?: boolean;
|
|
105
|
+
"delay-duration"?: number | string;
|
|
106
|
+
"disable-hoverable-content"?: boolean;
|
|
107
|
+
"onprimitiv-tooltip-change"?: (event: PrimitivTooltipChangeEvent) => void;
|
|
108
|
+
};
|
|
109
|
+
"primitiv-tooltip-provider": ElementProps<PrimitivTooltipProviderElement> & {
|
|
110
|
+
"delay-duration"?: number | string;
|
|
111
|
+
"skip-delay-duration"?: number | string;
|
|
112
|
+
};
|
|
113
|
+
"primitiv-tooltip-trigger": ElementProps<PrimitivTooltipTriggerElement>;
|
|
114
|
+
"primitiv-tooltip-content": ElementProps<PrimitivTooltipContentElement> & {
|
|
115
|
+
popover?: "auto" | "manual" | "";
|
|
116
|
+
};
|
|
117
|
+
"primitiv-tooltip-arrow": ElementProps<PrimitivTooltipArrowElement>;
|
|
89
118
|
}
|
|
90
119
|
}
|
|
91
120
|
}
|
|
@@ -20,8 +20,10 @@ import type { HTMLAttributes } from "svelte/elements";
|
|
|
20
20
|
import type { PrimitivAccordionContentElement, PrimitivAccordionElement, PrimitivAccordionItemElement, PrimitivAccordionTriggerElement, PrimitivAccordionTriggerIconElement } from "../accordion/elements.js";
|
|
21
21
|
import type { PrimitivCollapsibleContentElement, PrimitivCollapsibleElement, PrimitivCollapsibleTriggerElement, PrimitivCollapsibleTriggerIconElement } from "../collapsible/elements.js";
|
|
22
22
|
import type { PrimitivModalCloseElement, PrimitivModalContentElement, PrimitivModalDescriptionElement, PrimitivModalElement, PrimitivModalTitleElement, PrimitivModalTriggerElement } from "../modal/elements.js";
|
|
23
|
+
import type { PrimitivPopoverAnchorElement, PrimitivPopoverCloseElement, PrimitivPopoverContentElement, PrimitivPopoverDescriptionElement, PrimitivPopoverElement, PrimitivPopoverTitleElement, PrimitivPopoverTriggerElement } from "../popover/elements.js";
|
|
23
24
|
import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
|
|
24
|
-
import type {
|
|
25
|
+
import type { PrimitivTooltipArrowElement, PrimitivTooltipContentElement, PrimitivTooltipElement, PrimitivTooltipProviderElement, PrimitivTooltipTriggerElement } from "../tooltip/elements.js";
|
|
26
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent, PrimitivTooltipChangeEvent } from "./events.js";
|
|
25
27
|
/** Svelte's own attributes and events for an element. */
|
|
26
28
|
type Attributes<E extends HTMLElement> = HTMLAttributes<E>;
|
|
27
29
|
declare module "svelte/elements" {
|
|
@@ -64,6 +66,16 @@ declare module "svelte/elements" {
|
|
|
64
66
|
"primitiv-modal-title": Attributes<PrimitivModalTitleElement>;
|
|
65
67
|
"primitiv-modal-description": Attributes<PrimitivModalDescriptionElement>;
|
|
66
68
|
"primitiv-modal-close": Attributes<PrimitivModalCloseElement>;
|
|
69
|
+
"primitiv-popover": Attributes<PrimitivPopoverElement> & {
|
|
70
|
+
open?: boolean;
|
|
71
|
+
"onprimitiv-popover-change"?: (event: PrimitivPopoverChangeEvent) => void;
|
|
72
|
+
};
|
|
73
|
+
"primitiv-popover-trigger": Attributes<PrimitivPopoverTriggerElement>;
|
|
74
|
+
"primitiv-popover-anchor": Attributes<PrimitivPopoverAnchorElement>;
|
|
75
|
+
"primitiv-popover-content": Attributes<PrimitivPopoverContentElement>;
|
|
76
|
+
"primitiv-popover-title": Attributes<PrimitivPopoverTitleElement>;
|
|
77
|
+
"primitiv-popover-description": Attributes<PrimitivPopoverDescriptionElement>;
|
|
78
|
+
"primitiv-popover-close": Attributes<PrimitivPopoverCloseElement>;
|
|
67
79
|
"primitiv-tabs": Attributes<PrimitivTabsElement> & {
|
|
68
80
|
value?: string;
|
|
69
81
|
orientation?: "horizontal" | "vertical";
|
|
@@ -81,6 +93,19 @@ declare module "svelte/elements" {
|
|
|
81
93
|
value: string;
|
|
82
94
|
"onprimitiv-tabs-show"?: (event: CustomEvent) => void;
|
|
83
95
|
};
|
|
96
|
+
"primitiv-tooltip": Attributes<PrimitivTooltipElement> & {
|
|
97
|
+
open?: boolean;
|
|
98
|
+
"delay-duration"?: number | string;
|
|
99
|
+
"disable-hoverable-content"?: boolean;
|
|
100
|
+
"onprimitiv-tooltip-change"?: (event: PrimitivTooltipChangeEvent) => void;
|
|
101
|
+
};
|
|
102
|
+
"primitiv-tooltip-provider": Attributes<PrimitivTooltipProviderElement> & {
|
|
103
|
+
"delay-duration"?: number | string;
|
|
104
|
+
"skip-delay-duration"?: number | string;
|
|
105
|
+
};
|
|
106
|
+
"primitiv-tooltip-trigger": Attributes<PrimitivTooltipTriggerElement>;
|
|
107
|
+
"primitiv-tooltip-content": Attributes<PrimitivTooltipContentElement>;
|
|
108
|
+
"primitiv-tooltip-arrow": Attributes<PrimitivTooltipArrowElement>;
|
|
84
109
|
}
|
|
85
110
|
}
|
|
86
111
|
export {};
|
package/dist/frameworks/vue.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* JSR does not allow a published module to do.
|
|
20
20
|
*/
|
|
21
21
|
import type { DefineComponent, EmitsOptions } from "vue";
|
|
22
|
-
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivTabsChangeEvent } from "./events.js";
|
|
22
|
+
import type { PrimitivAccordionChangeEvent, PrimitivCollapsibleChangeEvent, PrimitivModalChangeEvent, PrimitivPopoverChangeEvent, PrimitivTabsChangeEvent, PrimitivTooltipChangeEvent } from "./events.js";
|
|
23
23
|
/** A tag as Vue's template checker sees it: its props, and the events it emits. */
|
|
24
24
|
type Tag<Props, Events extends EmitsOptions = Record<never, never>> = DefineComponent<Props, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Record<never, never>, Events>;
|
|
25
25
|
declare module "vue" {
|
|
@@ -67,6 +67,17 @@ declare module "vue" {
|
|
|
67
67
|
"primitiv-modal-title": Tag<Record<never, never>>;
|
|
68
68
|
"primitiv-modal-description": Tag<Record<never, never>>;
|
|
69
69
|
"primitiv-modal-close": Tag<Record<never, never>>;
|
|
70
|
+
"primitiv-popover": Tag<{
|
|
71
|
+
open?: boolean | "";
|
|
72
|
+
}, {
|
|
73
|
+
"primitiv-popover-change": (event: PrimitivPopoverChangeEvent) => void;
|
|
74
|
+
}>;
|
|
75
|
+
"primitiv-popover-trigger": Tag<Record<never, never>>;
|
|
76
|
+
"primitiv-popover-anchor": Tag<Record<never, never>>;
|
|
77
|
+
"primitiv-popover-content": Tag<Record<never, never>>;
|
|
78
|
+
"primitiv-popover-title": Tag<Record<never, never>>;
|
|
79
|
+
"primitiv-popover-description": Tag<Record<never, never>>;
|
|
80
|
+
"primitiv-popover-close": Tag<Record<never, never>>;
|
|
70
81
|
"primitiv-tabs": Tag<{
|
|
71
82
|
value?: string;
|
|
72
83
|
orientation?: "horizontal" | "vertical";
|
|
@@ -86,6 +97,20 @@ declare module "vue" {
|
|
|
86
97
|
}, {
|
|
87
98
|
"primitiv-tabs-show": (event: CustomEvent) => void;
|
|
88
99
|
}>;
|
|
100
|
+
"primitiv-tooltip": Tag<{
|
|
101
|
+
open?: boolean | "";
|
|
102
|
+
delayDuration?: number | string;
|
|
103
|
+
disableHoverableContent?: boolean | "";
|
|
104
|
+
}, {
|
|
105
|
+
"primitiv-tooltip-change": (event: PrimitivTooltipChangeEvent) => void;
|
|
106
|
+
}>;
|
|
107
|
+
"primitiv-tooltip-provider": Tag<{
|
|
108
|
+
delayDuration?: number | string;
|
|
109
|
+
skipDelayDuration?: number | string;
|
|
110
|
+
}>;
|
|
111
|
+
"primitiv-tooltip-trigger": Tag<Record<never, never>>;
|
|
112
|
+
"primitiv-tooltip-content": Tag<Record<never, never>>;
|
|
113
|
+
"primitiv-tooltip-arrow": Tag<Record<never, never>>;
|
|
89
114
|
}
|
|
90
115
|
}
|
|
91
116
|
export {};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a {@link PopoverController} asks of whoever hosts it. The controller
|
|
3
|
+
* owns behaviour and never owns state (RFC 0033 D28): the custom elements keep
|
|
4
|
+
* the open state in a reflected `open` attribute, the React adapter keeps it in
|
|
5
|
+
* React, and each answers these calls from wherever it keeps it.
|
|
6
|
+
*/
|
|
7
|
+
export type PopoverControllerHost = {
|
|
8
|
+
/** The state the controller cannot see for itself. */
|
|
9
|
+
state(): {
|
|
10
|
+
/** Whether the popover is open. */
|
|
11
|
+
open: boolean;
|
|
12
|
+
};
|
|
13
|
+
/** Apply a change the user asked for: `open` is the state afterwards. */
|
|
14
|
+
change(open: boolean): void;
|
|
15
|
+
/** The trigger: Escape hands focus back to it, and a press on it is not an outside press. */
|
|
16
|
+
trigger(): HTMLElement | null;
|
|
17
|
+
/**
|
|
18
|
+
* The element to hand `showPopover({ source })`, which makes it the panel's
|
|
19
|
+
* implicit anchor for CSS anchor positioning. Optional: without it the panel
|
|
20
|
+
* is shown with no source, and positioning is the consumer's to wire.
|
|
21
|
+
*/
|
|
22
|
+
source?(): HTMLElement | null;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The DOM behaviour of a popover, over a `popover="auto"` panel: the browser
|
|
26
|
+
* owns the top layer and light dismiss, and this adds the rest of the WAI-ARIA
|
|
27
|
+
* non-modal dialog pattern:
|
|
28
|
+
*
|
|
29
|
+
* - **Sync** — {@link PopoverController.sync | `sync()`} shows or hides the
|
|
30
|
+
* panel to match the host's state, moving focus into it as it opens (its
|
|
31
|
+
* first focusable, or the panel itself). A host calls it whenever that state
|
|
32
|
+
* may have changed.
|
|
33
|
+
* - **Dismissal** — the browser light-dismissing the panel is reported, Escape
|
|
34
|
+
* inside it closes it and hands focus back to the trigger, and where the
|
|
35
|
+
* browser has no Popover API a press outside closes it.
|
|
36
|
+
*
|
|
37
|
+
* Opening from the trigger is the host's, as a plain click.
|
|
38
|
+
*/
|
|
39
|
+
export declare class PopoverController {
|
|
40
|
+
#private;
|
|
41
|
+
constructor(content: HTMLElement, host: PopoverControllerHost);
|
|
42
|
+
/**
|
|
43
|
+
* Start listening. Connecting again while connected does nothing, so a host
|
|
44
|
+
* whose lifecycle runs twice never stacks handlers.
|
|
45
|
+
*/
|
|
46
|
+
connect(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Stop listening, and forget the panel was showing: a host disconnects when
|
|
49
|
+
* it leaves the document, which hides a popover with no event, so the next
|
|
50
|
+
* sync shows it again.
|
|
51
|
+
*/
|
|
52
|
+
disconnect(): void;
|
|
53
|
+
/** Show or hide the panel to match the host's state. */
|
|
54
|
+
sync(): void;
|
|
55
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { FOCUSABLE_SELECTOR, popoverKeydown, popoverPressDismisses } from "@primitiv-ui/core";
|
|
2
|
+
/**
|
|
3
|
+
* The DOM behaviour of a popover, over a `popover="auto"` panel: the browser
|
|
4
|
+
* owns the top layer and light dismiss, and this adds the rest of the WAI-ARIA
|
|
5
|
+
* non-modal dialog pattern:
|
|
6
|
+
*
|
|
7
|
+
* - **Sync** — {@link PopoverController.sync | `sync()`} shows or hides the
|
|
8
|
+
* panel to match the host's state, moving focus into it as it opens (its
|
|
9
|
+
* first focusable, or the panel itself). A host calls it whenever that state
|
|
10
|
+
* may have changed.
|
|
11
|
+
* - **Dismissal** — the browser light-dismissing the panel is reported, Escape
|
|
12
|
+
* inside it closes it and hands focus back to the trigger, and where the
|
|
13
|
+
* browser has no Popover API a press outside closes it.
|
|
14
|
+
*
|
|
15
|
+
* Opening from the trigger is the host's, as a plain click.
|
|
16
|
+
*/
|
|
17
|
+
export class PopoverController {
|
|
18
|
+
#content;
|
|
19
|
+
#host;
|
|
20
|
+
#connection = null;
|
|
21
|
+
/** Whether this controller showed the panel and has not hidden it since. */
|
|
22
|
+
#shown = false;
|
|
23
|
+
constructor(content, host) {
|
|
24
|
+
this.#content = content;
|
|
25
|
+
this.#host = host;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Start listening. Connecting again while connected does nothing, so a host
|
|
29
|
+
* whose lifecycle runs twice never stacks handlers.
|
|
30
|
+
*/
|
|
31
|
+
connect() {
|
|
32
|
+
if (this.#connection)
|
|
33
|
+
return;
|
|
34
|
+
this.#connection = new AbortController();
|
|
35
|
+
const { signal } = this.#connection;
|
|
36
|
+
this.#content.addEventListener("toggle", (event) => this.#toggle(event), { signal });
|
|
37
|
+
this.#content.addEventListener("keydown", (event) => this.#keydown(event), { signal });
|
|
38
|
+
document.addEventListener("click", (event) => this.#press(event), { signal });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Stop listening, and forget the panel was showing: a host disconnects when
|
|
42
|
+
* it leaves the document, which hides a popover with no event, so the next
|
|
43
|
+
* sync shows it again.
|
|
44
|
+
*/
|
|
45
|
+
disconnect() {
|
|
46
|
+
this.#connection?.abort();
|
|
47
|
+
this.#connection = null;
|
|
48
|
+
this.#shown = false;
|
|
49
|
+
}
|
|
50
|
+
/** Show or hide the panel to match the host's state. */
|
|
51
|
+
sync() {
|
|
52
|
+
const { open } = this.#host.state();
|
|
53
|
+
if (open && !this.#shown) {
|
|
54
|
+
this.#shown = true;
|
|
55
|
+
const source = this.#host.source?.();
|
|
56
|
+
if (source)
|
|
57
|
+
this.#content.showPopover({ source });
|
|
58
|
+
else
|
|
59
|
+
this.#content.showPopover();
|
|
60
|
+
// Move focus into the panel (WAI-ARIA non-modal dialog): the first
|
|
61
|
+
// focusable, or the panel itself, which carries tabindex="-1".
|
|
62
|
+
(this.#content.querySelector(FOCUSABLE_SELECTOR) ?? this.#content).focus();
|
|
63
|
+
}
|
|
64
|
+
else if (!open && this.#shown) {
|
|
65
|
+
this.#shown = false;
|
|
66
|
+
try {
|
|
67
|
+
this.#content.hidePopover();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Already hidden: the browser light-dismissed it first.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
#toggle(event) {
|
|
75
|
+
if (event.newState !== "closed")
|
|
76
|
+
return;
|
|
77
|
+
this.#shown = false;
|
|
78
|
+
this.#host.change(false);
|
|
79
|
+
}
|
|
80
|
+
#keydown(event) {
|
|
81
|
+
// A popover nested in this panel handles its own Escape first, as the
|
|
82
|
+
// event bubbles out of it; leave that one alone, or both would close.
|
|
83
|
+
if (event.defaultPrevented || !popoverKeydown(event.key))
|
|
84
|
+
return;
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
this.#host.change(false);
|
|
87
|
+
this.#host.trigger()?.focus();
|
|
88
|
+
}
|
|
89
|
+
#press(event) {
|
|
90
|
+
const target = event.target;
|
|
91
|
+
const dismisses = popoverPressDismisses({
|
|
92
|
+
open: this.#host.state().open,
|
|
93
|
+
nativeLightDismiss: "popover" in HTMLElement.prototype,
|
|
94
|
+
inTrigger: this.#host.trigger()?.contains(target) ?? false,
|
|
95
|
+
inPopover: target.closest("[popover]") !== null,
|
|
96
|
+
});
|
|
97
|
+
if (dismisses)
|
|
98
|
+
this.#host.change(false);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ElementBase, type ElementRegistry } from "../internal/element.js";
|
|
2
|
+
import { PrimitivRootElement } from "../internal/RootElement.js";
|
|
3
|
+
export type { ElementRegistry };
|
|
4
|
+
/**
|
|
5
|
+
* `<primitiv-popover>` — the state owner of a non-modal popover: a trigger
|
|
6
|
+
* that opens a floating panel, built on the native Popover API. The browser
|
|
7
|
+
* puts the panel in the top layer and light-dismisses it; the element adds the
|
|
8
|
+
* rest of the WAI-ARIA non-modal dialog pattern — focus moves into the panel
|
|
9
|
+
* as it opens, Escape closes it and hands focus back to the trigger, and the
|
|
10
|
+
* trigger's `aria-expanded` follows it.
|
|
11
|
+
*
|
|
12
|
+
* The panel is shown with its trigger (or the anchor) as its source, which
|
|
13
|
+
* makes that element the panel's implicit anchor, so CSS anchor positioning
|
|
14
|
+
* (`position-area`) places it with no `anchor-name` to wire.
|
|
15
|
+
*
|
|
16
|
+
* The root finds its own parts, so a popover nested in a panel keeps its own,
|
|
17
|
+
* and reconciles their ARIA from its reflected state whenever a part arrives,
|
|
18
|
+
* leaves, or changes an attribute the root reads (the lifecycle is
|
|
19
|
+
* `PrimitivRootElement`'s).
|
|
20
|
+
*
|
|
21
|
+
* @customElement primitiv-popover
|
|
22
|
+
* @summary The state owner of a non-modal popover on the native Popover API.
|
|
23
|
+
* @attr {boolean} open - Whether the panel is open. Reflected: it changes as the user opens and dismisses it, so a server re-render or a history snapshot sees the live state. Set it (or the `open` property) to open or close the panel from script.
|
|
24
|
+
* @fires {CustomEvent<{ open: boolean }>} primitiv-popover-change - Bubbles, cancelable, fired before a user-driven change is applied — a trigger or close click, Escape, or a light dismiss — with the open state afterwards. Call `preventDefault()` to veto it.
|
|
25
|
+
*/
|
|
26
|
+
export declare class PrimitivPopoverElement extends PrimitivRootElement {
|
|
27
|
+
#private;
|
|
28
|
+
protected readonly controller: {
|
|
29
|
+
connect(): void;
|
|
30
|
+
disconnect(): void;
|
|
31
|
+
};
|
|
32
|
+
protected readonly reconcileOn: readonly string[];
|
|
33
|
+
/** Whether the panel is open, reflected as the boolean `open` attribute. */
|
|
34
|
+
get open(): boolean;
|
|
35
|
+
set open(next: boolean);
|
|
36
|
+
protected reconcile(): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `<primitiv-popover-trigger>` — an interactive part. It decorates exactly one
|
|
40
|
+
* child the consumer writes, a `<button>`, which toggles the panel and receives
|
|
41
|
+
* `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`, so the
|
|
42
|
+
* rendered DOM matches React's (RFC 0033 D24).
|
|
43
|
+
*
|
|
44
|
+
* @customElement primitiv-popover-trigger
|
|
45
|
+
*/
|
|
46
|
+
export declare class PrimitivPopoverTriggerElement extends ElementBase {
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `<primitiv-popover-anchor>` — optional. It decorates exactly one element the
|
|
50
|
+
* consumer writes, which the panel is anchored to in place of the trigger: a
|
|
51
|
+
* field, say, whose trigger is an icon inside it.
|
|
52
|
+
*
|
|
53
|
+
* @customElement primitiv-popover-anchor
|
|
54
|
+
*/
|
|
55
|
+
export declare class PrimitivPopoverAnchorElement extends ElementBase {
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `<primitiv-popover-content>` — the panel. Structural: the root gives it an
|
|
59
|
+
* id, `role="dialog"`, `popover="auto"` (write it in your markup too, so the
|
|
60
|
+
* panel is hidden before the script loads), `tabindex="-1"`, `data-state`, and
|
|
61
|
+
* `aria-labelledby` / `aria-describedby` pointing at the title and description.
|
|
62
|
+
*
|
|
63
|
+
* @customElement primitiv-popover-content
|
|
64
|
+
*/
|
|
65
|
+
export declare class PrimitivPopoverContentElement extends ElementBase {
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* `<primitiv-popover-title>` — decorates exactly one heading the consumer
|
|
69
|
+
* writes, whose id becomes the panel's `aria-labelledby`.
|
|
70
|
+
*
|
|
71
|
+
* @customElement primitiv-popover-title
|
|
72
|
+
*/
|
|
73
|
+
export declare class PrimitivPopoverTitleElement extends ElementBase {
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* `<primitiv-popover-description>` — decorates exactly one element the
|
|
77
|
+
* consumer writes (a `<p>`, usually), whose id becomes the panel's
|
|
78
|
+
* `aria-describedby`.
|
|
79
|
+
*
|
|
80
|
+
* @customElement primitiv-popover-description
|
|
81
|
+
*/
|
|
82
|
+
export declare class PrimitivPopoverDescriptionElement extends ElementBase {
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* `<primitiv-popover-close>` — an interactive part. It decorates exactly one
|
|
86
|
+
* `<button>` the consumer writes, which closes the panel. A popover may have
|
|
87
|
+
* several.
|
|
88
|
+
*
|
|
89
|
+
* @customElement primitiv-popover-close
|
|
90
|
+
*/
|
|
91
|
+
export declare class PrimitivPopoverCloseElement extends ElementBase {
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Define the seven Popover elements on `registry` (the global `customElements`
|
|
95
|
+
* by default). Safe to call more than once, and a no-op where there is no
|
|
96
|
+
* registry (a server render).
|
|
97
|
+
*/
|
|
98
|
+
export declare function definePopover(registry?: ElementRegistry | undefined): void;
|