@telesign/boreal-web-components 0.1.0-alpha.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/LICENSE +21 -0
- package/components-build/bds-banner.d.ts +11 -0
- package/components-build/bds-banner.js +1 -0
- package/components-build/bds-typography.d.ts +11 -0
- package/components-build/bds-typography.js +1 -0
- package/components-build/index.d.ts +35 -0
- package/components-build/index.js +1 -0
- package/components-build/my-component.d.ts +11 -0
- package/components-build/my-component.js +1 -0
- package/components-build/p-B9wshZ_4.js +1 -0
- package/components-build/p-noyWJ11s.js +1 -0
- package/custom-elements.json +764 -0
- package/dist/boreal-web-components/boreal-web-components.css +1 -0
- package/dist/boreal-web-components/boreal-web-components.esm.js +1 -0
- package/dist/boreal-web-components/boreal-web-components.js +127 -0
- package/dist/boreal-web-components/css/boreal.css +1594 -0
- package/dist/boreal-web-components/css/global.css +682 -0
- package/dist/boreal-web-components/css/theme-connect.css +227 -0
- package/dist/boreal-web-components/css/theme-engage.css +227 -0
- package/dist/boreal-web-components/css/theme-protect.css +227 -0
- package/dist/boreal-web-components/css/theme-proximus.css +227 -0
- package/dist/boreal-web-components/index.esm.js +0 -0
- package/dist/boreal-web-components/p-412d037b.system.entry.js +1 -0
- package/dist/boreal-web-components/p-527a761b.entry.js +1 -0
- package/dist/boreal-web-components/p-5666a22a.system.entry.js +1 -0
- package/dist/boreal-web-components/p-B-PpI2Xv.system.js +1 -0
- package/dist/boreal-web-components/p-B9wshZ_4.js +1 -0
- package/dist/boreal-web-components/p-BQdH0ijK.system.js +2 -0
- package/dist/boreal-web-components/p-BbPAtVJG.system.js +1 -0
- package/dist/boreal-web-components/p-CMd-Mv-5.system.js +1 -0
- package/dist/boreal-web-components/p-CaVEtaG3.system.js +1 -0
- package/dist/boreal-web-components/p-DQuL1Twl.js +1 -0
- package/dist/boreal-web-components/p-DgFiTd6X.js +2 -0
- package/dist/boreal-web-components/p-YWpyar7R.system.js +1 -0
- package/dist/boreal-web-components/p-b818618b.entry.js +1 -0
- package/dist/boreal-web-components/p-d596406b.entry.js +1 -0
- package/dist/boreal-web-components/p-e37e7dba.system.entry.js +1 -0
- package/dist/boreal-web-components/p-noyWJ11s.js +1 -0
- package/dist/boreal-web-components/scss/global/_fonts.scss +1 -0
- package/dist/boreal-web-components/scss/global/_index.scss +3 -0
- package/dist/boreal-web-components/scss/global/_reset.scss +50 -0
- package/dist/boreal-web-components/scss/global/_typography.scss +156 -0
- package/dist/boreal-web-components/scss/maps/_primitives.scss +461 -0
- package/dist/boreal-web-components/scss/maps/_theme-connect.scss +227 -0
- package/dist/boreal-web-components/scss/maps/_theme-engage.scss +227 -0
- package/dist/boreal-web-components/scss/maps/_theme-protect.scss +227 -0
- package/dist/boreal-web-components/scss/maps/_theme-proximus.scss +227 -0
- package/dist/boreal-web-components/scss/variables/_primitives.scss +459 -0
- package/dist/boreal-web-components/scss/variables/_theme-connect.scss +225 -0
- package/dist/boreal-web-components/scss/variables/_theme-engage.scss +225 -0
- package/dist/boreal-web-components/scss/variables/_theme-protect.scss +225 -0
- package/dist/boreal-web-components/scss/variables/_theme-proximus.scss +225 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/attributes-RPVEtBdj.js +90 -0
- package/dist/cjs/bds-banner.cjs.entry.js +130 -0
- package/dist/cjs/bds-typography.cjs.entry.js +167 -0
- package/dist/cjs/boreal-web-components.cjs.js +46 -0
- package/dist/cjs/index-CD9v53WJ.js +133 -0
- package/dist/cjs/index-Cdb66Tqj.js +2342 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/my-component.cjs.entry.js +29 -0
- package/dist/collection/collection-manifest.json +14 -0
- package/dist/collection/components/feedback/bds-banner/bds-banner.css +101 -0
- package/dist/collection/components/feedback/bds-banner/bds-banner.js +266 -0
- package/dist/collection/components/feedback/bds-banner/types/IBanner.js +1 -0
- package/dist/collection/components/my-component/my-component.css +3 -0
- package/dist/collection/components/my-component/my-component.js +95 -0
- package/dist/collection/components/titles-text/bds-typography/bds-typography.css +183 -0
- package/dist/collection/components/titles-text/bds-typography/bds-typography.js +577 -0
- package/dist/collection/components/titles-text/bds-typography/types/ITypography.js +1 -0
- package/dist/collection/components/titles-text/bds-typography/types/enum.js +23 -0
- package/dist/collection/components/titles-text/bds-typography/types/types.js +1 -0
- package/dist/collection/components/titles-text/bds-typography/utils/bds-typography-utils.js +41 -0
- package/dist/collection/css/boreal.css +1594 -0
- package/dist/collection/css/global.css +682 -0
- package/dist/collection/css/theme-connect.css +227 -0
- package/dist/collection/css/theme-engage.css +227 -0
- package/dist/collection/css/theme-protect.css +227 -0
- package/dist/collection/css/theme-proximus.css +227 -0
- package/dist/collection/index.js +1 -0
- package/dist/collection/mixins/anchored.mixin.js +272 -0
- package/dist/collection/mixins/floating.mixin.js +181 -0
- package/dist/collection/mixins/form-associated.mixin.js +95 -0
- package/dist/collection/mixins/index.js +3 -0
- package/dist/collection/scss/global/_fonts.scss +1 -0
- package/dist/collection/scss/global/_index.scss +3 -0
- package/dist/collection/scss/global/_reset.scss +50 -0
- package/dist/collection/scss/global/_typography.scss +156 -0
- package/dist/collection/scss/maps/_primitives.scss +461 -0
- package/dist/collection/scss/maps/_theme-connect.scss +227 -0
- package/dist/collection/scss/maps/_theme-engage.scss +227 -0
- package/dist/collection/scss/maps/_theme-protect.scss +227 -0
- package/dist/collection/scss/maps/_theme-proximus.scss +227 -0
- package/dist/collection/scss/variables/_primitives.scss +459 -0
- package/dist/collection/scss/variables/_theme-connect.scss +225 -0
- package/dist/collection/scss/variables/_theme-engage.scss +225 -0
- package/dist/collection/scss/variables/_theme-protect.scss +225 -0
- package/dist/collection/scss/variables/_theme-proximus.scss +225 -0
- package/dist/collection/services/floating/interfaces/Floating.js +1 -0
- package/dist/collection/services/floating/interfaces/Positioning.js +1 -0
- package/dist/collection/services/floating/interfaces/Props.js +1 -0
- package/dist/collection/services/floating/positioning.service.js +71 -0
- package/dist/collection/services/floating/types/Arrow.js +1 -0
- package/dist/collection/services/logger/Logger.js +47 -0
- package/dist/collection/types/alignment.js +6 -0
- package/dist/collection/types/form.js +1 -0
- package/dist/collection/types/index.js +5 -0
- package/dist/collection/types/position.js +11 -0
- package/dist/collection/types/size.js +7 -0
- package/dist/collection/types/states.js +22 -0
- package/dist/collection/types/stylesMap.js +1 -0
- package/dist/collection/utils/a11y/attributes.js +80 -0
- package/dist/collection/utils/a11y/index.js +1 -0
- package/dist/collection/utils/constants/common/Events.js +10 -0
- package/dist/collection/utils/constants/common/Keys.js +16 -0
- package/dist/collection/utils/dom/elements.js +22 -0
- package/dist/collection/utils/dom/index.js +1 -0
- package/dist/collection/utils/form/index.js +1 -0
- package/dist/collection/utils/form/internals.js +79 -0
- package/dist/collection/utils/helpers/common/BaseAttributes.js +17 -0
- package/dist/collection/utils/index.js +3 -0
- package/dist/css/boreal.css +1594 -0
- package/dist/css/global.css +682 -0
- package/dist/css/theme-connect.css +227 -0
- package/dist/css/theme-engage.css +227 -0
- package/dist/css/theme-protect.css +227 -0
- package/dist/css/theme-proximus.css +227 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/attributes-B9wshZ_4.js +86 -0
- package/dist/esm/bds-banner.entry.js +128 -0
- package/dist/esm/bds-typography.entry.js +165 -0
- package/dist/esm/boreal-web-components.js +42 -0
- package/dist/esm/index-DgFiTd6X.js +2332 -0
- package/dist/esm/index-noyWJ11s.js +131 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/my-component.entry.js +27 -0
- package/dist/esm/polyfills/core-js.js +11 -0
- package/dist/esm/polyfills/dom.js +79 -0
- package/dist/esm/polyfills/es5-html-element.js +1 -0
- package/dist/esm/polyfills/index.js +34 -0
- package/dist/esm/polyfills/system.js +6 -0
- package/dist/esm-es5/app-globals-DQuL1Twl.js +1 -0
- package/dist/esm-es5/attributes-B9wshZ_4.js +1 -0
- package/dist/esm-es5/bds-banner.entry.js +1 -0
- package/dist/esm-es5/bds-typography.entry.js +1 -0
- package/dist/esm-es5/boreal-web-components.js +1 -0
- package/dist/esm-es5/index-DgFiTd6X.js +2 -0
- package/dist/esm-es5/index-noyWJ11s.js +1 -0
- package/dist/esm-es5/index.js +0 -0
- package/dist/esm-es5/loader.js +1 -0
- package/dist/esm-es5/my-component.entry.js +1 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/scss/global/_fonts.scss +1 -0
- package/dist/scss/global/_index.scss +3 -0
- package/dist/scss/global/_reset.scss +50 -0
- package/dist/scss/global/_typography.scss +156 -0
- package/dist/scss/maps/_primitives.scss +461 -0
- package/dist/scss/maps/_theme-connect.scss +227 -0
- package/dist/scss/maps/_theme-engage.scss +227 -0
- package/dist/scss/maps/_theme-protect.scss +227 -0
- package/dist/scss/maps/_theme-proximus.scss +227 -0
- package/dist/scss/variables/_primitives.scss +459 -0
- package/dist/scss/variables/_theme-connect.scss +225 -0
- package/dist/scss/variables/_theme-engage.scss +225 -0
- package/dist/scss/variables/_theme-protect.scss +225 -0
- package/dist/scss/variables/_theme-proximus.scss +225 -0
- package/dist/types/components/feedback/bds-banner/bds-banner.d.ts +71 -0
- package/dist/types/components/feedback/bds-banner/types/IBanner.d.ts +10 -0
- package/dist/types/components/my-component/my-component.d.ts +16 -0
- package/dist/types/components/titles-text/bds-typography/bds-typography.d.ts +99 -0
- package/dist/types/components/titles-text/bds-typography/types/ITypography.d.ts +22 -0
- package/dist/types/components/titles-text/bds-typography/types/enum.d.ts +24 -0
- package/dist/types/components/titles-text/bds-typography/types/types.d.ts +4 -0
- package/dist/types/components/titles-text/bds-typography/utils/bds-typography-utils.d.ts +15 -0
- package/dist/types/components.d.ts +565 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/mixins/anchored.mixin.d.ts +228 -0
- package/dist/types/mixins/floating.mixin.d.ts +158 -0
- package/dist/types/mixins/form-associated.mixin.d.ts +127 -0
- package/dist/types/mixins/index.d.ts +4 -0
- package/dist/types/services/floating/interfaces/Floating.d.ts +38 -0
- package/dist/types/services/floating/interfaces/Positioning.d.ts +22 -0
- package/dist/types/services/floating/interfaces/Props.d.ts +35 -0
- package/dist/types/services/floating/positioning.service.d.ts +45 -0
- package/dist/types/services/floating/types/Arrow.d.ts +7 -0
- package/dist/types/services/logger/Logger.d.ts +50 -0
- package/dist/types/stencil-public-runtime.d.ts +1858 -0
- package/dist/types/types/alignment.d.ts +8 -0
- package/dist/types/types/form.d.ts +7 -0
- package/dist/types/types/index.d.ts +6 -0
- package/dist/types/types/position.d.ts +13 -0
- package/dist/types/types/size.d.ts +9 -0
- package/dist/types/types/states.d.ts +26 -0
- package/dist/types/types/stylesMap.d.ts +2 -0
- package/dist/types/utils/a11y/attributes.d.ts +13 -0
- package/dist/types/utils/a11y/index.d.ts +2 -0
- package/dist/types/utils/constants/common/Events.d.ts +14 -0
- package/dist/types/utils/constants/common/Keys.d.ts +18 -0
- package/dist/types/utils/dom/elements.d.ts +12 -0
- package/dist/types/utils/dom/index.d.ts +2 -0
- package/dist/types/utils/form/index.d.ts +2 -0
- package/dist/types/utils/form/internals.d.ts +66 -0
- package/dist/types/utils/helpers/common/BaseAttributes.d.ts +16 -0
- package/dist/types/utils/index.d.ts +4 -0
- package/loader/cdn.js +2 -0
- package/loader/index.cjs.js +2 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +2 -0
- package/loader/index.js +3 -0
- package/package.json +96 -0
- package/readme.md +111 -0
- package/scripts/copy-styles.js +18 -0
- package/scripts/postbuild.js +21 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { PositioningEngine } from "../services/floating/positioning.service";
|
|
2
|
+
import { floatingMixin } from "./floating.mixin";
|
|
3
|
+
import { Logger } from "../services/logger/Logger";
|
|
4
|
+
import { autoUpdate } from "@floating-ui/dom";
|
|
5
|
+
import { KEYBOARD } from "../utils/constants/common/Keys";
|
|
6
|
+
import { EVENTS } from "../utils/constants/common/Events";
|
|
7
|
+
/**
|
|
8
|
+
* Positioning and trigger mixin for anchor-based floating elements.
|
|
9
|
+
*
|
|
10
|
+
* Extends `floatingMixin` with two additional responsibilities:
|
|
11
|
+
* - **Positioning** — computes and maintains the position of the floating element
|
|
12
|
+
* relative to a trigger element using `IFloatingAdapter` (wraps Floating UI).
|
|
13
|
+
* Position is kept in sync via `autoUpdate` while the element is visible.
|
|
14
|
+
* - **Triggers** — manages DOM event listeners on the trigger element
|
|
15
|
+
* (focus/blur, click) to show and hide the floating element.
|
|
16
|
+
*
|
|
17
|
+
* Use this mixin for components whose floating element must be anchored
|
|
18
|
+
* to a specific DOM element: `Tooltip`, `Popover`, `Dropdown`.
|
|
19
|
+
*
|
|
20
|
+
* For viewport-relative components (Dialog, Drawer, Toast),
|
|
21
|
+
* use `backdropMixin` instead.
|
|
22
|
+
*
|
|
23
|
+
* ## Lifecycle flow
|
|
24
|
+
* ```
|
|
25
|
+
* showElement() → showPopover() + startAutoUpdate()
|
|
26
|
+
* hideElement() → hidePopover() + stopAutoUpdate()
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## Required by the component
|
|
30
|
+
* - `triggerSlot` — must be assigned to the trigger element before `show()` is called.
|
|
31
|
+
* - `floatingContent` — must be assigned via `ref` in the render method.
|
|
32
|
+
* - `options` — override this getter to customize placement, offset and strategy.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { Component, Element, Mixin, Prop, h } from '@stencil/core';
|
|
37
|
+
* import { anchoredMixin } from '@/mixins/anchored.mixin';
|
|
38
|
+
* import { FloatingHooks, FloatingMixinOptions } from '@/services/floating/interfaces/Floating';
|
|
39
|
+
*
|
|
40
|
+
* @Component({ tag: 'bds-tooltip' })
|
|
41
|
+
* export class BdsTooltip extends Mixin(anchoredMixin) {
|
|
42
|
+
*
|
|
43
|
+
* get options(): FloatingMixinOptions {
|
|
44
|
+
* return { placement: 'bottom', offset: 8, strategy: 'fixed' };
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* get hooks(): FloatingHooks {
|
|
48
|
+
* return {
|
|
49
|
+
* onBeforeShow: () => !this.disabled,
|
|
50
|
+
* onPositionUpdate: result => this.handlePosition(result),
|
|
51
|
+
* };
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* componentDidLoad() {
|
|
55
|
+
* const trigger = document.getElementById(this.trigger);
|
|
56
|
+
* if (trigger) {
|
|
57
|
+
* this.triggerSlot = trigger;
|
|
58
|
+
* trigger.addEventListener('click', () => this.toggle());
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* render() {
|
|
63
|
+
* return (
|
|
64
|
+
* <Host>
|
|
65
|
+
* <div
|
|
66
|
+
* popover="manual"
|
|
67
|
+
* ref={el => (this.floatingContent = el as HTMLElement)}
|
|
68
|
+
* />
|
|
69
|
+
* </Host>
|
|
70
|
+
* );
|
|
71
|
+
* }
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @see floatingMixin - base lifecycle mixin
|
|
76
|
+
* @see IFloatingAdapter - positioning adapter interface
|
|
77
|
+
* @see FloatingMixinOptions - positioning configuration interface
|
|
78
|
+
* @see FloatingHooks - lifecycle hook interface, includes `onPositionUpdate`
|
|
79
|
+
*/
|
|
80
|
+
export const anchoredMixin = (Base) => {
|
|
81
|
+
class Anchored extends floatingMixin(Base) {
|
|
82
|
+
/**
|
|
83
|
+
* Default positioning options.
|
|
84
|
+
* Override this getter in the component to customize placement,
|
|
85
|
+
* offset, strategy, flip, shift, and arrow.
|
|
86
|
+
*/
|
|
87
|
+
get options() {
|
|
88
|
+
return { placement: 'bottom', offset: 8, strategy: 'fixed' };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Shows the floating element using the Popover API
|
|
92
|
+
* and starts position auto-update relative to `triggerSlot`.
|
|
93
|
+
*
|
|
94
|
+
* @override floatingMixin.showElement
|
|
95
|
+
*/
|
|
96
|
+
showElement() {
|
|
97
|
+
this.floatingContent.showPopover();
|
|
98
|
+
this.isVisible = true;
|
|
99
|
+
this.startAutoUpdate(this.triggerSlot, this.floatingContent, this.options, result => {
|
|
100
|
+
this.hooks.onPositionUpdate?.(result);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Guards against showing without a valid trigger.
|
|
105
|
+
* Delegates to `floatingMixin.onBeforeShow` if the guard passes.
|
|
106
|
+
*
|
|
107
|
+
* @override floatingMixin.onBeforeShow
|
|
108
|
+
* @param target - Optional element that triggered the show action
|
|
109
|
+
* @returns `false` if `triggerSlot` is not set, otherwise delegates to super
|
|
110
|
+
*/
|
|
111
|
+
onBeforeShow(target) {
|
|
112
|
+
if (this.triggerSlot === null) {
|
|
113
|
+
this.logger.error('AnchoredMixin.show', 'triggerSlot is required');
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return super.onBeforeShow(target);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Hides the floating element using the Popover API
|
|
120
|
+
* and stops position auto-update.
|
|
121
|
+
*
|
|
122
|
+
* @override floatingMixin.hideElement
|
|
123
|
+
*/
|
|
124
|
+
hideElement() {
|
|
125
|
+
this.stopAutoUpdate();
|
|
126
|
+
this.floatingContent?.hidePopover();
|
|
127
|
+
this.isVisible = false;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handles slot change events to update the trigger element reference
|
|
131
|
+
* and re-attach event listeners to the new trigger.
|
|
132
|
+
*
|
|
133
|
+
* @param e - The slot change event
|
|
134
|
+
* @param showFn - Bound show function to attach as listener
|
|
135
|
+
* @param hideFn - Bound hide function to attach as listener
|
|
136
|
+
*/
|
|
137
|
+
handleSlotChange(e, showFn, hideFn) {
|
|
138
|
+
const newTrigger = e.target;
|
|
139
|
+
if (this.previousTrigger !== undefined && this.previousTrigger !== null) {
|
|
140
|
+
this.detachTriggerListeners(this.previousTrigger, showFn, hideFn);
|
|
141
|
+
}
|
|
142
|
+
if (newTrigger !== undefined && newTrigger !== null) {
|
|
143
|
+
this.attachTriggerListeners(newTrigger, showFn, hideFn);
|
|
144
|
+
this.previousTrigger = newTrigger;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Handles keyboard events on the trigger element.
|
|
149
|
+
* - `Enter` / `Space` — shows the floating element
|
|
150
|
+
* - `Escape` — hides the floating element
|
|
151
|
+
*
|
|
152
|
+
* @param e - The keyboard event
|
|
153
|
+
* @param showFn - Bound show function
|
|
154
|
+
* @param hideFn - Bound hide function
|
|
155
|
+
*/
|
|
156
|
+
handleKeydown(e, showFn, hideFn) {
|
|
157
|
+
if (e.key === KEYBOARD.Enter.key || e.key === ' ')
|
|
158
|
+
showFn();
|
|
159
|
+
if (e.key === KEYBOARD.Escape.key)
|
|
160
|
+
hideFn();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Computes the position of the floating element relative to the trigger
|
|
164
|
+
* using `IFloatingAdapter` and applies the result to the floating element's style.
|
|
165
|
+
*
|
|
166
|
+
* @param triggerElement - The anchor element
|
|
167
|
+
* @param floatingElement - The element to position
|
|
168
|
+
* @param options - Positioning options (placement, offset, flip, shift, arrow)
|
|
169
|
+
* @param onPositionUpdate - Optional callback invoked after each position update
|
|
170
|
+
*/
|
|
171
|
+
async updatePosition(triggerElement, floatingElement, options, onPositionUpdate) {
|
|
172
|
+
const result = await this.positionEngine.computePosition(triggerElement, floatingElement, {
|
|
173
|
+
placement: options.placement,
|
|
174
|
+
offset: options.offset,
|
|
175
|
+
flip: options.flip ?? true,
|
|
176
|
+
shift: options.shift ?? true,
|
|
177
|
+
arrow: options.arrow,
|
|
178
|
+
strategy: options.strategy ?? 'fixed',
|
|
179
|
+
});
|
|
180
|
+
this.positionEngine.applyPosition(floatingElement, result);
|
|
181
|
+
onPositionUpdate?.(result);
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Starts automatic position synchronization between the trigger
|
|
186
|
+
* and the floating element. Runs `updatePosition` once immediately,
|
|
187
|
+
* then subscribes to DOM/scroll/resize changes via `autoUpdate`.
|
|
188
|
+
*
|
|
189
|
+
* @param triggerElement - The anchor element
|
|
190
|
+
* @param floatingElement - The element to keep in sync
|
|
191
|
+
* @param options - Positioning options
|
|
192
|
+
* @param onPositionUpdate - Optional callback after each position update
|
|
193
|
+
*/
|
|
194
|
+
startAutoUpdate(triggerElement, floatingElement, options, onPositionUpdate) {
|
|
195
|
+
const sync = () => {
|
|
196
|
+
void this.updatePosition(triggerElement, floatingElement, options, onPositionUpdate);
|
|
197
|
+
};
|
|
198
|
+
sync(); // run once immediately
|
|
199
|
+
this.cleanupAutoUpdate = autoUpdate(triggerElement, floatingElement, sync);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Stops automatic position synchronization and clears the cleanup reference.
|
|
203
|
+
*/
|
|
204
|
+
stopAutoUpdate() {
|
|
205
|
+
this.cleanupAutoUpdate?.();
|
|
206
|
+
this.cleanupAutoUpdate = undefined;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Attaches focus and blur listeners to the trigger element.
|
|
210
|
+
*
|
|
211
|
+
* @param trigger - The trigger element
|
|
212
|
+
* @param showFn - Bound show function
|
|
213
|
+
* @param hideFn - Bound hide function
|
|
214
|
+
*/
|
|
215
|
+
attachTriggerListeners(trigger, showFn, hideFn) {
|
|
216
|
+
trigger.addEventListener(EVENTS.Focus, showFn);
|
|
217
|
+
trigger.addEventListener(EVENTS.Blur, hideFn);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Detaches focus and blur listeners from the trigger element.
|
|
221
|
+
*
|
|
222
|
+
* @param trigger - The trigger element
|
|
223
|
+
* @param showFn - Bound show function to remove
|
|
224
|
+
* @param hideFn - Bound hide function to remove
|
|
225
|
+
*/
|
|
226
|
+
detachTriggerListeners(trigger, showFn, hideFn) {
|
|
227
|
+
trigger.removeEventListener(EVENTS.Focus, showFn);
|
|
228
|
+
trigger.removeEventListener(EVENTS.Blur, hideFn);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Detaches trigger listeners and stops auto-update.
|
|
232
|
+
* Call this when the component disconnects from the DOM.
|
|
233
|
+
*
|
|
234
|
+
* @param showFn - Bound show function to remove
|
|
235
|
+
* @param hideFn - Bound hide function to remove
|
|
236
|
+
*/
|
|
237
|
+
floatingDisconnect(showFn, hideFn) {
|
|
238
|
+
if (this.previousTrigger !== undefined && this.previousTrigger !== null) {
|
|
239
|
+
this.detachTriggerListeners(this.previousTrigger, showFn, hideFn);
|
|
240
|
+
}
|
|
241
|
+
this.stopAutoUpdate();
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Initializes the positioning engine, logger, and binds lifecycle methods
|
|
245
|
+
* so they can be safely passed as event listener callbacks.
|
|
246
|
+
*
|
|
247
|
+
* @remarks `show`, `hide`, and `toggle` are bound here — not in `floatingMixin` —
|
|
248
|
+
* to ensure they resolve to the `anchoredMixin` overrides at call time.
|
|
249
|
+
*/
|
|
250
|
+
componentWillLoad() {
|
|
251
|
+
this.toggle = this.toggle.bind(this);
|
|
252
|
+
this.show = this.show.bind(this);
|
|
253
|
+
this.hide = this.hide.bind(this);
|
|
254
|
+
this.positionEngine = new PositioningEngine();
|
|
255
|
+
this.logger = new Logger();
|
|
256
|
+
this.cleanupAutoUpdate = undefined;
|
|
257
|
+
this.previousTrigger = undefined;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Cleans up trigger listeners, stops auto-update, and hides the floating element
|
|
261
|
+
* when the component is removed from the DOM.
|
|
262
|
+
*/
|
|
263
|
+
disconnectedCallback() {
|
|
264
|
+
if (this.previousTrigger !== undefined && this.previousTrigger !== null) {
|
|
265
|
+
this.floatingDisconnect(() => this.show(), () => this.hide());
|
|
266
|
+
}
|
|
267
|
+
this.stopAutoUpdate();
|
|
268
|
+
this.hide();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return Anchored;
|
|
272
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core lifecycle mixin for all floating elements in the design system.
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified lifecycle contract (`show`, `hide`, `toggle`, `isVisible`)
|
|
5
|
+
* and an extension mechanism via `FloatingHooks` that allows each component
|
|
6
|
+
* to inject its own logic at specific lifecycle points without modifying the mixin.
|
|
7
|
+
*
|
|
8
|
+
* This mixin is the base for all floating components. It does not handle
|
|
9
|
+
* positioning or triggers — use `anchoredMixin` for components that need
|
|
10
|
+
* to be anchored to a DOM element (Tooltip, Popover),
|
|
11
|
+
* or `backdropMixin` for viewport-relative components (Dialog, Drawer, Toast).
|
|
12
|
+
*
|
|
13
|
+
* ## Extension points
|
|
14
|
+
*
|
|
15
|
+
* Override `showElement` / `hideElement` to control how the element
|
|
16
|
+
* mounts and unmounts (e.g. `showPopover()`, `showModal()`, CSS animations).
|
|
17
|
+
*
|
|
18
|
+
* Override `hooks` to inject logic at lifecycle points:
|
|
19
|
+
* - `onBeforeShow` / `onBeforeHide` — return `false` to cancel the action
|
|
20
|
+
* - `onAfterShow` / `onAfterHide` — side effects after the action completes
|
|
21
|
+
* - `mounted` / `unmounted` — called after the element is shown or hidden
|
|
22
|
+
*
|
|
23
|
+
* ## Lifecycle flow
|
|
24
|
+
* ```
|
|
25
|
+
* show(): onBeforeShow() → showElement() → onAfterShow()
|
|
26
|
+
* hide(): onBeforeHide() → hideElement() → onAfterHide()
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { Component, Mixin, Prop } from '@stencil/core';
|
|
32
|
+
* import { floatingMixin } from '@/mixins/floating.mixin';
|
|
33
|
+
* import { FloatingHooks } from '@/services/floating/interfaces/Floating';
|
|
34
|
+
*
|
|
35
|
+
* @Component({ tag: 'bds-dialog' })
|
|
36
|
+
* export class BdsDialog extends Mixin(floatingMixin) {
|
|
37
|
+
* private dialogElement!: HTMLDialogElement;
|
|
38
|
+
*
|
|
39
|
+
* // Override showElement/hideElement to use the native <dialog> API
|
|
40
|
+
* showElement(): void {
|
|
41
|
+
* this.dialogElement.showModal();
|
|
42
|
+
* this.isVisible = true;
|
|
43
|
+
* }
|
|
44
|
+
* hideElement(): void {
|
|
45
|
+
* this.dialogElement.close();
|
|
46
|
+
* this.isVisible = false;
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* // Inject component-specific logic via hooks
|
|
50
|
+
* get hooks(): FloatingHooks {
|
|
51
|
+
* return {
|
|
52
|
+
* onBeforeShow: () => !this.disabled,
|
|
53
|
+
* onAfterShow: () => this.lockScroll(),
|
|
54
|
+
* onAfterHide: () => this.unlockScroll(),
|
|
55
|
+
* };
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export const floatingMixin = (Base) => {
|
|
61
|
+
class Floating extends Base {
|
|
62
|
+
constructor() {
|
|
63
|
+
super();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Lifecycle hooks provided by the component.
|
|
67
|
+
* Override this getter to inject component-specific logic
|
|
68
|
+
* into the floating lifecycle without modifying the mixin.
|
|
69
|
+
*
|
|
70
|
+
* @returns FloatingHooks — an object with optional lifecycle callbacks
|
|
71
|
+
*/
|
|
72
|
+
get hooks() {
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Called before the element is shown.
|
|
77
|
+
* Aggregates both the component `hooks` and `floatingOptions` controls.
|
|
78
|
+
* If either returns `false`, the show action is cancelled.
|
|
79
|
+
*
|
|
80
|
+
* @param target - Optional element that triggered the show action
|
|
81
|
+
* @returns `true` if the element can be shown, `false` to cancel
|
|
82
|
+
*/
|
|
83
|
+
onBeforeShow(target) {
|
|
84
|
+
const hookControl = this.hooks.onBeforeShow?.(target) ?? true;
|
|
85
|
+
const propControl = this.floatingOptions?.onBeforeShow?.(target) ?? true;
|
|
86
|
+
return hookControl && propControl;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Called before the element is hidden.
|
|
90
|
+
* Aggregates both the component `hooks` and `floatingOptions` controls.
|
|
91
|
+
* If either returns `false`, the hide action is cancelled.
|
|
92
|
+
*
|
|
93
|
+
* @param target - Optional element the mouse moved to (used for stayOnHover logic)
|
|
94
|
+
* @returns `true` if the element can be hidden, `false` to cancel
|
|
95
|
+
*/
|
|
96
|
+
onBeforeHide(target) {
|
|
97
|
+
const hookControl = this.hooks.onBeforeHide?.(target) ?? true;
|
|
98
|
+
const propControl = this.floatingOptions?.onBeforeHide?.(target) ?? true;
|
|
99
|
+
return hookControl && propControl;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Mounts the floating element into the visible DOM.
|
|
103
|
+
* Override in subclasses to use a different mount strategy
|
|
104
|
+
* (e.g. `showPopover()`, `showModal()`, CSS class toggle).
|
|
105
|
+
*/
|
|
106
|
+
showElement() {
|
|
107
|
+
this.isVisible = true;
|
|
108
|
+
this.hooks.mounted?.(this.floatingContent);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Unmounts the floating element from the visible DOM.
|
|
112
|
+
* Override in subclasses to use a different unmount strategy.
|
|
113
|
+
*/
|
|
114
|
+
hideElement() {
|
|
115
|
+
this.isVisible = false;
|
|
116
|
+
this.hooks.unmounted?.(this.floatingContent);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Shows the floating element if not already visible.
|
|
120
|
+
* Runs the full lifecycle: `onBeforeShow` → `showElement` → `onAfterShow`.
|
|
121
|
+
*
|
|
122
|
+
* @param target - Optional element that triggered the action
|
|
123
|
+
*/
|
|
124
|
+
show(target) {
|
|
125
|
+
if (this.isVisible)
|
|
126
|
+
return;
|
|
127
|
+
if (!this.onBeforeShow(target))
|
|
128
|
+
return;
|
|
129
|
+
this.showElement();
|
|
130
|
+
this.onAfterShow(target);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Hides the floating element if currently visible.
|
|
134
|
+
* Runs the full lifecycle: `onBeforeHide` → `hideElement` → `onAfterHide`.
|
|
135
|
+
*
|
|
136
|
+
* @param target - Optional element the mouse moved to
|
|
137
|
+
*/
|
|
138
|
+
hide(target) {
|
|
139
|
+
if (!this.isVisible)
|
|
140
|
+
return;
|
|
141
|
+
if (!this.onBeforeHide(target))
|
|
142
|
+
return;
|
|
143
|
+
this.hideElement();
|
|
144
|
+
this.onAfterHide(target);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Toggles the floating element visibility.
|
|
148
|
+
*
|
|
149
|
+
* @param target - Optional element that triggered the action
|
|
150
|
+
*/
|
|
151
|
+
toggle(target) {
|
|
152
|
+
this.isVisible ? this.hide(target) : this.show();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Called after the element is shown.
|
|
156
|
+
* Notifies both `hooks` and `floatingOptions` consumers.
|
|
157
|
+
*
|
|
158
|
+
* @param target - Optional element that triggered the action
|
|
159
|
+
*/
|
|
160
|
+
onAfterShow(target) {
|
|
161
|
+
this.hooks.onAfterShow?.(target);
|
|
162
|
+
this.floatingOptions?.onAfterShow?.(target);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Called after the element is hidden.
|
|
166
|
+
* Notifies both `hooks` and `floatingOptions` consumers.
|
|
167
|
+
*
|
|
168
|
+
* @param target - Optional element that triggered the action
|
|
169
|
+
*/
|
|
170
|
+
onAfterHide(target) {
|
|
171
|
+
this.hooks.onAfterHide?.(target);
|
|
172
|
+
this.floatingOptions?.onAfterHide?.(target);
|
|
173
|
+
}
|
|
174
|
+
static get states() {
|
|
175
|
+
return {
|
|
176
|
+
"isVisible": {}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return Floating;
|
|
181
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared base mixin for Form-Associated Custom Elements in Boreal DS.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `name`, `disabled`, and `required` form props
|
|
6
|
+
* - `formDisabledCallback` with universal disabled sync behavior
|
|
7
|
+
*
|
|
8
|
+
* Each component must declare `@AttachInternals() internals!: ElementInternals`
|
|
9
|
+
* directly on its class body — Stencil's compiler requires this decorator to be
|
|
10
|
+
* statically visible on the component class, not inside a mixin factory.
|
|
11
|
+
*
|
|
12
|
+
* Components must also implement `IFormControl<T>` for value registration,
|
|
13
|
+
* reset, state restoration, and 2-way binding event emission.
|
|
14
|
+
*/
|
|
15
|
+
export const formAssociatedMixin = (Base) => {
|
|
16
|
+
class FormAssociated extends Base {
|
|
17
|
+
constructor() {
|
|
18
|
+
/** Disables the control. Synced automatically from a parent `<fieldset>` or `<form>` via `formDisabledCallback`. */
|
|
19
|
+
this.disabled = false;
|
|
20
|
+
/** Marks the control as required for form submission. */
|
|
21
|
+
this.required = false;
|
|
22
|
+
super();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Sync component disabled state with parent form disabled state.
|
|
26
|
+
*/
|
|
27
|
+
formDisabledCallback(disabled) {
|
|
28
|
+
this.disabled = disabled;
|
|
29
|
+
}
|
|
30
|
+
static get properties() {
|
|
31
|
+
return {
|
|
32
|
+
"name": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"mutable": false,
|
|
35
|
+
"complexType": {
|
|
36
|
+
"original": "string",
|
|
37
|
+
"resolved": "string",
|
|
38
|
+
"references": {}
|
|
39
|
+
},
|
|
40
|
+
"required": true,
|
|
41
|
+
"optional": false,
|
|
42
|
+
"docs": {
|
|
43
|
+
"tags": [],
|
|
44
|
+
"text": "Name of the form control, submitted as a key in the form data."
|
|
45
|
+
},
|
|
46
|
+
"getter": false,
|
|
47
|
+
"setter": false,
|
|
48
|
+
"reflect": true,
|
|
49
|
+
"attribute": "name"
|
|
50
|
+
},
|
|
51
|
+
"disabled": {
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"mutable": true,
|
|
54
|
+
"complexType": {
|
|
55
|
+
"original": "boolean",
|
|
56
|
+
"resolved": "boolean",
|
|
57
|
+
"references": {}
|
|
58
|
+
},
|
|
59
|
+
"required": false,
|
|
60
|
+
"optional": false,
|
|
61
|
+
"docs": {
|
|
62
|
+
"tags": [],
|
|
63
|
+
"text": "Disables the control. Synced automatically from a parent `<fieldset>` or `<form>` via `formDisabledCallback`."
|
|
64
|
+
},
|
|
65
|
+
"getter": false,
|
|
66
|
+
"setter": false,
|
|
67
|
+
"reflect": true,
|
|
68
|
+
"attribute": "disabled",
|
|
69
|
+
"defaultValue": "false"
|
|
70
|
+
},
|
|
71
|
+
"required": {
|
|
72
|
+
"type": "boolean",
|
|
73
|
+
"mutable": false,
|
|
74
|
+
"complexType": {
|
|
75
|
+
"original": "boolean",
|
|
76
|
+
"resolved": "boolean",
|
|
77
|
+
"references": {}
|
|
78
|
+
},
|
|
79
|
+
"required": false,
|
|
80
|
+
"optional": false,
|
|
81
|
+
"docs": {
|
|
82
|
+
"tags": [],
|
|
83
|
+
"text": "Marks the control as required for form submission."
|
|
84
|
+
},
|
|
85
|
+
"getter": false,
|
|
86
|
+
"setter": false,
|
|
87
|
+
"reflect": true,
|
|
88
|
+
"attribute": "required",
|
|
89
|
+
"defaultValue": "false"
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return FormAssociated;
|
|
95
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boreal Design System - CSS Reset
|
|
3
|
+
* Minimal reset for consistent cross-browser rendering
|
|
4
|
+
*/
|
|
5
|
+
*,
|
|
6
|
+
*::before,
|
|
7
|
+
*::after {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
* {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
html {
|
|
17
|
+
-webkit-font-smoothing: antialiased;
|
|
18
|
+
-moz-osx-font-smoothing: grayscale;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
body {
|
|
22
|
+
line-height: 1.5;
|
|
23
|
+
-webkit-text-size-adjust: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
img,
|
|
27
|
+
picture,
|
|
28
|
+
video,
|
|
29
|
+
canvas,
|
|
30
|
+
svg {
|
|
31
|
+
display: block;
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
input,
|
|
36
|
+
button,
|
|
37
|
+
textarea,
|
|
38
|
+
select {
|
|
39
|
+
font: inherit;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
p,
|
|
43
|
+
h1,
|
|
44
|
+
h2,
|
|
45
|
+
h3,
|
|
46
|
+
h4,
|
|
47
|
+
h5,
|
|
48
|
+
h6 {
|
|
49
|
+
overflow-wrap: break-word;
|
|
50
|
+
}
|