@raintonic/formaui 0.4.0 → 0.9.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/CHANGELOG.md +80 -35
- package/README.md +22 -26
- package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs +39 -41
- package/fesm2022/raintonic-formaui-cdk-drag-drop.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-cdk-form-field.mjs +207 -3
- package/fesm2022/raintonic-formaui-cdk-form-field.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-cdk-overlay.mjs +19 -1
- package/fesm2022/raintonic-formaui-cdk-overlay.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs +5 -12
- package/fesm2022/raintonic-formaui-cdk-virtual-scroll.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-accordion.mjs +8 -5
- package/fesm2022/raintonic-formaui-components-accordion.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-alert.mjs +16 -2
- package/fesm2022/raintonic-formaui-components-alert.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-autocomplete.mjs +255 -462
- package/fesm2022/raintonic-formaui-components-autocomplete.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-avatar.mjs +34 -59
- package/fesm2022/raintonic-formaui-components-avatar.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-badge.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-badge.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-breadcrumb.mjs +4 -4
- package/fesm2022/raintonic-formaui-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-button-group.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-button-group.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-button.mjs +15 -20
- package/fesm2022/raintonic-formaui-components-button.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-card.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-card.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-checkbox.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-checkbox.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-chip.mjs +97 -0
- package/fesm2022/raintonic-formaui-components-chip.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-data-table.mjs +69 -29
- package/fesm2022/raintonic-formaui-components-data-table.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-date-picker.mjs +223 -144
- package/fesm2022/raintonic-formaui-components-date-picker.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-divider.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-divider.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-drawer.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-drawer.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs +888 -0
- package/fesm2022/raintonic-formaui-components-dropdown-menu.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs +774 -0
- package/fesm2022/raintonic-formaui-components-dual-tier-navigation.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-empty-state.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-empty-state.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-file-upload.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-file-upload.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-form-field.mjs +81 -50
- package/fesm2022/raintonic-formaui-components-form-field.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-icon.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-icon.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-input.mjs +47 -12
- package/fesm2022/raintonic-formaui-components-input.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-list.mjs +4 -4
- package/fesm2022/raintonic-formaui-components-list.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-number-input.mjs +20 -12
- package/fesm2022/raintonic-formaui-components-number-input.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-paginator.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-paginator.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-password-input.mjs +35 -110
- package/fesm2022/raintonic-formaui-components-password-input.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-popover.mjs +3 -2
- package/fesm2022/raintonic-formaui-components-popover.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-progressbar.mjs +3 -2
- package/fesm2022/raintonic-formaui-components-progressbar.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-radio.mjs +5 -6
- package/fesm2022/raintonic-formaui-components-radio.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-select.mjs +257 -412
- package/fesm2022/raintonic-formaui-components-select.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-side-panel.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-side-panel.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs +525 -0
- package/fesm2022/raintonic-formaui-components-sidebar-nav-menu.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-skeleton.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-skeleton.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-slider.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-slider.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-spinner.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-spinner.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-stepper.mjs +50 -45
- package/fesm2022/raintonic-formaui-components-stepper.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-strength-meter.mjs +149 -0
- package/fesm2022/raintonic-formaui-components-strength-meter.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-tab.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-tab.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-time-picker.mjs +194 -154
- package/fesm2022/raintonic-formaui-components-time-picker.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-toggle-group.mjs +302 -0
- package/fesm2022/raintonic-formaui-components-toggle-group.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-toggle.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-toggle.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-toolbar.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-toolbar.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-tooltip.mjs +10 -4
- package/fesm2022/raintonic-formaui-components-tooltip.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-topbar.mjs +60 -0
- package/fesm2022/raintonic-formaui-components-topbar.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-components-tree-select.mjs +59 -69
- package/fesm2022/raintonic-formaui-components-tree-select.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-tree-table.mjs +2 -2
- package/fesm2022/raintonic-formaui-components-tree-table.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-components-tree.mjs +31 -5
- package/fesm2022/raintonic-formaui-components-tree.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-core.mjs +279 -1
- package/fesm2022/raintonic-formaui-core.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-services-breakpoint.mjs +93 -0
- package/fesm2022/raintonic-formaui-services-breakpoint.mjs.map +1 -0
- package/fesm2022/raintonic-formaui-services-dialog.mjs +314 -16
- package/fesm2022/raintonic-formaui-services-dialog.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-services-notification.mjs +93 -29
- package/fesm2022/raintonic-formaui-services-notification.mjs.map +1 -1
- package/fesm2022/raintonic-formaui-services-theme.mjs +46 -196
- package/fesm2022/raintonic-formaui-services-theme.mjs.map +1 -1
- package/fesm2022/raintonic-formaui.mjs +1 -1
- package/fesm2022/raintonic-formaui.mjs.map +1 -1
- package/llms-full.txt +2329 -450
- package/llms.txt +36 -33
- package/package.json +42 -19
- package/styles/fonts/Geist-Bold.woff2 +0 -0
- package/styles/fonts/Geist-Italic.woff2 +0 -0
- package/styles/fonts/Geist-Light.woff2 +0 -0
- package/styles/fonts/Geist-Medium.woff2 +0 -0
- package/styles/fonts/Geist-Regular.woff2 +0 -0
- package/styles/fonts/Geist-SemiBold.woff2 +0 -0
- package/styles/fonts/GeistMono-Regular.woff2 +0 -0
- package/styles/generated/_tokens.scss +906 -0
- package/styles/index.scss +11 -10
- package/styles/partials/_brand.scss +46 -0
- package/styles/partials/_constants.scss +22 -20
- package/styles/partials/_fonts.scss +54 -10
- package/styles/partials/_grid.scss +29 -18
- package/styles/partials/_mixins.scss +69 -27
- package/styles/partials/_motion.scss +28 -33
- package/styles/partials/_theme.scss +28 -255
- package/styles/partials/_type.scss +117 -0
- package/styles/partials/_typography.scss +45 -45
- package/styles/partials/_utilities.scss +198 -98
- package/styles/partials/components/_button.scss +144 -75
- package/styles/partials/components/_dialog.scss +181 -180
- package/styles/partials/components/_overlay.scss +87 -87
- package/styles/partials/themes/_dark.scss +3 -268
- package/styles/partials/themes/_light.scss +4 -268
- package/styles/styles.css +7744 -0
- package/styles/styles.entry.scss +3 -0
- package/styles/utilities.css +4802 -0
- package/styles/utilities.entry.scss +3 -0
- package/types/raintonic-formaui-cdk-drag-drop.d.ts +0 -1
- package/types/raintonic-formaui-cdk-drag-drop.d.ts.map +1 -1
- package/types/raintonic-formaui-cdk-form-field.d.ts +118 -2
- package/types/raintonic-formaui-cdk-form-field.d.ts.map +1 -1
- package/types/raintonic-formaui-cdk-overlay.d.ts +2 -0
- package/types/raintonic-formaui-cdk-overlay.d.ts.map +1 -1
- package/types/raintonic-formaui-cdk-virtual-scroll.d.ts +0 -1
- package/types/raintonic-formaui-cdk-virtual-scroll.d.ts.map +1 -1
- package/types/raintonic-formaui-components-accordion.d.ts +1 -1
- package/types/raintonic-formaui-components-accordion.d.ts.map +1 -1
- package/types/raintonic-formaui-components-alert.d.ts +6 -1
- package/types/raintonic-formaui-components-alert.d.ts.map +1 -1
- package/types/raintonic-formaui-components-autocomplete.d.ts +73 -116
- package/types/raintonic-formaui-components-autocomplete.d.ts.map +1 -1
- package/types/raintonic-formaui-components-avatar.d.ts +13 -31
- package/types/raintonic-formaui-components-avatar.d.ts.map +1 -1
- package/types/raintonic-formaui-components-button.d.ts +4 -10
- package/types/raintonic-formaui-components-button.d.ts.map +1 -1
- package/types/raintonic-formaui-components-chip.d.ts +43 -0
- package/types/raintonic-formaui-components-chip.d.ts.map +1 -0
- package/types/raintonic-formaui-components-data-table.d.ts +48 -11
- package/types/raintonic-formaui-components-data-table.d.ts.map +1 -1
- package/types/raintonic-formaui-components-date-picker.d.ts +59 -23
- package/types/raintonic-formaui-components-date-picker.d.ts.map +1 -1
- package/types/raintonic-formaui-components-dropdown-menu.d.ts +394 -0
- package/types/raintonic-formaui-components-dropdown-menu.d.ts.map +1 -0
- package/types/raintonic-formaui-components-dual-tier-navigation.d.ts +87 -0
- package/types/raintonic-formaui-components-dual-tier-navigation.d.ts.map +1 -0
- package/types/raintonic-formaui-components-form-field.d.ts +51 -21
- package/types/raintonic-formaui-components-form-field.d.ts.map +1 -1
- package/types/raintonic-formaui-components-input.d.ts +20 -11
- package/types/raintonic-formaui-components-input.d.ts.map +1 -1
- package/types/raintonic-formaui-components-number-input.d.ts +5 -3
- package/types/raintonic-formaui-components-number-input.d.ts.map +1 -1
- package/types/raintonic-formaui-components-password-input.d.ts +18 -32
- package/types/raintonic-formaui-components-password-input.d.ts.map +1 -1
- package/types/raintonic-formaui-components-popover.d.ts.map +1 -1
- package/types/raintonic-formaui-components-progressbar.d.ts +1 -1
- package/types/raintonic-formaui-components-progressbar.d.ts.map +1 -1
- package/types/raintonic-formaui-components-radio.d.ts +1 -2
- package/types/raintonic-formaui-components-radio.d.ts.map +1 -1
- package/types/raintonic-formaui-components-select.d.ts +107 -76
- package/types/raintonic-formaui-components-select.d.ts.map +1 -1
- package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts +223 -0
- package/types/raintonic-formaui-components-sidebar-nav-menu.d.ts.map +1 -0
- package/types/raintonic-formaui-components-stepper.d.ts +4 -2
- package/types/raintonic-formaui-components-stepper.d.ts.map +1 -1
- package/types/raintonic-formaui-components-strength-meter.d.ts +78 -0
- package/types/raintonic-formaui-components-strength-meter.d.ts.map +1 -0
- package/types/raintonic-formaui-components-time-picker.d.ts +44 -24
- package/types/raintonic-formaui-components-time-picker.d.ts.map +1 -1
- package/types/raintonic-formaui-components-toggle-group.d.ts +100 -0
- package/types/raintonic-formaui-components-toggle-group.d.ts.map +1 -0
- package/types/raintonic-formaui-components-tooltip.d.ts +2 -1
- package/types/raintonic-formaui-components-tooltip.d.ts.map +1 -1
- package/types/raintonic-formaui-components-topbar.d.ts +48 -0
- package/types/raintonic-formaui-components-topbar.d.ts.map +1 -0
- package/types/raintonic-formaui-components-tree-select.d.ts +25 -9
- package/types/raintonic-formaui-components-tree-select.d.ts.map +1 -1
- package/types/raintonic-formaui-components-tree.d.ts +12 -1
- package/types/raintonic-formaui-components-tree.d.ts.map +1 -1
- package/types/raintonic-formaui-core.d.ts +243 -5
- package/types/raintonic-formaui-core.d.ts.map +1 -1
- package/types/raintonic-formaui-services-breakpoint.d.ts +44 -0
- package/types/raintonic-formaui-services-breakpoint.d.ts.map +1 -0
- package/types/raintonic-formaui-services-dialog.d.ts +141 -2
- package/types/raintonic-formaui-services-dialog.d.ts.map +1 -1
- package/types/raintonic-formaui-services-notification.d.ts +24 -2
- package/types/raintonic-formaui-services-notification.d.ts.map +1 -1
- package/types/raintonic-formaui-services-theme.d.ts +13 -103
- package/types/raintonic-formaui-services-theme.d.ts.map +1 -1
- package/types/raintonic-formaui.d.ts +1 -1
- package/fesm2022/raintonic-formaui-components-big-menu.mjs +0 -86
- package/fesm2022/raintonic-formaui-components-big-menu.mjs.map +0 -1
- package/fesm2022/raintonic-formaui-components-menu.mjs +0 -896
- package/fesm2022/raintonic-formaui-components-menu.mjs.map +0 -1
- package/fesm2022/raintonic-formaui-components-sidebar.mjs +0 -275
- package/fesm2022/raintonic-formaui-components-sidebar.mjs.map +0 -1
- package/fesm2022/raintonic-formaui-components-tag.mjs +0 -95
- package/fesm2022/raintonic-formaui-components-tag.mjs.map +0 -1
- package/styles/_fonts-entry.scss +0 -3
- package/styles/fonts/inter-tight-latin-italic.woff2 +0 -0
- package/styles/fonts/inter-tight-latin.woff2 +0 -0
- package/types/raintonic-formaui-components-big-menu.d.ts +0 -73
- package/types/raintonic-formaui-components-big-menu.d.ts.map +0 -1
- package/types/raintonic-formaui-components-menu.d.ts +0 -403
- package/types/raintonic-formaui-components-menu.d.ts.map +0 -1
- package/types/raintonic-formaui-components-sidebar.d.ts +0 -185
- package/types/raintonic-formaui-components-sidebar.d.ts.map +0 -1
- package/types/raintonic-formaui-components-tag.d.ts +0 -43
- package/types/raintonic-formaui-components-tag.d.ts.map +0 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, DestroyRef, PLATFORM_ID, signal, computed, Injectable } from '@angular/core';
|
|
3
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Soglie in px (mobile-first min-width).
|
|
7
|
+
*
|
|
8
|
+
* Sync con:
|
|
9
|
+
* - tokens/core/layout.json (bp.{xs..2xl})
|
|
10
|
+
* - lib/styles/partials/_constants.scss ($fui-bp-{xs..2xl})
|
|
11
|
+
*
|
|
12
|
+
* Drift detection: vedi consistency test in breakpoint.service.spec.ts.
|
|
13
|
+
*/
|
|
14
|
+
const FUI_BREAKPOINTS = {
|
|
15
|
+
xs: 480,
|
|
16
|
+
sm: 640,
|
|
17
|
+
md: 768,
|
|
18
|
+
lg: 1024,
|
|
19
|
+
xl: 1280,
|
|
20
|
+
'2xl': 1536,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* FuiBreakpointService — accesso signal-based ai breakpoint del PRD.
|
|
24
|
+
*
|
|
25
|
+
* - `matches(bp)`: Signal<boolean> true se viewport ≥ soglia del bp (semantica
|
|
26
|
+
* `@media (min-width: …)`).
|
|
27
|
+
* - SSR-safe: prima dell'attach al browser tutti i signal sono `false`.
|
|
28
|
+
*/
|
|
29
|
+
class FuiBreakpointService {
|
|
30
|
+
_destroyRef = inject(DestroyRef);
|
|
31
|
+
_document = inject(DOCUMENT);
|
|
32
|
+
_platformId = inject(PLATFORM_ID);
|
|
33
|
+
_matches = {
|
|
34
|
+
xs: signal(false),
|
|
35
|
+
sm: signal(false),
|
|
36
|
+
md: signal(false),
|
|
37
|
+
lg: signal(false),
|
|
38
|
+
xl: signal(false),
|
|
39
|
+
'2xl': signal(false),
|
|
40
|
+
};
|
|
41
|
+
// Ordine mobile-first dal più grande al più piccolo per il computed `active`.
|
|
42
|
+
static BP_ORDER_DESC = ['2xl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
|
43
|
+
/**
|
|
44
|
+
* Bp più grande matched mobile-first. `null` se viewport < `xs` (480px) o in SSR.
|
|
45
|
+
*/
|
|
46
|
+
active = computed(() => {
|
|
47
|
+
for (const bp of FuiBreakpointService.BP_ORDER_DESC) {
|
|
48
|
+
if (this._matches[bp]()) {
|
|
49
|
+
return bp;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
54
|
+
constructor() {
|
|
55
|
+
if (!isPlatformBrowser(this._platformId)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const win = this._document.defaultView;
|
|
59
|
+
if (!win) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const bp of Object.keys(FUI_BREAKPOINTS)) {
|
|
63
|
+
const mq = win.matchMedia(`(min-width: ${FUI_BREAKPOINTS[bp].toString()}px)`);
|
|
64
|
+
this._matches[bp].set(mq.matches);
|
|
65
|
+
const handler = (e) => {
|
|
66
|
+
this._matches[bp].set(e.matches);
|
|
67
|
+
};
|
|
68
|
+
mq.addEventListener('change', handler);
|
|
69
|
+
this._destroyRef.onDestroy(() => {
|
|
70
|
+
mq.removeEventListener('change', handler);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Signal true se viewport ≥ soglia del bp. Stesso Signal per chiamate ripetute.
|
|
76
|
+
*/
|
|
77
|
+
matches(bp) {
|
|
78
|
+
return this._matches[bp].asReadonly();
|
|
79
|
+
}
|
|
80
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBreakpointService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
81
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBreakpointService, providedIn: 'root' });
|
|
82
|
+
}
|
|
83
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiBreakpointService, decorators: [{
|
|
84
|
+
type: Injectable,
|
|
85
|
+
args: [{ providedIn: 'root' }]
|
|
86
|
+
}], ctorParameters: () => [] });
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Generated bundle index. Do not edit.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
export { FUI_BREAKPOINTS, FuiBreakpointService };
|
|
93
|
+
//# sourceMappingURL=raintonic-formaui-services-breakpoint.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raintonic-formaui-services-breakpoint.mjs","sources":["../../../lib/services/breakpoint/breakpoint.service.ts","../../../lib/services/breakpoint/raintonic-formaui-services-breakpoint.ts"],"sourcesContent":["import { computed, DestroyRef, inject, Injectable, PLATFORM_ID, signal, Signal, WritableSignal } from '@angular/core';\r\nimport { DOCUMENT, isPlatformBrowser } from '@angular/common';\r\n\r\n/** I 6 breakpoint nominali (mobile-first min-width). */\r\nexport type FuiBreakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\r\n\r\n/**\r\n * Soglie in px (mobile-first min-width).\r\n *\r\n * Sync con:\r\n * - tokens/core/layout.json (bp.{xs..2xl})\r\n * - lib/styles/partials/_constants.scss ($fui-bp-{xs..2xl})\r\n *\r\n * Drift detection: vedi consistency test in breakpoint.service.spec.ts.\r\n */\r\nexport const FUI_BREAKPOINTS: Readonly<Record<FuiBreakpoint, number>> = {\r\n xs: 480,\r\n sm: 640,\r\n md: 768,\r\n lg: 1024,\r\n xl: 1280,\r\n '2xl': 1536,\r\n} as const;\r\n\r\n/**\r\n * FuiBreakpointService — accesso signal-based ai breakpoint del PRD.\r\n *\r\n * - `matches(bp)`: Signal<boolean> true se viewport ≥ soglia del bp (semantica\r\n * `@media (min-width: …)`).\r\n * - SSR-safe: prima dell'attach al browser tutti i signal sono `false`.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class FuiBreakpointService {\r\n private readonly _destroyRef = inject(DestroyRef);\r\n private readonly _document = inject(DOCUMENT);\r\n private readonly _platformId = inject(PLATFORM_ID);\r\n\r\n private readonly _matches: Record<FuiBreakpoint, WritableSignal<boolean>> = {\r\n xs: signal(false),\r\n sm: signal(false),\r\n md: signal(false),\r\n lg: signal(false),\r\n xl: signal(false),\r\n '2xl': signal(false),\r\n };\r\n\r\n // Ordine mobile-first dal più grande al più piccolo per il computed `active`.\r\n private static readonly BP_ORDER_DESC: readonly FuiBreakpoint[] = ['2xl', 'xl', 'lg', 'md', 'sm', 'xs'];\r\n\r\n /**\r\n * Bp più grande matched mobile-first. `null` se viewport < `xs` (480px) o in SSR.\r\n */\r\n readonly active: Signal<FuiBreakpoint | null> = computed(() => {\r\n for (const bp of FuiBreakpointService.BP_ORDER_DESC) {\r\n if (this._matches[bp]()) {\r\n return bp;\r\n }\r\n }\r\n return null;\r\n });\r\n\r\n constructor() {\r\n if (!isPlatformBrowser(this._platformId)) {\r\n return;\r\n }\r\n const win = this._document.defaultView;\r\n if (!win) {\r\n return;\r\n }\r\n for (const bp of Object.keys(FUI_BREAKPOINTS) as FuiBreakpoint[]) {\r\n const mq = win.matchMedia(`(min-width: ${FUI_BREAKPOINTS[bp].toString()}px)`);\r\n this._matches[bp].set(mq.matches);\r\n const handler = (e: MediaQueryListEvent): void => {\r\n this._matches[bp].set(e.matches);\r\n };\r\n mq.addEventListener('change', handler);\r\n this._destroyRef.onDestroy(() => {\r\n mq.removeEventListener('change', handler);\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Signal true se viewport ≥ soglia del bp. Stesso Signal per chiamate ripetute.\r\n */\r\n matches(bp: FuiBreakpoint): Signal<boolean> {\r\n return this._matches[bp].asReadonly();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAMA;;;;;;;;AAQG;AACI,MAAM,eAAe,GAA4C;AACtE,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,KAAK,EAAE,IAAI;;AAGb;;;;;;AAMG;MAEU,oBAAoB,CAAA;AACd,IAAA,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAChC,IAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC5B,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAEjC,IAAA,QAAQ,GAAmD;AAC1E,QAAA,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;AACjB,QAAA,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;AACjB,QAAA,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;AACjB,QAAA,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;AACjB,QAAA,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC;AACjB,QAAA,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;KACrB;;AAGO,IAAA,OAAgB,aAAa,GAA6B,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;AAEvG;;AAEG;AACM,IAAA,MAAM,GAAiC,QAAQ,CAAC,MAAK;AAC5D,QAAA,KAAK,MAAM,EAAE,IAAI,oBAAoB,CAAC,aAAa,EAAE;YACnD,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE;AACvB,gBAAA,OAAO,EAAE;YACX;QACF;AACA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,6EAAC;AAEF,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;YACxC;QACF;AACA,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW;QACtC,IAAI,CAAC,GAAG,EAAE;YACR;QACF;QACA,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAoB,EAAE;AAChE,YAAA,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC,CAAA,YAAA,EAAe,eAAe,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA,GAAA,CAAK,CAAC;AAC7E,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC;AACjC,YAAA,MAAM,OAAO,GAAG,CAAC,CAAsB,KAAU;AAC/C,gBAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AAClC,YAAA,CAAC;AACD,YAAA,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC;AACtC,YAAA,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAK;AAC9B,gBAAA,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC3C,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;AAEG;AACH,IAAA,OAAO,CAAC,EAAiB,EAAA;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE;IACvC;uGAvDW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAApB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,oBAAoB,cADP,MAAM,EAAA,CAAA;;2FACnB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBADhC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC/BlC;;AAEG;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, ElementRef, signal, computed, HostListener, ViewChild, ChangeDetectionStrategy, Component, ViewEncapsulation, EnvironmentInjector, Injector, ApplicationRef, TemplateRef, createComponent, Injectable } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ElementRef, signal, computed, HostListener, ViewChild, ChangeDetectionStrategy, Component, Renderer2, output, ViewEncapsulation, EnvironmentInjector, Injector, ApplicationRef, TemplateRef, createComponent, Injectable } from '@angular/core';
|
|
3
3
|
import { Subject, defer } from 'rxjs';
|
|
4
4
|
import { filter, startWith, map } from 'rxjs/operators';
|
|
5
5
|
import { FuiOverlayService } from '@raintonic/formaui/cdk/overlay';
|
|
@@ -15,6 +15,13 @@ const FUI_DIALOG_DATA = new InjectionToken('FuiDialogData');
|
|
|
15
15
|
* Injection token for the dialog scroll strategy
|
|
16
16
|
*/
|
|
17
17
|
const FUI_DIALOG_DEFAULT_OPTIONS = new InjectionToken('FuiDialogDefaultOptions');
|
|
18
|
+
/** Size presets mapped to CSS values */
|
|
19
|
+
const DRAWER_SIZE_VALUES = {
|
|
20
|
+
sm: '320px',
|
|
21
|
+
md: '480px',
|
|
22
|
+
lg: '640px',
|
|
23
|
+
full: '100%',
|
|
24
|
+
};
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* # FuiDialogRefImpl
|
|
@@ -417,7 +424,7 @@ class FuiDialogContainerComponent {
|
|
|
417
424
|
<ng-content></ng-content>
|
|
418
425
|
</div>
|
|
419
426
|
</div>
|
|
420
|
-
`, isInline: true, styles: [":host{display:block;outline:0}.fui-dialog-container{display:flex;flex-direction:column;box-sizing:border-box;overflow:auto;outline:0;max-height:inherit;border:1px solid var(--fui-border-
|
|
427
|
+
`, isInline: true, styles: [":host{display:block;outline:0}.fui-dialog-container{display:flex;flex-direction:column;box-sizing:border-box;overflow:auto;outline:0;max-height:inherit;border:1px solid var(--fui-border-default);border-radius:var(--fui-radius-md);background:var(--fui-bg-default);box-shadow:var(--fui-dialog-box-shadow, var(--fui-shadow-xl))}.fui-dialog-content{display:contents}.fui-dialog-enter{animation:fui-dialog-enter var(--fui-duration-moderate) var(--fui-ease-out)}.fui-dialog-exit{animation:fui-dialog-exit var(--fui-duration-base) var(--fui-ease-in)}@keyframes fui-dialog-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fui-dialog-exit{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@media(prefers-reduced-motion:reduce){.fui-dialog-enter,.fui-dialog-exit{animation:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
421
428
|
}
|
|
422
429
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDialogContainerComponent, decorators: [{
|
|
423
430
|
type: Component,
|
|
@@ -440,7 +447,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
440
447
|
</div>
|
|
441
448
|
`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
442
449
|
class: 'fui-dialog-container-host',
|
|
443
|
-
}, styles: [":host{display:block;outline:0}.fui-dialog-container{display:flex;flex-direction:column;box-sizing:border-box;overflow:auto;outline:0;max-height:inherit;border:1px solid var(--fui-border-
|
|
450
|
+
}, styles: [":host{display:block;outline:0}.fui-dialog-container{display:flex;flex-direction:column;box-sizing:border-box;overflow:auto;outline:0;max-height:inherit;border:1px solid var(--fui-border-default);border-radius:var(--fui-radius-md);background:var(--fui-bg-default);box-shadow:var(--fui-dialog-box-shadow, var(--fui-shadow-xl))}.fui-dialog-content{display:contents}.fui-dialog-enter{animation:fui-dialog-enter var(--fui-duration-moderate) var(--fui-ease-out)}.fui-dialog-exit{animation:fui-dialog-exit var(--fui-duration-base) var(--fui-ease-in)}@keyframes fui-dialog-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes fui-dialog-exit{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}@media(prefers-reduced-motion:reduce){.fui-dialog-enter,.fui-dialog-exit{animation:none}}\n"] }]
|
|
444
451
|
}], propDecorators: { _dialogContainer: [{
|
|
445
452
|
type: ViewChild,
|
|
446
453
|
args: ['dialogContainer', { static: true }]
|
|
@@ -449,6 +456,146 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
449
456
|
args: ['keydown', ['$event']]
|
|
450
457
|
}] } });
|
|
451
458
|
|
|
459
|
+
/**
|
|
460
|
+
* # FuiDialogDrawerContainerComponent
|
|
461
|
+
*
|
|
462
|
+
* Internal container component used by `FuiDialogService.openAsDrawer()`. Renders
|
|
463
|
+
* the drawer chrome (header, content slot, optional footer) with a position-based
|
|
464
|
+
* slide animation.
|
|
465
|
+
*
|
|
466
|
+
* Unlike the standalone `FuiDrawerComponent` (which manages its own backdrop and
|
|
467
|
+
* fixed positioning), this component delegates backdrop and positioning to the CDK
|
|
468
|
+
* overlay. The container's host element carries position classes and toggles the
|
|
469
|
+
* open class to trigger CSS transitions on the child panel — mirroring the original
|
|
470
|
+
* drawer's animation model.
|
|
471
|
+
*/
|
|
472
|
+
class FuiDialogDrawerContainerComponent {
|
|
473
|
+
_document = inject(DOCUMENT);
|
|
474
|
+
_renderer = inject(Renderer2);
|
|
475
|
+
_elementRef = inject((ElementRef));
|
|
476
|
+
_drawerPanel;
|
|
477
|
+
/** Which edge the drawer slides from */
|
|
478
|
+
position = 'right';
|
|
479
|
+
title = null;
|
|
480
|
+
/** Whether to show the close button in the header */
|
|
481
|
+
showCloseButton = true;
|
|
482
|
+
/** ARIA label */
|
|
483
|
+
ariaLabel = null;
|
|
484
|
+
/** ARIA labelled-by element ID */
|
|
485
|
+
ariaLabelledBy = null;
|
|
486
|
+
/** Emitted when the close button is clicked */
|
|
487
|
+
closed = output();
|
|
488
|
+
/** Element that had focus before the drawer opened (for restoration) */
|
|
489
|
+
_previouslyFocusedElement = null;
|
|
490
|
+
ngAfterViewInit() {
|
|
491
|
+
setTimeout(() => {
|
|
492
|
+
this._renderer.addClass(this._elementRef.nativeElement, 'fui-drawer-service--open');
|
|
493
|
+
});
|
|
494
|
+
this._trapFocus();
|
|
495
|
+
}
|
|
496
|
+
ngOnDestroy() {
|
|
497
|
+
this._restoreFocus();
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Returns the host element (for internal use by DialogService when projecting content).
|
|
501
|
+
*/
|
|
502
|
+
_getHostElement() {
|
|
503
|
+
return this._elementRef.nativeElement;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Appends a DOM element to the drawer's content area (for internal use).
|
|
507
|
+
*/
|
|
508
|
+
_appendToContent(element) {
|
|
509
|
+
const contentArea = this._elementRef.nativeElement.querySelector('.fui-drawer-service-content');
|
|
510
|
+
if (contentArea) {
|
|
511
|
+
this._renderer.appendChild(contentArea, element);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Handles keydown events for focus trap cycling within the drawer.
|
|
516
|
+
* Tab loops from last to first focusable element, Shift+Tab from first to last.
|
|
517
|
+
*/
|
|
518
|
+
_onKeydown(event) {
|
|
519
|
+
if (event.key === 'Tab') {
|
|
520
|
+
const focusableElements = this._getFocusableElements();
|
|
521
|
+
if (focusableElements.length === 0) {
|
|
522
|
+
event.preventDefault();
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const firstFocusable = focusableElements[0];
|
|
526
|
+
const lastFocusable = focusableElements[focusableElements.length - 1];
|
|
527
|
+
const activeElement = this._document.activeElement;
|
|
528
|
+
if (event.shiftKey) {
|
|
529
|
+
if (activeElement === firstFocusable) {
|
|
530
|
+
event.preventDefault();
|
|
531
|
+
lastFocusable.focus();
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
if (activeElement === lastFocusable) {
|
|
536
|
+
event.preventDefault();
|
|
537
|
+
firstFocusable.focus();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Focuses the first tabbable element in the drawer panel.
|
|
544
|
+
*/
|
|
545
|
+
_trapFocus() {
|
|
546
|
+
this._previouslyFocusedElement = this._document.activeElement;
|
|
547
|
+
const focusable = this._getFocusableElements();
|
|
548
|
+
if (focusable.length > 0) {
|
|
549
|
+
focusable[0].focus();
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
this._drawerPanel.nativeElement.focus();
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Restores focus to the element that was focused before the drawer opened.
|
|
557
|
+
*/
|
|
558
|
+
_restoreFocus() {
|
|
559
|
+
if (this._previouslyFocusedElement && typeof this._previouslyFocusedElement.focus === 'function') {
|
|
560
|
+
this._previouslyFocusedElement.focus();
|
|
561
|
+
}
|
|
562
|
+
this._previouslyFocusedElement = null;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Returns all focusable elements currently visible inside the drawer.
|
|
566
|
+
*/
|
|
567
|
+
_getFocusableElements() {
|
|
568
|
+
const selectors = [
|
|
569
|
+
'a[href]',
|
|
570
|
+
'button:not([disabled])',
|
|
571
|
+
'textarea:not([disabled])',
|
|
572
|
+
'input:not([disabled])',
|
|
573
|
+
'select:not([disabled])',
|
|
574
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
575
|
+
'[contenteditable="true"]',
|
|
576
|
+
].join(',');
|
|
577
|
+
return Array.from(this._drawerPanel.nativeElement.querySelectorAll(selectors)).filter((el) => el.getClientRects().length > 0);
|
|
578
|
+
}
|
|
579
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDialogDrawerContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
580
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: FuiDialogDrawerContainerComponent, isStandalone: true, selector: "fui-dialog-drawer-container", outputs: { closed: "closed" }, host: { listeners: { "keydown": "_onKeydown($event)" }, properties: { "class.fui-drawer-service--left": "position === \"left\"", "class.fui-drawer-service--right": "position === \"right\"", "class.fui-drawer-service--top": "position === \"top\"", "class.fui-drawer-service--bottom": "position === \"bottom\"" }, classAttribute: "fui-drawer-service" }, viewQueries: [{ propertyName: "_drawerPanel", first: true, predicate: ["drawerPanel"], descendants: true, static: true }], ngImport: i0, template: "<div\r\n #drawerPanel\r\n class=\"fui-drawer-service-panel\"\r\n [attr.role]=\"'dialog'\"\r\n [attr.aria-modal]=\"true\"\r\n [attr.aria-label]=\"ariaLabel || title || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy\"\r\n tabindex=\"-1\"\r\n>\r\n @if (title || showCloseButton) {\r\n <div class=\"fui-drawer-service-header\">\r\n @if (title) {\r\n <h2 class=\"fui-drawer-service-title\">{{ title }}</h2>\r\n }\r\n @if (showCloseButton) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-drawer-service-close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'Close drawer'\"\r\n >\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"fui-drawer-service-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div class=\"fui-drawer-service-footer\">\r\n <ng-content select=\"[drawerFooter]\"></ng-content>\r\n </div>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-drawer-service{display:block;width:100%;height:100%;outline:0;overflow:hidden}.fui-drawer-service-panel{display:flex;flex-direction:column;width:100%;height:100%;background-color:var(--fui-bg-default);transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-drawer-service--right .fui-drawer-service-panel{border-left:1px solid var(--fui-border-default);box-shadow:-4px 0 24px #0000001a;transform:translate(100%)}.fui-drawer-service--left .fui-drawer-service-panel{border-right:1px solid var(--fui-border-default);box-shadow:4px 0 24px #0000001a;transform:translate(-100%)}.fui-drawer-service--top .fui-drawer-service-panel{border-bottom:1px solid var(--fui-border-default);box-shadow:0 4px 24px #0000001a;transform:translateY(-100%)}.fui-drawer-service--bottom .fui-drawer-service-panel{border-top:1px solid var(--fui-border-default);box-shadow:0 -4px 24px #0000001a;transform:translateY(100%)}.fui-drawer-service--open .fui-drawer-service-panel{transform:translate(0)}.fui-drawer-service-header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-6) var(--fui-spacing-7);border-bottom:1px solid var(--fui-border-default);flex-shrink:0}.fui-drawer-service-title{font-size:var(--fui-text-md);font-weight:var(--fui-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer-service-close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-base) var(--fui-ease-in-out),color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-drawer-service-close:hover{background-color:var(--fui-bg-subtle);color:var(--fui-text-primary)}.fui-drawer-service-close:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-drawer-service-content{flex:1;overflow-y:auto;padding:var(--fui-spacing-7)}.fui-drawer-service-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-4);padding:var(--fui-spacing-6) var(--fui-spacing-7);border-top:1px solid var(--fui-border-default);flex-shrink:0}.fui-drawer-service-footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer-service-panel{transition:none!important}.fui-drawer-service--right .fui-drawer-service-panel,.fui-drawer-service--left .fui-drawer-service-panel,.fui-drawer-service--top .fui-drawer-service-panel,.fui-drawer-service--bottom .fui-drawer-service-panel{transform:translate(0)}.fui-drawer-service-close{transition:none}}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
581
|
+
}
|
|
582
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiDialogDrawerContainerComponent, decorators: [{
|
|
583
|
+
type: Component,
|
|
584
|
+
args: [{ selector: 'fui-dialog-drawer-container', standalone: true, imports: [FuiIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
585
|
+
class: 'fui-drawer-service',
|
|
586
|
+
'[class.fui-drawer-service--left]': 'position === "left"',
|
|
587
|
+
'[class.fui-drawer-service--right]': 'position === "right"',
|
|
588
|
+
'[class.fui-drawer-service--top]': 'position === "top"',
|
|
589
|
+
'[class.fui-drawer-service--bottom]': 'position === "bottom"',
|
|
590
|
+
}, template: "<div\r\n #drawerPanel\r\n class=\"fui-drawer-service-panel\"\r\n [attr.role]=\"'dialog'\"\r\n [attr.aria-modal]=\"true\"\r\n [attr.aria-label]=\"ariaLabel || title || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledBy\"\r\n tabindex=\"-1\"\r\n>\r\n @if (title || showCloseButton) {\r\n <div class=\"fui-drawer-service-header\">\r\n @if (title) {\r\n <h2 class=\"fui-drawer-service-title\">{{ title }}</h2>\r\n }\r\n @if (showCloseButton) {\r\n <button\r\n type=\"button\"\r\n class=\"fui-drawer-service-close\"\r\n (click)=\"closed.emit()\"\r\n [attr.aria-label]=\"'Close drawer'\"\r\n >\r\n <fui-icon name=\"x\" size=\"sm\"></fui-icon>\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"fui-drawer-service-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <div class=\"fui-drawer-service-footer\">\r\n <ng-content select=\"[drawerFooter]\"></ng-content>\r\n </div>\r\n</div>\r\n", styles: ["@keyframes fui-skeleton-pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}@keyframes fui-spin{to{transform:rotate(360deg)}}@keyframes fui-shake{0%,to{transform:translate(0)}10%,30%,50%,70%,90%{transform:translate(-2px)}20%,40%,60%,80%{transform:translate(2px)}}.fui-motion-fade-in{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-motion-fade-out{transition-property:opacity;transition-duration:var(--fui-duration-fast);transition-timing-function:var(--fui-ease-in);transition-delay:0ms}.fui-motion-slide-in-bottom{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-bottom.fui-motion-entering{transform:translateY(1rem)}.fui-motion-slide-in-top{transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:translateY(0)}.fui-motion-slide-in-top.fui-motion-entering{transform:translateY(-1rem)}.fui-motion-scale-in{transition-property:transform,opacity;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms;transform:scale(1);opacity:1}.fui-motion-scale-in.fui-motion-entering{transform:scale(.95);opacity:0}.fui-no-motion{transition:none!important;animation:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}@keyframes fui-pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}@keyframes fui-slide-in{0%{transform:translate(120%)}to{transform:translate(0)}}.fui-slide-in{animation:fui-slide-in var(--fui-duration-base) var(--fui-ease-out)}@keyframes fui-popover-enter{0%{opacity:0;transform:translateY(-14px)}60%{opacity:1}to{opacity:1;transform:translateY(0)}}.fui-drawer-service{display:block;width:100%;height:100%;outline:0;overflow:hidden}.fui-drawer-service-panel{display:flex;flex-direction:column;width:100%;height:100%;background-color:var(--fui-bg-default);transition-property:transform;transition-duration:var(--fui-duration-base);transition-timing-function:var(--fui-ease-out);transition-delay:0ms}.fui-drawer-service--right .fui-drawer-service-panel{border-left:1px solid var(--fui-border-default);box-shadow:-4px 0 24px #0000001a;transform:translate(100%)}.fui-drawer-service--left .fui-drawer-service-panel{border-right:1px solid var(--fui-border-default);box-shadow:4px 0 24px #0000001a;transform:translate(-100%)}.fui-drawer-service--top .fui-drawer-service-panel{border-bottom:1px solid var(--fui-border-default);box-shadow:0 4px 24px #0000001a;transform:translateY(-100%)}.fui-drawer-service--bottom .fui-drawer-service-panel{border-top:1px solid var(--fui-border-default);box-shadow:0 -4px 24px #0000001a;transform:translateY(100%)}.fui-drawer-service--open .fui-drawer-service-panel{transform:translate(0)}.fui-drawer-service-header{display:flex;align-items:center;justify-content:space-between;padding:var(--fui-spacing-6) var(--fui-spacing-7);border-bottom:1px solid var(--fui-border-default);flex-shrink:0}.fui-drawer-service-title{font-size:var(--fui-text-md);font-weight:var(--fui-weight-semibold);color:var(--fui-text-primary);margin:0}.fui-drawer-service-close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;border-radius:var(--fui-radius-sm);color:var(--fui-text-secondary);cursor:pointer;transition:background-color var(--fui-duration-base) var(--fui-ease-in-out),color var(--fui-duration-base) var(--fui-ease-in-out)}.fui-drawer-service-close:hover{background-color:var(--fui-bg-subtle);color:var(--fui-text-primary)}.fui-drawer-service-close:focus-visible{outline:2px solid var(--fui-primary-10)}.fui-drawer-service-content{flex:1;overflow-y:auto;padding:var(--fui-spacing-7)}.fui-drawer-service-footer{display:flex;align-items:center;justify-content:flex-end;gap:var(--fui-spacing-4);padding:var(--fui-spacing-6) var(--fui-spacing-7);border-top:1px solid var(--fui-border-default);flex-shrink:0}.fui-drawer-service-footer:empty{display:none}@media(prefers-reduced-motion:reduce){.fui-drawer-service-panel{transition:none!important}.fui-drawer-service--right .fui-drawer-service-panel,.fui-drawer-service--left .fui-drawer-service-panel,.fui-drawer-service--top .fui-drawer-service-panel,.fui-drawer-service--bottom .fui-drawer-service-panel{transform:translate(0)}.fui-drawer-service-close{transition:none}}\n"] }]
|
|
591
|
+
}], propDecorators: { _drawerPanel: [{
|
|
592
|
+
type: ViewChild,
|
|
593
|
+
args: ['drawerPanel', { static: true }]
|
|
594
|
+
}], closed: [{ type: i0.Output, args: ["closed"] }], _onKeydown: [{
|
|
595
|
+
type: HostListener,
|
|
596
|
+
args: ['keydown', ['$event']]
|
|
597
|
+
}] } });
|
|
598
|
+
|
|
452
599
|
class FuiConfirmDialogComponent {
|
|
453
600
|
data = inject(FUI_DIALOG_DATA);
|
|
454
601
|
dialogRef = inject(FuiDialogRef);
|
|
@@ -484,11 +631,11 @@ class FuiConfirmDialogComponent {
|
|
|
484
631
|
this.dialogRef.close(false);
|
|
485
632
|
}
|
|
486
633
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
487
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: FuiConfirmDialogComponent, isStandalone: true, selector: "fui-confirm-dialog", host: { classAttribute: "fui-confirm-dialog" }, ngImport: i0, template: "<div class=\"fui-confirm-dialog__header\">\r\n <fui-icon class=\"fui-confirm-dialog__icon fui-confirm-dialog__icon--{{ variant }}\" [name]=\"icon()\" size=\"lg\" />\r\n <h2 class=\"fui-confirm-dialog__title\" id=\"confirm-dialog-title\">{{ title }}</h2>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__body\" id=\"confirm-dialog-description\">\r\n <p class=\"fui-confirm-dialog__message\">{{ message }}</p>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__actions\">\r\n <button fuiButton variant=\"tertiary\" (click)=\"onCancel()\">{{ cancelText }}</button>\r\n <button fuiButton [variant]=\"confirmButtonVariant()\" (click)=\"onConfirm()\">{{ confirmText }}</button>\r\n</div>\r\n", styles: [".fui-confirm-dialog{display:flex;flex-direction:column;padding:var(--fui-
|
|
634
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: FuiConfirmDialogComponent, isStandalone: true, selector: "fui-confirm-dialog", host: { classAttribute: "fui-confirm-dialog" }, ngImport: i0, template: "<div class=\"fui-confirm-dialog__header\">\r\n <fui-icon class=\"fui-confirm-dialog__icon fui-confirm-dialog__icon--{{ variant }}\" [name]=\"icon()\" size=\"lg\" />\r\n <h2 class=\"fui-confirm-dialog__title\" id=\"confirm-dialog-title\">{{ title }}</h2>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__body\" id=\"confirm-dialog-description\">\r\n <p class=\"fui-confirm-dialog__message\">{{ message }}</p>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__actions\">\r\n <button fuiButton variant=\"tertiary\" (click)=\"onCancel()\">{{ cancelText }}</button>\r\n <button fuiButton [variant]=\"confirmButtonVariant()\" (click)=\"onConfirm()\">{{ confirmText }}</button>\r\n</div>\r\n", styles: [".fui-confirm-dialog{display:flex;flex-direction:column;padding:var(--fui-spacing-9, 1.5rem)}.fui-confirm-dialog__header{display:flex;align-items:center;gap:var(--fui-spacing-6, .75rem);margin-bottom:var(--fui-spacing-7, 1rem)}.fui-confirm-dialog__icon{flex-shrink:0}.fui-confirm-dialog__icon--info{color:var(--fui-text-info)}.fui-confirm-dialog__icon--warning{color:var(--fui-text-warning)}.fui-confirm-dialog__icon--danger{color:var(--fui-text-error)}.fui-confirm-dialog__title{font-family:var(--fui-font-sans);font-size:var(--fui-text-lg);font-weight:var(--fui-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-confirm-dialog__body{margin-bottom:var(--fui-spacing-9, 1.5rem)}.fui-confirm-dialog__message{font-size:var(--fui-text-base);color:var(--fui-text-secondary);line-height:1.5;margin:0}.fui-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:var(--fui-spacing-4, .5rem)}\n"], dependencies: [{ kind: "component", type: FuiIconComponent, selector: "fui-icon", inputs: ["name", "size", "weight", "color", "ariaLabel", "spin", "pulse"] }, { kind: "directive", type: FuiButtonDirective, selector: "button[fuiButton], a[fuiButton]", inputs: ["variant", "size", "disabled", "fullWidth", "loading", "iconOnly", "aria-label", "type"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
488
635
|
}
|
|
489
636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: FuiConfirmDialogComponent, decorators: [{
|
|
490
637
|
type: Component,
|
|
491
|
-
args: [{ selector: 'fui-confirm-dialog', standalone: true, imports: [FuiIconComponent, FuiButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'fui-confirm-dialog' }, template: "<div class=\"fui-confirm-dialog__header\">\r\n <fui-icon class=\"fui-confirm-dialog__icon fui-confirm-dialog__icon--{{ variant }}\" [name]=\"icon()\" size=\"lg\" />\r\n <h2 class=\"fui-confirm-dialog__title\" id=\"confirm-dialog-title\">{{ title }}</h2>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__body\" id=\"confirm-dialog-description\">\r\n <p class=\"fui-confirm-dialog__message\">{{ message }}</p>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__actions\">\r\n <button fuiButton variant=\"tertiary\" (click)=\"onCancel()\">{{ cancelText }}</button>\r\n <button fuiButton [variant]=\"confirmButtonVariant()\" (click)=\"onConfirm()\">{{ confirmText }}</button>\r\n</div>\r\n", styles: [".fui-confirm-dialog{display:flex;flex-direction:column;padding:var(--fui-
|
|
638
|
+
args: [{ selector: 'fui-confirm-dialog', standalone: true, imports: [FuiIconComponent, FuiButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'fui-confirm-dialog' }, template: "<div class=\"fui-confirm-dialog__header\">\r\n <fui-icon class=\"fui-confirm-dialog__icon fui-confirm-dialog__icon--{{ variant }}\" [name]=\"icon()\" size=\"lg\" />\r\n <h2 class=\"fui-confirm-dialog__title\" id=\"confirm-dialog-title\">{{ title }}</h2>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__body\" id=\"confirm-dialog-description\">\r\n <p class=\"fui-confirm-dialog__message\">{{ message }}</p>\r\n</div>\r\n\r\n<div class=\"fui-confirm-dialog__actions\">\r\n <button fuiButton variant=\"tertiary\" (click)=\"onCancel()\">{{ cancelText }}</button>\r\n <button fuiButton [variant]=\"confirmButtonVariant()\" (click)=\"onConfirm()\">{{ confirmText }}</button>\r\n</div>\r\n", styles: [".fui-confirm-dialog{display:flex;flex-direction:column;padding:var(--fui-spacing-9, 1.5rem)}.fui-confirm-dialog__header{display:flex;align-items:center;gap:var(--fui-spacing-6, .75rem);margin-bottom:var(--fui-spacing-7, 1rem)}.fui-confirm-dialog__icon{flex-shrink:0}.fui-confirm-dialog__icon--info{color:var(--fui-text-info)}.fui-confirm-dialog__icon--warning{color:var(--fui-text-warning)}.fui-confirm-dialog__icon--danger{color:var(--fui-text-error)}.fui-confirm-dialog__title{font-family:var(--fui-font-sans);font-size:var(--fui-text-lg);font-weight:var(--fui-weight-semibold, 600);color:var(--fui-text-primary);margin:0}.fui-confirm-dialog__body{margin-bottom:var(--fui-spacing-9, 1.5rem)}.fui-confirm-dialog__message{font-size:var(--fui-text-base);color:var(--fui-text-secondary);line-height:1.5;margin:0}.fui-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:var(--fui-spacing-4, .5rem)}\n"] }]
|
|
492
639
|
}] });
|
|
493
640
|
|
|
494
641
|
/**
|
|
@@ -692,7 +839,20 @@ class FuiDialogService {
|
|
|
692
839
|
return new FuiDialogRef(overlayRef, config, dialogId);
|
|
693
840
|
}
|
|
694
841
|
_attachComponentContent(container, component, dialogRef, config) {
|
|
695
|
-
|
|
842
|
+
return this._createAndAttachContentComponent(component, dialogRef, config, (el) => {
|
|
843
|
+
const hostElement = container._getHostElement();
|
|
844
|
+
const containerElement = hostElement.querySelector('.fui-dialog-container');
|
|
845
|
+
if (containerElement) {
|
|
846
|
+
containerElement.appendChild(el);
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Shared helper: creates a component with dialog/drawer data and ref providers,
|
|
852
|
+
* attaches it to ApplicationRef for change detection, runs initial CD, and
|
|
853
|
+
* delegates DOM insertion to the provided callback.
|
|
854
|
+
*/
|
|
855
|
+
_createAndAttachContentComponent(component, dialogRef, config, appendTo) {
|
|
696
856
|
const providers = [
|
|
697
857
|
{ provide: FUI_DIALOG_DATA, useValue: config.data },
|
|
698
858
|
{ provide: FuiDialogRef, useValue: dialogRef },
|
|
@@ -701,21 +861,14 @@ class FuiDialogService {
|
|
|
701
861
|
parent: config.injector ?? this._injector,
|
|
702
862
|
providers,
|
|
703
863
|
});
|
|
704
|
-
// Create the component
|
|
705
864
|
const componentRef = createComponent(component, {
|
|
706
865
|
environmentInjector: this._environmentInjector,
|
|
707
866
|
elementInjector: injector,
|
|
708
867
|
});
|
|
709
868
|
// Attach to ApplicationRef to connect it to Angular's change detection tree
|
|
710
|
-
// This is crucial for form controls and event bindings to work properly
|
|
711
869
|
this._appRef.attachView(componentRef.hostView);
|
|
712
|
-
//
|
|
713
|
-
|
|
714
|
-
const containerElement = hostElement.querySelector('.fui-dialog-container');
|
|
715
|
-
if (containerElement) {
|
|
716
|
-
containerElement.appendChild(componentRef.location.nativeElement);
|
|
717
|
-
}
|
|
718
|
-
// Trigger change detection
|
|
870
|
+
// Delegate DOM insertion to caller
|
|
871
|
+
appendTo(componentRef.location.nativeElement);
|
|
719
872
|
componentRef.changeDetectorRef.detectChanges();
|
|
720
873
|
return componentRef;
|
|
721
874
|
}
|
|
@@ -750,6 +903,54 @@ class FuiDialogService {
|
|
|
750
903
|
_getAfterAllClosed() {
|
|
751
904
|
return this._afterAllClosedSubject.asObservable();
|
|
752
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* Opens a component or template as a drawer that slides in from the specified
|
|
908
|
+
* viewport edge. Built on the same overlay infrastructure as `open()`, but
|
|
909
|
+
* anchored to the viewport edge with a slide animation instead of a centered modal.
|
|
910
|
+
*
|
|
911
|
+
* @param componentOrTemplateRef Component type or TemplateRef to display
|
|
912
|
+
* @param config Configuration options for the drawer (position, size, etc.)
|
|
913
|
+
* @returns Reference to the opened drawer (same lifecycle API as a dialog)
|
|
914
|
+
*
|
|
915
|
+
* ## Usage
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const drawerRef = this.dialog.openAsDrawer(MyPanelComponent, {
|
|
918
|
+
* position: 'right',
|
|
919
|
+
* size: 'md',
|
|
920
|
+
* title: 'Settings'
|
|
921
|
+
* });
|
|
922
|
+
* drawerRef.afterClosed().subscribe(result => console.log(result));
|
|
923
|
+
* ```
|
|
924
|
+
*/
|
|
925
|
+
openAsDrawer(componentOrTemplateRef, config) {
|
|
926
|
+
const mergedConfig = this._applyDrawerConfigDefaults(config);
|
|
927
|
+
const overlayRef = this._createDrawerOverlay(mergedConfig);
|
|
928
|
+
const drawerContainer = this._attachDrawerContainer(overlayRef, mergedConfig);
|
|
929
|
+
const dialogRef = this._createDialogRef(overlayRef, drawerContainer, mergedConfig);
|
|
930
|
+
if (componentOrTemplateRef instanceof TemplateRef) {
|
|
931
|
+
this._attachTemplateContent(drawerContainer, componentOrTemplateRef, dialogRef);
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
const componentRef = this._attachDrawerComponentContent(drawerContainer, componentOrTemplateRef, dialogRef, mergedConfig);
|
|
935
|
+
dialogRef.componentInstance = componentRef.instance;
|
|
936
|
+
}
|
|
937
|
+
// Listen for drawer close button click
|
|
938
|
+
const subscription = drawerContainer.closed.subscribe(() => {
|
|
939
|
+
dialogRef.close();
|
|
940
|
+
subscription.unsubscribe();
|
|
941
|
+
});
|
|
942
|
+
// Track open dialogs
|
|
943
|
+
this._openDialogs.push(dialogRef);
|
|
944
|
+
dialogRef.afterClosed.subscribe(() => {
|
|
945
|
+
this._removeOpenDialog(dialogRef);
|
|
946
|
+
});
|
|
947
|
+
// Notify opened
|
|
948
|
+
requestAnimationFrame(() => {
|
|
949
|
+
dialogRef._notifyOpened();
|
|
950
|
+
this._afterOpenedSubject.next(dialogRef);
|
|
951
|
+
});
|
|
952
|
+
return dialogRef;
|
|
953
|
+
}
|
|
753
954
|
/**
|
|
754
955
|
* Opens a confirmation dialog and returns an Observable<boolean>.
|
|
755
956
|
* Resolves to `true` when confirmed, `false` when cancelled, ESC, or backdrop click.
|
|
@@ -766,6 +967,103 @@ class FuiDialogService {
|
|
|
766
967
|
});
|
|
767
968
|
return dialogRef.afterClosed.pipe(map((result) => result === true));
|
|
768
969
|
}
|
|
970
|
+
// ── Drawer-specific helpers ──
|
|
971
|
+
_createDrawerOverlay(config) {
|
|
972
|
+
const overlayConfig = this._getDrawerOverlayConfig(config);
|
|
973
|
+
return this._overlayService.create(overlayConfig);
|
|
974
|
+
}
|
|
975
|
+
_getDrawerOverlayConfig(config) {
|
|
976
|
+
const position = config.position ?? 'right';
|
|
977
|
+
const sizeValue = this._resolveDrawerSize(config.size);
|
|
978
|
+
const isHorizontal = position === 'left' || position === 'right';
|
|
979
|
+
const positionStrategy = this._overlayService.position().global();
|
|
980
|
+
// Anchor to viewport edge
|
|
981
|
+
switch (position) {
|
|
982
|
+
case 'left':
|
|
983
|
+
positionStrategy.left('0').top('0');
|
|
984
|
+
break;
|
|
985
|
+
case 'right':
|
|
986
|
+
positionStrategy.right('0').top('0');
|
|
987
|
+
break;
|
|
988
|
+
case 'top':
|
|
989
|
+
positionStrategy.top('0').left('0');
|
|
990
|
+
break;
|
|
991
|
+
case 'bottom':
|
|
992
|
+
positionStrategy.bottom('0').left('0');
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
// Set the drawer dimension (width for left/right, height for top/bottom)
|
|
996
|
+
if (isHorizontal) {
|
|
997
|
+
positionStrategy.width(sizeValue);
|
|
998
|
+
positionStrategy.height('100%');
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
positionStrategy.height(sizeValue);
|
|
1002
|
+
positionStrategy.width('100%');
|
|
1003
|
+
}
|
|
1004
|
+
return {
|
|
1005
|
+
positionStrategy,
|
|
1006
|
+
scrollStrategy: this._overlayService.scrollStrategies.block(),
|
|
1007
|
+
hasBackdrop: config.hasBackdrop ?? true,
|
|
1008
|
+
backdropClass: this._getDrawerBackdropClass(config),
|
|
1009
|
+
backdropClickBehavior: config.disableClose ? 'ignore' : 'close',
|
|
1010
|
+
panelClass: this._getDrawerPanelClass(config),
|
|
1011
|
+
direction: config.direction,
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
_attachDrawerContainer(overlayRef, config) {
|
|
1015
|
+
const containerRef = createComponent(FuiDialogDrawerContainerComponent, {
|
|
1016
|
+
environmentInjector: this._environmentInjector,
|
|
1017
|
+
});
|
|
1018
|
+
const instance = containerRef.instance;
|
|
1019
|
+
instance.position = config.position ?? 'right';
|
|
1020
|
+
instance.title = config.title ?? null;
|
|
1021
|
+
instance.showCloseButton = config.showCloseButton ?? true;
|
|
1022
|
+
instance.ariaLabel = config.ariaLabel ?? null;
|
|
1023
|
+
instance.ariaLabelledBy = config.ariaLabelledBy ?? null;
|
|
1024
|
+
containerRef.changeDetectorRef.detectChanges();
|
|
1025
|
+
overlayRef.attach(containerRef);
|
|
1026
|
+
return instance;
|
|
1027
|
+
}
|
|
1028
|
+
_attachDrawerComponentContent(container, component, dialogRef, config) {
|
|
1029
|
+
return this._createAndAttachContentComponent(component, dialogRef, config, (el) => { container._appendToContent(el); });
|
|
1030
|
+
}
|
|
1031
|
+
_resolveDrawerSize(size) {
|
|
1032
|
+
if (!size) {
|
|
1033
|
+
return DRAWER_SIZE_VALUES.md;
|
|
1034
|
+
}
|
|
1035
|
+
return DRAWER_SIZE_VALUES[size] ?? size;
|
|
1036
|
+
}
|
|
1037
|
+
_getDrawerBackdropClass(config) {
|
|
1038
|
+
const baseClass = 'fui-drawer-service-backdrop';
|
|
1039
|
+
const customClasses = config.backdropClass
|
|
1040
|
+
? Array.isArray(config.backdropClass)
|
|
1041
|
+
? config.backdropClass
|
|
1042
|
+
: [config.backdropClass]
|
|
1043
|
+
: [];
|
|
1044
|
+
return [baseClass, ...customClasses];
|
|
1045
|
+
}
|
|
1046
|
+
_getDrawerPanelClass(config) {
|
|
1047
|
+
const baseClass = 'fui-drawer-service-panel-container';
|
|
1048
|
+
const customClasses = config.panelClass
|
|
1049
|
+
? Array.isArray(config.panelClass)
|
|
1050
|
+
? config.panelClass
|
|
1051
|
+
: [config.panelClass]
|
|
1052
|
+
: [];
|
|
1053
|
+
return [baseClass, ...customClasses];
|
|
1054
|
+
}
|
|
1055
|
+
_applyDrawerConfigDefaults(config) {
|
|
1056
|
+
return {
|
|
1057
|
+
position: 'right',
|
|
1058
|
+
size: 'md',
|
|
1059
|
+
showCloseButton: true,
|
|
1060
|
+
hasBackdrop: true,
|
|
1061
|
+
disableClose: false,
|
|
1062
|
+
restoreFocus: true,
|
|
1063
|
+
...config,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
// ── End drawer-specific helpers ──
|
|
769
1067
|
_applyConfigDefaults(config) {
|
|
770
1068
|
return {
|
|
771
1069
|
role: 'dialog',
|
|
@@ -794,5 +1092,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
794
1092
|
* Generated bundle index. Do not edit.
|
|
795
1093
|
*/
|
|
796
1094
|
|
|
797
|
-
export { FUI_DIALOG_DATA, FUI_DIALOG_DEFAULT_OPTIONS, FuiConfirmDialogComponent, FuiDialogContainerComponent, FuiDialogRef, FuiDialogService };
|
|
1095
|
+
export { DRAWER_SIZE_VALUES, FUI_DIALOG_DATA, FUI_DIALOG_DEFAULT_OPTIONS, FuiConfirmDialogComponent, FuiDialogContainerComponent, FuiDialogDrawerContainerComponent, FuiDialogRef, FuiDialogService };
|
|
798
1096
|
//# sourceMappingURL=raintonic-formaui-services-dialog.mjs.map
|