@brightspot/ui 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/components/avatar/Avatar.d.ts +1 -1
- package/dist/components/avatar/Avatar.d.ts.map +1 -1
- package/dist/components/avatar/Avatar.js +3 -1
- package/dist/components/avatar/Avatar.js.map +1 -1
- package/dist/components/popover/Popover.d.ts +161 -0
- package/dist/components/popover/Popover.d.ts.map +1 -0
- package/dist/components/popover/Popover.js +436 -0
- package/dist/components/popover/Popover.js.map +1 -0
- package/dist/components/widget/Widget.css +104 -0
- package/dist/components/widget/Widget.d.ts +170 -0
- package/dist/components/widget/Widget.d.ts.map +1 -0
- package/dist/components/widget/Widget.js +434 -0
- package/dist/components/widget/Widget.js.map +1 -0
- package/dist/custom-elements.json +604 -101
- package/dist/global.d.ts +5 -0
- package/dist/storybook/assets/{Avatar.stories-DrhezTR1.js → Avatar.stories-CPVNxsaA.js} +37 -32
- package/dist/storybook/assets/AvatarGroup.stories-Bl65NGHl.js +225 -0
- package/dist/storybook/assets/{Badge.stories-DtJcBfOR.js → Badge.stories-Bbnc6fRy.js} +1 -1
- package/dist/storybook/assets/{Button.stories-BKUfLgSY.js → Button.stories-CRJ5n2y4.js} +1 -1
- package/dist/storybook/assets/{CircularProgress.stories-dpmD-XJT.js → CircularProgress.stories-D9vBj3JJ.js} +1 -1
- package/dist/storybook/assets/{ClipboardMixin.stories-C0pnQ7BY.js → ClipboardMixin.stories-Dm-Jm4yb.js} +7 -7
- package/dist/storybook/assets/Color-6BZIO3FS-BcNIJY1U.js +1 -0
- package/dist/storybook/assets/{Colors.stories-bKK25qgF.js → Colors.stories-B9_090wL.js} +1 -1
- package/dist/storybook/assets/ComponentStatesMixin-ChiFBCuo.js +1 -0
- package/dist/storybook/assets/{ComponentStatesMixin.stories-9mRp2zuB.js → ComponentStatesMixin.stories-DHv9MHmE.js} +3 -3
- package/dist/storybook/assets/{CopyToClipboard.stories-BW3oaT1i.js → CopyToClipboard.stories-gtJlTP1l.js} +1 -1
- package/dist/storybook/assets/{Debounce.stories-BXx3CKvQ.js → Debounce.stories-BBNX7mJA.js} +3 -3
- package/dist/storybook/assets/DocsRenderer-LL677BLK-D-E99pXl.js +758 -0
- package/dist/storybook/assets/{Events.stories-PBeiuWQn.js → Events.stories-DDmydlh_.js} +1 -1
- package/dist/storybook/assets/{Heading.stories-Djkl0MoC.js → Heading.stories-BLGfko-i.js} +1 -1
- package/dist/storybook/assets/{Icon.stories-Cam1fyud.js → Icon.stories-BHnAGcFF.js} +1 -1
- package/dist/storybook/assets/{LinearProgress.stories-BDNoYIJu.js → LinearProgress.stories-Dx26a0P_.js} +1 -1
- package/dist/storybook/assets/Popover.stories-CbqpY6YR.js +431 -0
- package/dist/storybook/assets/ReadyMixin-BHiHoIbr.js +1 -0
- package/dist/storybook/assets/{Rtc.stories-BrTAIAi1.js → Rtc.stories-CAjDv_Ub.js} +3 -3
- package/dist/storybook/assets/{ScrollShadow.stories-DHcKhkag.js → ScrollShadow.stories-BSV4U-tq.js} +1 -1
- package/dist/storybook/assets/{Throttle.stories-cSYT_BXu.js → Throttle.stories-kaxXQ8RZ.js} +8 -8
- package/dist/storybook/assets/Tooltip.stories-CsxXkztr.js +143 -0
- package/dist/storybook/assets/Widget.stories-DqATHnSq.js +233 -0
- package/dist/storybook/assets/WithTooltip-65CFNBJE-BtbbFYSA.js +9 -0
- package/dist/storybook/assets/custom-element-UsVr97OX.js +1 -0
- package/dist/storybook/assets/formatter-EIJCOSYU-C87Csnpu.js +1 -0
- package/dist/storybook/assets/if-defined-COHr0XBn.js +1 -0
- package/dist/storybook/assets/{iframe-BMxUFmpF.css → iframe-BkDGeDre.css} +1 -1
- package/dist/storybook/assets/iframe-CcloOV09.js +1061 -0
- package/dist/storybook/assets/index-DP7vnJf7.js +1 -0
- package/dist/storybook/assets/onFind-DqriYjEB.js +1 -0
- package/dist/storybook/assets/onFind.stories-BxvoC-Z-.js +1069 -0
- package/dist/storybook/assets/{onRemove.stories-C7W9KyRr.js → onRemove.stories-Dwoixzb0.js} +3 -3
- package/dist/storybook/assets/{onVisible.stories-CIl6R0q4.js → onVisible.stories-CinmRF9w.js} +10 -10
- package/dist/storybook/assets/syntaxhighlighter-ED5Y7EFY-BHLkDkOn.js +6 -0
- package/dist/storybook/iframe.html +57 -39
- package/dist/storybook/index.html +11 -4
- package/dist/storybook/index.json +1 -1
- package/dist/storybook/project.json +1 -1
- package/dist/storybook/sb-addons/docs-1/manager-bundle.js +1 -1
- package/dist/storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +112 -290
- package/dist/storybook/sb-addons/vitest-2/manager-bundle.js +3 -0
- package/dist/storybook/sb-manager/globals-runtime.js +60754 -66346
- package/dist/storybook/sb-manager/globals.js +2 -3
- package/dist/storybook/sb-manager/manager-stores.js +23 -0
- package/dist/storybook/sb-manager/runtime.js +12983 -11699
- package/dist/storybook/vite-inject-mocker-entry.js +2 -2
- package/dist/tailwind-plugin-popover.d.ts +2 -0
- package/dist/tailwind-plugin-popover.d.ts.map +1 -0
- package/dist/tailwind-plugin-popover.js +177 -0
- package/dist/tailwind-plugin-popover.js.map +1 -0
- package/dist/tailwind-plugin-popover.ts +202 -0
- package/dist/tailwind-plugin-tooltip.d.ts +2 -0
- package/dist/tailwind-plugin-tooltip.d.ts.map +1 -0
- package/dist/tailwind-plugin-tooltip.js +184 -0
- package/dist/tailwind-plugin-tooltip.js.map +1 -0
- package/dist/tailwind-plugin-tooltip.ts +209 -0
- package/dist/util/EventEmitterMixin.d.ts +11 -0
- package/dist/util/EventEmitterMixin.d.ts.map +1 -1
- package/dist/util/EventEmitterMixin.js +1 -1
- package/dist/util/EventEmitterMixin.js.map +1 -1
- package/dist/util/TooltipController.d.ts +37 -0
- package/dist/util/TooltipController.d.ts.map +1 -0
- package/dist/util/TooltipController.js +133 -0
- package/dist/util/TooltipController.js.map +1 -0
- package/dist/util/TooltipMixin.d.ts +42 -0
- package/dist/util/TooltipMixin.d.ts.map +1 -0
- package/dist/util/TooltipMixin.js +401 -0
- package/dist/util/TooltipMixin.js.map +1 -0
- package/dist/util/onFind.d.ts +1 -0
- package/dist/util/onFind.d.ts.map +1 -1
- package/dist/util/onFind.js +73 -48
- package/dist/util/onFind.js.map +1 -1
- package/dist/util/onVisible.d.ts.map +1 -1
- package/dist/util/onVisible.js +13 -2
- package/dist/util/onVisible.js.map +1 -1
- package/package.json +12 -5
- package/dist/storybook/assets/AvatarGroup.stories-DrlxT-mF.js +0 -211
- package/dist/storybook/assets/Color-64QXVMR3-Dnd9S2a1.js +0 -1
- package/dist/storybook/assets/ComponentStatesMixin-C2HZ9ZFb.js +0 -1
- package/dist/storybook/assets/WithTooltip-SK46ZJ2J-Df0E-KJO.js +0 -825
- package/dist/storybook/assets/formatter-OMEEQ6HG-DFa_WTfb.js +0 -1
- package/dist/storybook/assets/iframe-lTczLWsL.js +0 -1064
- package/dist/storybook/assets/index-yMswRDPh.js +0 -1
- package/dist/storybook/assets/onFind-C6olvKHR.js +0 -1
- package/dist/storybook/assets/onFind.stories-DfW54CDE.js +0 -284
- package/dist/storybook/assets/syntaxhighlighter-CAVLW7PM-DoI0ixeu.js +0 -6
package/README.md
CHANGED
|
@@ -99,6 +99,18 @@ An example of including a plugin:
|
|
|
99
99
|
...
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
+
## Web Components
|
|
103
|
+
|
|
104
|
+
Brightspot UI includes custom web components built with LitElement. FOUC (Flash of Unstyled Content) prevention is handled automatically when you import the components.
|
|
105
|
+
|
|
106
|
+
Import components in your JavaScript/TypeScript:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import '@brightspot/ui/dist/components/widget/Widget'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
See the Storybook documentation for detailed usage examples and API references.
|
|
113
|
+
|
|
102
114
|
## Examples
|
|
103
115
|
|
|
104
116
|
We use [Storybook](https://storybook.js.org/) for interactive previewing of our ui components. Launch that in the browser by running:
|
|
@@ -5,7 +5,7 @@ export interface AvatarProps {
|
|
|
5
5
|
fallback?: string;
|
|
6
6
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
|
|
7
7
|
}
|
|
8
|
-
declare const Avatar_base: (new (...args: any[]) => import("../../util/EventEmitterMixin.js").EventEmitterMixinInterface) & (new (...args: any[]) => import("../../util/ReadyMixin.js").ReadyMixinInterface) & typeof LitElement;
|
|
8
|
+
declare const Avatar_base: (new (...args: any[]) => import("../../util/TooltipMixin.js").TooltipMixinInterface) & (new (...args: any[]) => import("../../util/EventEmitterMixin.js").EventEmitterMixinInterface) & (new (...args: any[]) => import("../../util/ReadyMixin.js").ReadyMixinInterface) & typeof LitElement;
|
|
9
9
|
/**
|
|
10
10
|
* An avatar component for displaying user profile images with fallback support.
|
|
11
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../src/components/avatar/Avatar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../src/components/avatar/Avatar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAA;AAMtC,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAA;CAChD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,WAAuD;IACzF;;;OAGG;IAEH,GAAG,SAAK;IAER;;;OAGG;IAEH,GAAG,SAAK;IAER;;;OAGG;IAEH,QAAQ,SAAK;IAEb;;;;;;;;;OASG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAO;IAErD,gBAAgB;IAChB,OAAO,CAAC,cAAc,CAAe;IAErC,gBAAgB;IAEhB,OAAO,CAAC,WAAW,CAAQ;IAE3B,gBAAgB;IAEhB,OAAO,CAAC,UAAU,CAAQ;IAE1B,iBAAiB,IAAI,IAAI;IAQzB,gBAAgB;IAIhB,UAAU,IAAI,IAAI;IAWlB,YAAY,IAAI,IAAI;IAqBpB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IA2BlD,MAAM;CAMP;AAMD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,MAAM,CAAA;KACrB;CACF"}
|
|
@@ -8,6 +8,7 @@ import { LitElement, html } from 'lit';
|
|
|
8
8
|
import { property, state } from 'lit/decorators.js';
|
|
9
9
|
import { EventEmitterMixin } from '../../util/EventEmitterMixin.js';
|
|
10
10
|
import { ReadyMixin } from '../../util/ReadyMixin.js';
|
|
11
|
+
import { TooltipMixin } from '../../util/TooltipMixin.js';
|
|
11
12
|
/**
|
|
12
13
|
* An avatar component for displaying user profile images with fallback support.
|
|
13
14
|
*
|
|
@@ -35,7 +36,7 @@ import { ReadyMixin } from '../../util/ReadyMixin.js';
|
|
|
35
36
|
* <btu-avatar fallback="JD" size="lg"></btu-avatar>
|
|
36
37
|
* ```
|
|
37
38
|
*/
|
|
38
|
-
export default class Avatar extends EventEmitterMixin(ReadyMixin(LitElement)) {
|
|
39
|
+
export default class Avatar extends TooltipMixin(EventEmitterMixin(ReadyMixin(LitElement))) {
|
|
39
40
|
constructor() {
|
|
40
41
|
super(...arguments);
|
|
41
42
|
/**
|
|
@@ -109,6 +110,7 @@ export default class Avatar extends EventEmitterMixin(ReadyMixin(LitElement)) {
|
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
updated(changedProperties) {
|
|
113
|
+
super.updated(changedProperties);
|
|
112
114
|
// Reset image error state when src changes
|
|
113
115
|
if (changedProperties.has('src')) {
|
|
114
116
|
this.imageError = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.js","sourceRoot":"","sources":["../../../src/components/avatar/Avatar.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"Avatar.js","sourceRoot":"","sources":["../../../src/components/avatar/Avatar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export type PopoverOffset = 'sm' | 'md' | 'lg' | 'xl';
|
|
3
|
+
export interface PopoverProps {
|
|
4
|
+
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
5
|
+
trigger?: 'click' | 'hover' | 'focus';
|
|
6
|
+
delay?: number;
|
|
7
|
+
offset?: PopoverOffset | null;
|
|
8
|
+
noArrow?: boolean;
|
|
9
|
+
open?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const Popover_base: (new (...args: any[]) => import("../../util/EventEmitterMixin.js").EventEmitterMixinInterface) & (new (...args: any[]) => import("../../util/ReadyMixin.js").ReadyMixinInterface) & typeof LitElement;
|
|
12
|
+
/**
|
|
13
|
+
* A popover component for displaying rich interactive content anchored to a trigger element.
|
|
14
|
+
*
|
|
15
|
+
* Uses the native HTML Popover API for top-layer rendering, light dismiss (click-outside
|
|
16
|
+
* and Escape for click triggers), and focus management. CSS anchor positioning handles
|
|
17
|
+
* viewport-aware placement.
|
|
18
|
+
*
|
|
19
|
+
* For click triggers (`popover="auto"`), the browser provides:
|
|
20
|
+
* - Light dismiss (Escape key and click-outside)
|
|
21
|
+
* - Top-layer rendering (no z-index needed)
|
|
22
|
+
* - Focus restoration on close
|
|
23
|
+
* - `autofocus` support — add `autofocus` to an element inside `slot="content"`
|
|
24
|
+
* to have it receive focus when the popover opens
|
|
25
|
+
*
|
|
26
|
+
* @element btu-popover
|
|
27
|
+
*
|
|
28
|
+
* @fires {CustomEvent} btu-popover-show - Fired when the popover opens
|
|
29
|
+
* @fires {CustomEvent} btu-popover-hide - Fired when the popover closes
|
|
30
|
+
*
|
|
31
|
+
* @slot trigger - The element that activates the popover
|
|
32
|
+
* @slot content - Rich HTML content displayed inside the popover panel
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```html
|
|
36
|
+
* <btu-popover position="bottom" trigger="click">
|
|
37
|
+
* <button slot="trigger">Open</button>
|
|
38
|
+
* <div slot="content">
|
|
39
|
+
* <h3>Title</h3>
|
|
40
|
+
* <p>Rich content here</p>
|
|
41
|
+
* </div>
|
|
42
|
+
* </btu-popover>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export default class Popover extends Popover_base {
|
|
46
|
+
/**
|
|
47
|
+
* Position relative to the trigger element.
|
|
48
|
+
* Auto-flips when constrained by the viewport.
|
|
49
|
+
* @attr
|
|
50
|
+
*/
|
|
51
|
+
position: 'top' | 'bottom' | 'left' | 'right';
|
|
52
|
+
/**
|
|
53
|
+
* How the popover is activated.
|
|
54
|
+
* - 'click': Toggle on click with light dismiss
|
|
55
|
+
* - 'hover': Show on mouseenter with delay
|
|
56
|
+
* - 'focus': Show on focusin
|
|
57
|
+
* @attr
|
|
58
|
+
*/
|
|
59
|
+
trigger: 'click' | 'hover' | 'focus';
|
|
60
|
+
/**
|
|
61
|
+
* Show delay in milliseconds (hover trigger only).
|
|
62
|
+
* @attr
|
|
63
|
+
*/
|
|
64
|
+
delay: number;
|
|
65
|
+
/**
|
|
66
|
+
* Gap between trigger and popover (sm=4px, md=8px, lg=12px, xl=16px).
|
|
67
|
+
* @attr
|
|
68
|
+
*/
|
|
69
|
+
offset: PopoverOffset | null;
|
|
70
|
+
/**
|
|
71
|
+
* Hide the arrow pseudo-element.
|
|
72
|
+
* @attr
|
|
73
|
+
*/
|
|
74
|
+
noArrow: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Programmatic open/close state (reflected).
|
|
77
|
+
* @attr
|
|
78
|
+
*/
|
|
79
|
+
open: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Accessible label for the popover panel (applied as aria-label on the dialog).
|
|
82
|
+
* @attr panel-label
|
|
83
|
+
*/
|
|
84
|
+
panelLabel: string;
|
|
85
|
+
/** @internal */
|
|
86
|
+
private _panelEl;
|
|
87
|
+
/** @internal */
|
|
88
|
+
private _panelId;
|
|
89
|
+
/** @internal */
|
|
90
|
+
private _anchorName;
|
|
91
|
+
/** @internal */
|
|
92
|
+
private _showTimer;
|
|
93
|
+
/** @internal */
|
|
94
|
+
private _hideTimer;
|
|
95
|
+
/** @internal */
|
|
96
|
+
private _isVisible;
|
|
97
|
+
/** @internal */
|
|
98
|
+
private initialClasses;
|
|
99
|
+
/** @internal bound listeners */
|
|
100
|
+
private _onTriggerMouseEnter;
|
|
101
|
+
private _onTriggerMouseLeave;
|
|
102
|
+
private _onTriggerFocusIn;
|
|
103
|
+
private _onTriggerFocusOut;
|
|
104
|
+
private _onPanelMouseEnter;
|
|
105
|
+
private _onPanelMouseLeave;
|
|
106
|
+
private _onNativeToggle;
|
|
107
|
+
private _onKeyDown;
|
|
108
|
+
createRenderRoot(): this;
|
|
109
|
+
connectedCallback(): void;
|
|
110
|
+
disconnectedCallback(): void;
|
|
111
|
+
willUpdate(): void;
|
|
112
|
+
firstUpdated(): void;
|
|
113
|
+
updated(changedProperties: Map<string | number | symbol, unknown>): void;
|
|
114
|
+
/** @internal Creates the popover panel and moves slot="content" children into it */
|
|
115
|
+
private _setupPanel;
|
|
116
|
+
/** @internal */
|
|
117
|
+
private _buildPanelClasses;
|
|
118
|
+
/** @internal */
|
|
119
|
+
private _getTriggerEl;
|
|
120
|
+
/** @internal */
|
|
121
|
+
private _bindTriggerListeners;
|
|
122
|
+
/** @internal */
|
|
123
|
+
private _unbindTriggerListeners;
|
|
124
|
+
/** @internal */
|
|
125
|
+
private _bindPanelListeners;
|
|
126
|
+
/** @internal */
|
|
127
|
+
private _unbindPanelListeners;
|
|
128
|
+
/** @internal */
|
|
129
|
+
private _show;
|
|
130
|
+
/** @internal */
|
|
131
|
+
private _hide;
|
|
132
|
+
/** @internal Native toggle event — single source of truth for state changes */
|
|
133
|
+
private _handleNativeToggle;
|
|
134
|
+
/** @internal Escape dismisses for popover="manual" (hover/focus triggers) */
|
|
135
|
+
private _handleKeyDown;
|
|
136
|
+
/** @internal */
|
|
137
|
+
private _clearShowTimer;
|
|
138
|
+
/** @internal */
|
|
139
|
+
private _clearHideTimer;
|
|
140
|
+
/** @internal */
|
|
141
|
+
private _clearTimers;
|
|
142
|
+
/** @internal Hover trigger: show with delay */
|
|
143
|
+
private _handleTriggerMouseEnter;
|
|
144
|
+
/** @internal Hover trigger: hide with small delay for cursor travel */
|
|
145
|
+
private _handleTriggerMouseLeave;
|
|
146
|
+
/** @internal Focus trigger: show immediately */
|
|
147
|
+
private _handleTriggerFocusIn;
|
|
148
|
+
/** @internal Focus trigger: hide immediately */
|
|
149
|
+
private _handleTriggerFocusOut;
|
|
150
|
+
/** @internal Keep popover open when hovering the panel (hover trigger) */
|
|
151
|
+
private _handlePanelMouseEnter;
|
|
152
|
+
/** @internal Hide when mouse leaves the panel (hover trigger) */
|
|
153
|
+
private _handlePanelMouseLeave;
|
|
154
|
+
}
|
|
155
|
+
declare global {
|
|
156
|
+
interface HTMLElementTagNameMap {
|
|
157
|
+
'btu-popover': Popover;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export {};
|
|
161
|
+
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../src/components/popover/Popover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement } from 'lit';
|
|
8
|
+
import { property } from 'lit/decorators.js';
|
|
9
|
+
import { EventEmitterMixin } from '../../util/EventEmitterMixin.js';
|
|
10
|
+
import { ReadyMixin } from '../../util/ReadyMixin.js';
|
|
11
|
+
// Tailwind content scanning requires complete class names (no template literals).
|
|
12
|
+
const POSITION_CLASSES = {
|
|
13
|
+
top: 'btu-popover-top',
|
|
14
|
+
bottom: 'btu-popover-bottom',
|
|
15
|
+
left: 'btu-popover-left',
|
|
16
|
+
right: 'btu-popover-right',
|
|
17
|
+
};
|
|
18
|
+
const OFFSET_CLASSES = {
|
|
19
|
+
sm: 'btu-popover-offset-sm',
|
|
20
|
+
md: 'btu-popover-offset-md',
|
|
21
|
+
lg: 'btu-popover-offset-lg',
|
|
22
|
+
xl: 'btu-popover-offset-xl',
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A popover component for displaying rich interactive content anchored to a trigger element.
|
|
26
|
+
*
|
|
27
|
+
* Uses the native HTML Popover API for top-layer rendering, light dismiss (click-outside
|
|
28
|
+
* and Escape for click triggers), and focus management. CSS anchor positioning handles
|
|
29
|
+
* viewport-aware placement.
|
|
30
|
+
*
|
|
31
|
+
* For click triggers (`popover="auto"`), the browser provides:
|
|
32
|
+
* - Light dismiss (Escape key and click-outside)
|
|
33
|
+
* - Top-layer rendering (no z-index needed)
|
|
34
|
+
* - Focus restoration on close
|
|
35
|
+
* - `autofocus` support — add `autofocus` to an element inside `slot="content"`
|
|
36
|
+
* to have it receive focus when the popover opens
|
|
37
|
+
*
|
|
38
|
+
* @element btu-popover
|
|
39
|
+
*
|
|
40
|
+
* @fires {CustomEvent} btu-popover-show - Fired when the popover opens
|
|
41
|
+
* @fires {CustomEvent} btu-popover-hide - Fired when the popover closes
|
|
42
|
+
*
|
|
43
|
+
* @slot trigger - The element that activates the popover
|
|
44
|
+
* @slot content - Rich HTML content displayed inside the popover panel
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```html
|
|
48
|
+
* <btu-popover position="bottom" trigger="click">
|
|
49
|
+
* <button slot="trigger">Open</button>
|
|
50
|
+
* <div slot="content">
|
|
51
|
+
* <h3>Title</h3>
|
|
52
|
+
* <p>Rich content here</p>
|
|
53
|
+
* </div>
|
|
54
|
+
* </btu-popover>
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export default class Popover extends EventEmitterMixin(ReadyMixin(LitElement)) {
|
|
58
|
+
constructor() {
|
|
59
|
+
super(...arguments);
|
|
60
|
+
/**
|
|
61
|
+
* Position relative to the trigger element.
|
|
62
|
+
* Auto-flips when constrained by the viewport.
|
|
63
|
+
* @attr
|
|
64
|
+
*/
|
|
65
|
+
this.position = 'bottom';
|
|
66
|
+
/**
|
|
67
|
+
* How the popover is activated.
|
|
68
|
+
* - 'click': Toggle on click with light dismiss
|
|
69
|
+
* - 'hover': Show on mouseenter with delay
|
|
70
|
+
* - 'focus': Show on focusin
|
|
71
|
+
* @attr
|
|
72
|
+
*/
|
|
73
|
+
this.trigger = 'click';
|
|
74
|
+
/**
|
|
75
|
+
* Show delay in milliseconds (hover trigger only).
|
|
76
|
+
* @attr
|
|
77
|
+
*/
|
|
78
|
+
this.delay = 300;
|
|
79
|
+
/**
|
|
80
|
+
* Gap between trigger and popover (sm=4px, md=8px, lg=12px, xl=16px).
|
|
81
|
+
* @attr
|
|
82
|
+
*/
|
|
83
|
+
this.offset = null;
|
|
84
|
+
/**
|
|
85
|
+
* Hide the arrow pseudo-element.
|
|
86
|
+
* @attr
|
|
87
|
+
*/
|
|
88
|
+
this.noArrow = false;
|
|
89
|
+
/**
|
|
90
|
+
* Programmatic open/close state (reflected).
|
|
91
|
+
* @attr
|
|
92
|
+
*/
|
|
93
|
+
this.open = false;
|
|
94
|
+
/**
|
|
95
|
+
* Accessible label for the popover panel (applied as aria-label on the dialog).
|
|
96
|
+
* @attr panel-label
|
|
97
|
+
*/
|
|
98
|
+
this.panelLabel = '';
|
|
99
|
+
/** @internal */
|
|
100
|
+
this._panelEl = null;
|
|
101
|
+
/** @internal */
|
|
102
|
+
this._panelId = `btu-popover-${crypto.randomUUID()}`;
|
|
103
|
+
/** @internal */
|
|
104
|
+
this._anchorName = `--btu-popover-trigger-${crypto.randomUUID()}`;
|
|
105
|
+
/** @internal */
|
|
106
|
+
this._showTimer = null;
|
|
107
|
+
/** @internal */
|
|
108
|
+
this._hideTimer = null;
|
|
109
|
+
/** @internal */
|
|
110
|
+
this._isVisible = false;
|
|
111
|
+
/** @internal */
|
|
112
|
+
this.initialClasses = [];
|
|
113
|
+
/** @internal bound listeners */
|
|
114
|
+
this._onTriggerMouseEnter = this._handleTriggerMouseEnter.bind(this);
|
|
115
|
+
this._onTriggerMouseLeave = this._handleTriggerMouseLeave.bind(this);
|
|
116
|
+
this._onTriggerFocusIn = this._handleTriggerFocusIn.bind(this);
|
|
117
|
+
this._onTriggerFocusOut = this._handleTriggerFocusOut.bind(this);
|
|
118
|
+
this._onPanelMouseEnter = this._handlePanelMouseEnter.bind(this);
|
|
119
|
+
this._onPanelMouseLeave = this._handlePanelMouseLeave.bind(this);
|
|
120
|
+
this._onNativeToggle = this._handleNativeToggle.bind(this);
|
|
121
|
+
this._onKeyDown = this._handleKeyDown.bind(this);
|
|
122
|
+
}
|
|
123
|
+
createRenderRoot() {
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
connectedCallback() {
|
|
127
|
+
super.connectedCallback();
|
|
128
|
+
if (this.className) {
|
|
129
|
+
this.initialClasses = this.className.split(' ').filter(c => c.trim());
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
disconnectedCallback() {
|
|
133
|
+
this._clearTimers();
|
|
134
|
+
this._unbindTriggerListeners();
|
|
135
|
+
this._unbindPanelListeners();
|
|
136
|
+
document.removeEventListener('keydown', this._onKeyDown);
|
|
137
|
+
if (this._panelEl) {
|
|
138
|
+
try {
|
|
139
|
+
this._panelEl.hidePopover();
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
if (!(e instanceof DOMException && e.name === 'InvalidStateError')) {
|
|
143
|
+
console.warn('[btu-popover] Failed to hide popover during disconnect:', e);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
this._panelEl.removeEventListener('toggle', this._onNativeToggle);
|
|
147
|
+
this._panelEl.remove();
|
|
148
|
+
this._panelEl = null;
|
|
149
|
+
}
|
|
150
|
+
this._isVisible = false;
|
|
151
|
+
super.disconnectedCallback();
|
|
152
|
+
}
|
|
153
|
+
willUpdate() {
|
|
154
|
+
const classes = [...this.initialClasses];
|
|
155
|
+
this.className = classes.filter(Boolean).join(' ');
|
|
156
|
+
}
|
|
157
|
+
firstUpdated() {
|
|
158
|
+
this._setupPanel();
|
|
159
|
+
this._bindTriggerListeners();
|
|
160
|
+
// If initially open, show immediately
|
|
161
|
+
if (this.open) {
|
|
162
|
+
this._show();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
updated(changedProperties) {
|
|
166
|
+
super.updated(changedProperties);
|
|
167
|
+
if (changedProperties.has('trigger') && changedProperties.get('trigger') !== undefined) {
|
|
168
|
+
this._unbindTriggerListeners();
|
|
169
|
+
this._bindTriggerListeners();
|
|
170
|
+
// Update popover mode when trigger changes
|
|
171
|
+
if (this._panelEl) {
|
|
172
|
+
if (this._isVisible) {
|
|
173
|
+
this._hide();
|
|
174
|
+
}
|
|
175
|
+
this._panelEl.setAttribute('popover', this.trigger === 'click' ? 'auto' : 'manual');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (changedProperties.has('position') || changedProperties.has('noArrow') || changedProperties.has('offset')) {
|
|
179
|
+
if (this._panelEl) {
|
|
180
|
+
this._panelEl.className = this._buildPanelClasses();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (changedProperties.has('panelLabel') && this._panelEl) {
|
|
184
|
+
if (this.panelLabel) {
|
|
185
|
+
this._panelEl.setAttribute('aria-label', this.panelLabel);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this._panelEl.removeAttribute('aria-label');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Sync programmatic open/close
|
|
192
|
+
if (changedProperties.has('open') && changedProperties.get('open') !== undefined) {
|
|
193
|
+
if (this.open && !this._isVisible) {
|
|
194
|
+
this._show();
|
|
195
|
+
}
|
|
196
|
+
else if (!this.open && this._isVisible) {
|
|
197
|
+
this._hide();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** @internal Creates the popover panel and moves slot="content" children into it */
|
|
202
|
+
_setupPanel() {
|
|
203
|
+
const triggerEl = this.querySelector('[slot="trigger"]');
|
|
204
|
+
const contentEl = this.querySelector('[slot="content"]');
|
|
205
|
+
if (!triggerEl) {
|
|
206
|
+
console.warn('[btu-popover] Missing required slot="trigger" element.');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Set anchor name on trigger element
|
|
210
|
+
triggerEl.style.setProperty('anchor-name', this._anchorName);
|
|
211
|
+
// Create panel
|
|
212
|
+
this._panelEl = document.createElement('div');
|
|
213
|
+
this._panelEl.id = this._panelId;
|
|
214
|
+
this._panelEl.className = this._buildPanelClasses();
|
|
215
|
+
this._panelEl.setAttribute('role', 'dialog');
|
|
216
|
+
if (this.panelLabel) {
|
|
217
|
+
this._panelEl.setAttribute('aria-label', this.panelLabel);
|
|
218
|
+
}
|
|
219
|
+
this._panelEl.setAttribute('data-popover-internal', '');
|
|
220
|
+
this._panelEl.style.setProperty('position-anchor', this._anchorName);
|
|
221
|
+
// Set native popover attribute
|
|
222
|
+
this._panelEl.setAttribute('popover', this.trigger === 'click' ? 'auto' : 'manual');
|
|
223
|
+
// Listen for native toggle events — single source of truth for state
|
|
224
|
+
this._panelEl.addEventListener('toggle', this._onNativeToggle);
|
|
225
|
+
// Move content into panel
|
|
226
|
+
if (contentEl) {
|
|
227
|
+
contentEl.removeAttribute('slot');
|
|
228
|
+
contentEl.style.display = '';
|
|
229
|
+
this._panelEl.appendChild(contentEl);
|
|
230
|
+
}
|
|
231
|
+
this.appendChild(this._panelEl);
|
|
232
|
+
// Set up aria on trigger
|
|
233
|
+
triggerEl.setAttribute('aria-expanded', 'false');
|
|
234
|
+
triggerEl.setAttribute('aria-controls', this._panelId);
|
|
235
|
+
// Bind panel listeners for hover trigger
|
|
236
|
+
this._bindPanelListeners();
|
|
237
|
+
}
|
|
238
|
+
/** @internal */
|
|
239
|
+
_buildPanelClasses() {
|
|
240
|
+
const classes = ['btu-popover', POSITION_CLASSES[this.position]];
|
|
241
|
+
if (this.offset && OFFSET_CLASSES[this.offset])
|
|
242
|
+
classes.push(OFFSET_CLASSES[this.offset]);
|
|
243
|
+
if (this.noArrow)
|
|
244
|
+
classes.push('btu-popover-no-arrow');
|
|
245
|
+
return classes.join(' ');
|
|
246
|
+
}
|
|
247
|
+
/** @internal */
|
|
248
|
+
_getTriggerEl() {
|
|
249
|
+
return this.querySelector('[slot="trigger"]');
|
|
250
|
+
}
|
|
251
|
+
/** @internal */
|
|
252
|
+
_bindTriggerListeners() {
|
|
253
|
+
const triggerEl = this._getTriggerEl();
|
|
254
|
+
if (!triggerEl)
|
|
255
|
+
return;
|
|
256
|
+
if (this.trigger === 'click') {
|
|
257
|
+
triggerEl.setAttribute('popovertarget', this._panelId);
|
|
258
|
+
}
|
|
259
|
+
if (this.trigger === 'hover') {
|
|
260
|
+
triggerEl.addEventListener('mouseenter', this._onTriggerMouseEnter);
|
|
261
|
+
triggerEl.addEventListener('mouseleave', this._onTriggerMouseLeave);
|
|
262
|
+
}
|
|
263
|
+
if (this.trigger === 'focus') {
|
|
264
|
+
triggerEl.addEventListener('focusin', this._onTriggerFocusIn);
|
|
265
|
+
triggerEl.addEventListener('focusout', this._onTriggerFocusOut);
|
|
266
|
+
}
|
|
267
|
+
// popover="manual" doesn't get browser Escape handling — add it ourselves
|
|
268
|
+
if (this.trigger !== 'click') {
|
|
269
|
+
document.addEventListener('keydown', this._onKeyDown);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/** @internal */
|
|
273
|
+
_unbindTriggerListeners() {
|
|
274
|
+
const triggerEl = this._getTriggerEl();
|
|
275
|
+
if (!triggerEl)
|
|
276
|
+
return;
|
|
277
|
+
triggerEl.removeAttribute('popovertarget');
|
|
278
|
+
triggerEl.removeEventListener('mouseenter', this._onTriggerMouseEnter);
|
|
279
|
+
triggerEl.removeEventListener('mouseleave', this._onTriggerMouseLeave);
|
|
280
|
+
triggerEl.removeEventListener('focusin', this._onTriggerFocusIn);
|
|
281
|
+
triggerEl.removeEventListener('focusout', this._onTriggerFocusOut);
|
|
282
|
+
document.removeEventListener('keydown', this._onKeyDown);
|
|
283
|
+
}
|
|
284
|
+
/** @internal */
|
|
285
|
+
_bindPanelListeners() {
|
|
286
|
+
if (!this._panelEl)
|
|
287
|
+
return;
|
|
288
|
+
this._panelEl.addEventListener('mouseenter', this._onPanelMouseEnter);
|
|
289
|
+
this._panelEl.addEventListener('mouseleave', this._onPanelMouseLeave);
|
|
290
|
+
}
|
|
291
|
+
/** @internal */
|
|
292
|
+
_unbindPanelListeners() {
|
|
293
|
+
if (!this._panelEl)
|
|
294
|
+
return;
|
|
295
|
+
this._panelEl.removeEventListener('mouseenter', this._onPanelMouseEnter);
|
|
296
|
+
this._panelEl.removeEventListener('mouseleave', this._onPanelMouseLeave);
|
|
297
|
+
}
|
|
298
|
+
/** @internal */
|
|
299
|
+
_show() {
|
|
300
|
+
this._clearHideTimer();
|
|
301
|
+
if (this._isVisible || !this._panelEl)
|
|
302
|
+
return;
|
|
303
|
+
try {
|
|
304
|
+
this._panelEl.showPopover();
|
|
305
|
+
}
|
|
306
|
+
catch (e) {
|
|
307
|
+
if (!(e instanceof DOMException && e.name === 'InvalidStateError')) {
|
|
308
|
+
console.warn('[btu-popover] Failed to show popover:', e);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/** @internal */
|
|
313
|
+
_hide() {
|
|
314
|
+
this._clearTimers();
|
|
315
|
+
if (!this._isVisible || !this._panelEl)
|
|
316
|
+
return;
|
|
317
|
+
try {
|
|
318
|
+
this._panelEl.hidePopover();
|
|
319
|
+
}
|
|
320
|
+
catch (e) {
|
|
321
|
+
if (!(e instanceof DOMException && e.name === 'InvalidStateError')) {
|
|
322
|
+
console.warn('[btu-popover] Failed to hide popover:', e);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/** @internal Native toggle event — single source of truth for state changes */
|
|
327
|
+
_handleNativeToggle(e) {
|
|
328
|
+
const { newState } = e;
|
|
329
|
+
if (newState === 'open') {
|
|
330
|
+
this._isVisible = true;
|
|
331
|
+
this.open = true;
|
|
332
|
+
const triggerEl = this._getTriggerEl();
|
|
333
|
+
if (triggerEl) {
|
|
334
|
+
triggerEl.setAttribute('aria-expanded', 'true');
|
|
335
|
+
}
|
|
336
|
+
this.emit('btu-popover-show');
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
this._isVisible = false;
|
|
340
|
+
this.open = false;
|
|
341
|
+
const triggerEl = this._getTriggerEl();
|
|
342
|
+
if (triggerEl) {
|
|
343
|
+
triggerEl.setAttribute('aria-expanded', 'false');
|
|
344
|
+
// Restore focus to trigger if focus was lost (e.g., programmatic close)
|
|
345
|
+
if (document.activeElement === document.body) {
|
|
346
|
+
triggerEl.focus();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
this.emit('btu-popover-hide');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/** @internal Escape dismisses for popover="manual" (hover/focus triggers) */
|
|
353
|
+
_handleKeyDown(e) {
|
|
354
|
+
if (e.key === 'Escape') {
|
|
355
|
+
this._clearTimers();
|
|
356
|
+
this._hide();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/** @internal */
|
|
360
|
+
_clearShowTimer() {
|
|
361
|
+
if (this._showTimer !== null) {
|
|
362
|
+
clearTimeout(this._showTimer);
|
|
363
|
+
this._showTimer = null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/** @internal */
|
|
367
|
+
_clearHideTimer() {
|
|
368
|
+
if (this._hideTimer !== null) {
|
|
369
|
+
clearTimeout(this._hideTimer);
|
|
370
|
+
this._hideTimer = null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/** @internal */
|
|
374
|
+
_clearTimers() {
|
|
375
|
+
this._clearShowTimer();
|
|
376
|
+
this._clearHideTimer();
|
|
377
|
+
}
|
|
378
|
+
/** @internal Hover trigger: show with delay */
|
|
379
|
+
_handleTriggerMouseEnter() {
|
|
380
|
+
this._clearTimers();
|
|
381
|
+
this._showTimer = setTimeout(() => this._show(), this.delay);
|
|
382
|
+
}
|
|
383
|
+
/** @internal Hover trigger: hide with small delay for cursor travel */
|
|
384
|
+
_handleTriggerMouseLeave() {
|
|
385
|
+
this._clearTimers();
|
|
386
|
+
this._hideTimer = setTimeout(() => this._hide(), 100);
|
|
387
|
+
}
|
|
388
|
+
/** @internal Focus trigger: show immediately */
|
|
389
|
+
_handleTriggerFocusIn() {
|
|
390
|
+
this._clearTimers();
|
|
391
|
+
this._show();
|
|
392
|
+
}
|
|
393
|
+
/** @internal Focus trigger: hide immediately */
|
|
394
|
+
_handleTriggerFocusOut() {
|
|
395
|
+
this._clearTimers();
|
|
396
|
+
this._hide();
|
|
397
|
+
}
|
|
398
|
+
/** @internal Keep popover open when hovering the panel (hover trigger) */
|
|
399
|
+
_handlePanelMouseEnter() {
|
|
400
|
+
if (this.trigger === 'hover') {
|
|
401
|
+
this._clearTimers();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/** @internal Hide when mouse leaves the panel (hover trigger) */
|
|
405
|
+
_handlePanelMouseLeave() {
|
|
406
|
+
if (this.trigger === 'hover') {
|
|
407
|
+
this._clearTimers();
|
|
408
|
+
this._hideTimer = setTimeout(() => this._hide(), 100);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
__decorate([
|
|
413
|
+
property({ attribute: 'position' })
|
|
414
|
+
], Popover.prototype, "position", void 0);
|
|
415
|
+
__decorate([
|
|
416
|
+
property({ attribute: 'trigger' })
|
|
417
|
+
], Popover.prototype, "trigger", void 0);
|
|
418
|
+
__decorate([
|
|
419
|
+
property({ attribute: 'delay', type: Number })
|
|
420
|
+
], Popover.prototype, "delay", void 0);
|
|
421
|
+
__decorate([
|
|
422
|
+
property({ attribute: 'offset' })
|
|
423
|
+
], Popover.prototype, "offset", void 0);
|
|
424
|
+
__decorate([
|
|
425
|
+
property({ attribute: 'no-arrow', type: Boolean })
|
|
426
|
+
], Popover.prototype, "noArrow", void 0);
|
|
427
|
+
__decorate([
|
|
428
|
+
property({ attribute: 'open', type: Boolean, reflect: true })
|
|
429
|
+
], Popover.prototype, "open", void 0);
|
|
430
|
+
__decorate([
|
|
431
|
+
property({ attribute: 'panel-label' })
|
|
432
|
+
], Popover.prototype, "panelLabel", void 0);
|
|
433
|
+
if (!customElements.get('btu-popover')) {
|
|
434
|
+
customElements.define('btu-popover', Popover);
|
|
435
|
+
}
|
|
436
|
+
//# sourceMappingURL=Popover.js.map
|