@cdevhub/ngx-tw 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -15
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog-dialog-renderer-DoIhoV3d.mjs +198 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-dialog-renderer-DoIhoV3d.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +199 -220
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +18 -3
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs +256 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +197 -278
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs +616 -0
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +556 -945
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
- package/index.json +1 -1
- package/package.json +63 -2
- package/theme/_base.css +13 -0
- package/theme/_dark.css +110 -36
- package/theme/_high-contrast-dark.css +367 -0
- package/theme/_high-contrast.css +13 -2
- package/theme/_light.css +276 -0
- package/theme/_semantic.css +47 -12
- package/theme/_typography.css +17 -0
- package/theme/index.css +86 -7
- package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
- package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
- package/types/cdevhub-ngx-tw-button.d.ts +1 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
- package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
- package/types/cdevhub-ngx-tw-card.d.ts +11 -3
- package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
- package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
- package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
- package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
- package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
- package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
- package/types/cdevhub-ngx-tw-core.d.ts +152 -21
- package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
- package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
- package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +89 -19
- package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
- package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
- package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
- package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
- package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
- package/types/cdevhub-ngx-tw-input.d.ts +5 -8
- package/types/cdevhub-ngx-tw-item.d.ts +2 -0
- package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
- package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
- package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
- package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
- package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
- package/types/cdevhub-ngx-tw-select.d.ts +104 -33
- package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +96 -21
- package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
- package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
- package/types/cdevhub-ngx-tw-split.d.ts +32 -2
- package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
- package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
- package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
- package/types/cdevhub-ngx-tw-table.d.ts +53 -10
- package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
- package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
- package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
- package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
- package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
- package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
- package/types/cdevhub-ngx-tw-toast.d.ts +61 -12
- package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
- package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
- package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
- package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { CdkDialogContainer, Dialog, DialogConfig } from '@angular/cdk/dialog';
|
|
2
|
+
import { createBlockScrollStrategy, createNoopScrollStrategy, createRepositionScrollStrategy, createCloseScrollStrategy, createGlobalPositionStrategy } from '@angular/cdk/overlay';
|
|
3
|
+
import { SheetRef, TW_SHEET_DATA, SheetConfig } from './cdevhub-ngx-tw-sheet.mjs';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { inject, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
6
|
+
import { CdkPortalOutlet } from '@angular/cdk/portal';
|
|
7
|
+
import { OverlayContainerCoordinator, mergeOverlayPanelClass, coerceOverlayDuration } from '@cdevhub/ngx-tw/core';
|
|
8
|
+
import { tv } from 'tailwind-variants';
|
|
9
|
+
|
|
10
|
+
// Sheet uses a `data-[state]` + `data-[side]` driven CSS transition rather than
|
|
11
|
+
// the project's `animate.enter`/`animate.leave` keyframes. Same rationale as
|
|
12
|
+
// the dialog container (see `dialog-container.ts`):
|
|
13
|
+
// 1. The ref owns the open/close lifecycle (state signal, observables) and
|
|
14
|
+
// needs runtime-configurable enter/exit durations per `Sheet.open()` call
|
|
15
|
+
// — `animate.enter` only accepts a static class name.
|
|
16
|
+
// 2. The transform direction depends on `side`, and encoding four pairs of
|
|
17
|
+
// keyframe classes (slide-in/out × 4 sides) is noisier than four
|
|
18
|
+
// `data-[side=…]` selectors on a single transition rule.
|
|
19
|
+
// All other library overlays (popover, menu, tooltip) use animate.enter/leave;
|
|
20
|
+
// this divergence is intentional and isolated to the sheet container.
|
|
21
|
+
const sheetContainerVariants = tv({
|
|
22
|
+
slots: {
|
|
23
|
+
host: 'fixed flex flex-col outline-none bg-surface-raised text-fg shadow-md overflow-hidden transition-[transform,opacity] ease-out motion-reduce:transition-none opacity-0 data-[state=open]:opacity-100',
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
side: {
|
|
27
|
+
right: {
|
|
28
|
+
host: 'h-screen right-0 top-0 border-l border-border data-[state=opening]:translate-x-full data-[state=closing]:translate-x-full data-[state=open]:translate-x-0',
|
|
29
|
+
},
|
|
30
|
+
left: {
|
|
31
|
+
host: 'h-screen left-0 top-0 border-r border-border data-[state=opening]:-translate-x-full data-[state=closing]:-translate-x-full data-[state=open]:translate-x-0',
|
|
32
|
+
},
|
|
33
|
+
top: {
|
|
34
|
+
host: 'w-screen left-0 top-0 border-b border-border data-[state=opening]:-translate-y-full data-[state=closing]:-translate-y-full data-[state=open]:translate-y-0',
|
|
35
|
+
},
|
|
36
|
+
bottom: {
|
|
37
|
+
host: 'w-screen left-0 bottom-0 border-t border-border data-[state=opening]:translate-y-full data-[state=closing]:translate-y-full data-[state=open]:translate-y-0',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
size: {
|
|
41
|
+
xs: { host: '' },
|
|
42
|
+
sm: { host: '' },
|
|
43
|
+
md: { host: '' },
|
|
44
|
+
lg: { host: '' },
|
|
45
|
+
xl: { host: '' },
|
|
46
|
+
full: { host: '' },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
// Sheets are axis-aware: `size` controls width on horizontal sides and
|
|
50
|
+
// height on vertical sides. Encoded as compound variants so a single
|
|
51
|
+
// {side, size} pair resolves to one set of utility classes.
|
|
52
|
+
compoundVariants: [
|
|
53
|
+
// ── Right-anchored ─────────────────────────────────────────────
|
|
54
|
+
{ side: 'right', size: 'xs', class: { host: 'w-full max-w-xs' } },
|
|
55
|
+
{ side: 'right', size: 'sm', class: { host: 'w-full max-w-sm' } },
|
|
56
|
+
{ side: 'right', size: 'md', class: { host: 'w-full max-w-md' } },
|
|
57
|
+
{ side: 'right', size: 'lg', class: { host: 'w-full max-w-xl' } },
|
|
58
|
+
{ side: 'right', size: 'xl', class: { host: 'w-full max-w-2xl' } },
|
|
59
|
+
{ side: 'right', size: 'full', class: { host: 'w-screen max-w-none' } },
|
|
60
|
+
// ── Left-anchored ──────────────────────────────────────────────
|
|
61
|
+
{ side: 'left', size: 'xs', class: { host: 'w-full max-w-xs' } },
|
|
62
|
+
{ side: 'left', size: 'sm', class: { host: 'w-full max-w-sm' } },
|
|
63
|
+
{ side: 'left', size: 'md', class: { host: 'w-full max-w-md' } },
|
|
64
|
+
{ side: 'left', size: 'lg', class: { host: 'w-full max-w-xl' } },
|
|
65
|
+
{ side: 'left', size: 'xl', class: { host: 'w-full max-w-2xl' } },
|
|
66
|
+
{ side: 'left', size: 'full', class: { host: 'w-screen max-w-none' } },
|
|
67
|
+
// ── Top-anchored ───────────────────────────────────────────────
|
|
68
|
+
{ side: 'top', size: 'xs', class: { host: 'h-[20vh]' } },
|
|
69
|
+
{ side: 'top', size: 'sm', class: { host: 'h-[33vh]' } },
|
|
70
|
+
{ side: 'top', size: 'md', class: { host: 'h-[50vh]' } },
|
|
71
|
+
{ side: 'top', size: 'lg', class: { host: 'h-[66vh]' } },
|
|
72
|
+
{ side: 'top', size: 'xl', class: { host: 'h-[80vh]' } },
|
|
73
|
+
{ side: 'top', size: 'full', class: { host: 'h-screen' } },
|
|
74
|
+
// ── Bottom-anchored ────────────────────────────────────────────
|
|
75
|
+
{ side: 'bottom', size: 'xs', class: { host: 'h-[20vh]' } },
|
|
76
|
+
{ side: 'bottom', size: 'sm', class: { host: 'h-[33vh]' } },
|
|
77
|
+
{ side: 'bottom', size: 'md', class: { host: 'h-[50vh]' } },
|
|
78
|
+
{ side: 'bottom', size: 'lg', class: { host: 'h-[66vh]' } },
|
|
79
|
+
{ side: 'bottom', size: 'xl', class: { host: 'h-[80vh]' } },
|
|
80
|
+
{ side: 'bottom', size: 'full', class: { host: 'h-screen' } },
|
|
81
|
+
],
|
|
82
|
+
defaultVariants: { side: 'right', size: 'md' },
|
|
83
|
+
}, { twMerge: true });
|
|
84
|
+
/**
|
|
85
|
+
* Sheet container rendered inside the CDK overlay. Wraps the user-provided
|
|
86
|
+
* content in a Tailwind-styled, edge-anchored surface and coordinates slide
|
|
87
|
+
* enter/exit transitions with {@link SheetRef}.
|
|
88
|
+
*
|
|
89
|
+
* The animation state machine, `aria-describedby` queue, and panel-class
|
|
90
|
+
* merge are shared with `DialogContainer` via {@link OverlayContainerCoordinator}
|
|
91
|
+
* (component-scoped — see `providers: [OverlayContainerCoordinator]`).
|
|
92
|
+
*
|
|
93
|
+
* @docs-private
|
|
94
|
+
*/
|
|
95
|
+
class SheetContainer extends CdkDialogContainer {
|
|
96
|
+
coordinator = inject(OverlayContainerCoordinator);
|
|
97
|
+
/** Lifecycle state of the sheet's enter/exit animation. */
|
|
98
|
+
state = this.coordinator.state;
|
|
99
|
+
/** Emits whenever the animation state transitions. */
|
|
100
|
+
animationStateChanged = this.coordinator.animationStateChanged;
|
|
101
|
+
/** Resolved enter-animation duration in ms. */
|
|
102
|
+
enterAnimationDuration;
|
|
103
|
+
/** Resolved exit-animation duration in ms. */
|
|
104
|
+
exitAnimationDuration;
|
|
105
|
+
sideAttr = computed(() => this._config.side ?? 'right', /* @ts-ignore */
|
|
106
|
+
...(ngDevMode ? [{ debugName: "sideAttr" }] : /* istanbul ignore next */ []));
|
|
107
|
+
variants = computed(() => {
|
|
108
|
+
const side = this._config.side ?? 'right';
|
|
109
|
+
const size = this._config.size ?? 'md';
|
|
110
|
+
return sheetContainerVariants({ side, size });
|
|
111
|
+
}, /* @ts-ignore */
|
|
112
|
+
...(ngDevMode ? [{ debugName: "variants" }] : /* istanbul ignore next */ []));
|
|
113
|
+
hostClasses = computed(() => mergeOverlayPanelClass(this.variants().host(), this._config.panelClass), /* @ts-ignore */
|
|
114
|
+
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
115
|
+
ariaDescribedByAttr = computed(() => this._config.ariaDescribedBy ||
|
|
116
|
+
this.coordinator.describedByIds()[0] ||
|
|
117
|
+
null, /* @ts-ignore */
|
|
118
|
+
...(ngDevMode ? [{ debugName: "ariaDescribedByAttr" }] : /* istanbul ignore next */ []));
|
|
119
|
+
transitionDuration = this.coordinator.transitionDuration;
|
|
120
|
+
constructor() {
|
|
121
|
+
super();
|
|
122
|
+
this.enterAnimationDuration = coerceOverlayDuration(this._config.enterAnimationDuration, 200);
|
|
123
|
+
this.exitAnimationDuration = coerceOverlayDuration(this._config.exitAnimationDuration, 160);
|
|
124
|
+
this.coordinator.setDurations(this.enterAnimationDuration, this.exitAnimationDuration);
|
|
125
|
+
}
|
|
126
|
+
_contentAttached() {
|
|
127
|
+
super._contentAttached();
|
|
128
|
+
this.coordinator.startEnterAnimation();
|
|
129
|
+
}
|
|
130
|
+
/** Triggered by the sheet ref to play the exit transition before disposing the overlay. */
|
|
131
|
+
_startExitAnimation() {
|
|
132
|
+
this.coordinator.startExitAnimation();
|
|
133
|
+
}
|
|
134
|
+
/** Registers a description id for the container's `aria-describedby`. */
|
|
135
|
+
_addAriaDescribedBy(id) {
|
|
136
|
+
this.coordinator.addAriaDescribedBy(id);
|
|
137
|
+
}
|
|
138
|
+
/** Removes a previously registered description id. */
|
|
139
|
+
_removeAriaDescribedBy(id) {
|
|
140
|
+
this.coordinator.removeAriaDescribedBy(id);
|
|
141
|
+
}
|
|
142
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: SheetContainer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
143
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.7", type: SheetContainer, isStandalone: true, selector: "tw-sheet-container", host: { attributes: { "tabindex": "-1" }, properties: { "attr.id": "_config.id || null", "attr.role": "_config.role", "attr.aria-modal": "_config.ariaModal", "attr.aria-labelledby": "_config.ariaLabel ? null : _ariaLabelledByQueue[0]", "attr.aria-label": "_config.ariaLabel", "attr.aria-describedby": "ariaDescribedByAttr()", "attr.data-state": "state()", "attr.data-side": "sideAttr()", "class": "hostClasses()", "style.transition-duration.ms": "transitionDuration()" } }, providers: [OverlayContainerCoordinator], usesInheritance: true, ngImport: i0, template: '<ng-template cdkPortalOutlet />', isInline: true, dependencies: [{ kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
144
|
+
}
|
|
145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: SheetContainer, decorators: [{
|
|
146
|
+
type: Component,
|
|
147
|
+
args: [{
|
|
148
|
+
selector: 'tw-sheet-container',
|
|
149
|
+
template: '<ng-template cdkPortalOutlet />',
|
|
150
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
151
|
+
encapsulation: ViewEncapsulation.None,
|
|
152
|
+
imports: [CdkPortalOutlet],
|
|
153
|
+
providers: [OverlayContainerCoordinator],
|
|
154
|
+
host: {
|
|
155
|
+
tabindex: '-1',
|
|
156
|
+
'[attr.id]': '_config.id || null',
|
|
157
|
+
'[attr.role]': '_config.role',
|
|
158
|
+
'[attr.aria-modal]': '_config.ariaModal',
|
|
159
|
+
'[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledByQueue[0]',
|
|
160
|
+
'[attr.aria-label]': '_config.ariaLabel',
|
|
161
|
+
'[attr.aria-describedby]': 'ariaDescribedByAttr()',
|
|
162
|
+
'[attr.data-state]': 'state()',
|
|
163
|
+
'[attr.data-side]': 'sideAttr()',
|
|
164
|
+
'[class]': 'hostClasses()',
|
|
165
|
+
'[style.transition-duration.ms]': 'transitionDuration()',
|
|
166
|
+
},
|
|
167
|
+
}]
|
|
168
|
+
}], ctorParameters: () => [] });
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Rendering half of the sheet feature: the only module that pulls in
|
|
172
|
+
* `@angular/cdk/dialog`, the overlay position/scroll strategies, and the
|
|
173
|
+
* Tailwind `SheetContainer`. Reached exclusively through a dynamic `import()`
|
|
174
|
+
* in {@link Sheet}, which keeps that graph out of a consumer's initial bundle.
|
|
175
|
+
* Nothing here may be imported as a value from `sheet.ts`.
|
|
176
|
+
*
|
|
177
|
+
* @docs-private
|
|
178
|
+
*/
|
|
179
|
+
function openRenderedSheet(injector, content, merged, sheetRef) {
|
|
180
|
+
// `Dialog` is `providedIn: 'root'`, so resolving it here — rather than
|
|
181
|
+
// injecting it into the service — keeps the CDK symbol in this lazy chunk.
|
|
182
|
+
const cdkDialog = injector.get(Dialog);
|
|
183
|
+
const cdkRef = cdkDialog.open(content, {
|
|
184
|
+
id: merged.id,
|
|
185
|
+
role: merged.role,
|
|
186
|
+
data: merged.data,
|
|
187
|
+
panelClass: merged.panelClass,
|
|
188
|
+
backdropClass: merged.backdropClass || 'tw-sheet-backdrop',
|
|
189
|
+
hasBackdrop: merged.hasBackdrop,
|
|
190
|
+
// Sheet sizing happens on the container element (axis-aware width/height
|
|
191
|
+
// utilities). The overlay pane itself is the full-edge bounding box.
|
|
192
|
+
direction: merged.direction,
|
|
193
|
+
ariaDescribedBy: merged.ariaDescribedBy,
|
|
194
|
+
ariaLabelledBy: merged.ariaLabelledBy,
|
|
195
|
+
ariaLabel: merged.ariaLabel,
|
|
196
|
+
ariaModal: merged.ariaModal,
|
|
197
|
+
autoFocus: merged.autoFocus,
|
|
198
|
+
restoreFocus: merged.restoreFocus,
|
|
199
|
+
scrollStrategy: merged.scrollStrategy ?? resolveScrollStrategy(injector, merged.scrollBehavior),
|
|
200
|
+
positionStrategy: merged.positionStrategy ?? resolvePositionStrategy(injector, merged.side ?? 'right'),
|
|
201
|
+
closeOnNavigation: merged.closeOnNavigation,
|
|
202
|
+
viewContainerRef: merged.viewContainerRef,
|
|
203
|
+
injector: merged.injector,
|
|
204
|
+
// We handle close/Escape/backdrop ourselves so we can run the exit slide animation.
|
|
205
|
+
disableClose: true,
|
|
206
|
+
closeOnOverlayDetachments: false,
|
|
207
|
+
container: {
|
|
208
|
+
type: SheetContainer,
|
|
209
|
+
providers: () => [
|
|
210
|
+
{ provide: SheetConfig, useValue: merged },
|
|
211
|
+
{ provide: DialogConfig, useValue: merged },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
providers: (cdkRef, _cdkConfig, container) => {
|
|
215
|
+
sheetRef._attach(cdkRef, container);
|
|
216
|
+
const providers = [
|
|
217
|
+
{ provide: SheetRef, useValue: sheetRef },
|
|
218
|
+
{ provide: TW_SHEET_DATA, useValue: merged.data ?? null },
|
|
219
|
+
];
|
|
220
|
+
if (Array.isArray(merged.providers))
|
|
221
|
+
providers.push(...merged.providers);
|
|
222
|
+
return providers;
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
sheetRef._setComponent(cdkRef.componentInstance, cdkRef.componentRef);
|
|
226
|
+
}
|
|
227
|
+
function resolveScrollStrategy(injector, strategy) {
|
|
228
|
+
switch (strategy) {
|
|
229
|
+
case 'close':
|
|
230
|
+
return createCloseScrollStrategy(injector);
|
|
231
|
+
case 'reposition':
|
|
232
|
+
return createRepositionScrollStrategy(injector);
|
|
233
|
+
case 'noop':
|
|
234
|
+
return createNoopScrollStrategy();
|
|
235
|
+
case 'block':
|
|
236
|
+
default:
|
|
237
|
+
return createBlockScrollStrategy(injector);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function resolvePositionStrategy(injector, side) {
|
|
241
|
+
const strategy = createGlobalPositionStrategy(injector);
|
|
242
|
+
switch (side) {
|
|
243
|
+
case 'left':
|
|
244
|
+
return strategy.top('0').left('0').bottom('0');
|
|
245
|
+
case 'top':
|
|
246
|
+
return strategy.top('0').left('0').right('0');
|
|
247
|
+
case 'bottom':
|
|
248
|
+
return strategy.bottom('0').left('0').right('0');
|
|
249
|
+
case 'right':
|
|
250
|
+
default:
|
|
251
|
+
return strategy.top('0').right('0').bottom('0');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export { openRenderedSheet };
|
|
256
|
+
//# sourceMappingURL=cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs","sources":["../../../projects/ngx-tw/sheet/sheet-container.ts","../../../projects/ngx-tw/sheet/sheet-renderer.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n type EventEmitter,\n inject,\n type Signal,\n ViewEncapsulation,\n computed,\n} from '@angular/core';\nimport { CdkDialogContainer } from '@angular/cdk/dialog';\nimport { CdkPortalOutlet } from '@angular/cdk/portal';\nimport {\n coerceOverlayDuration,\n mergeOverlayPanelClass,\n OverlayContainerCoordinator,\n type OverlayContainerAnimationEvent,\n type OverlayContainerState,\n} from '@cdevhub/ngx-tw/core';\nimport { tv } from 'tailwind-variants';\nimport { type SheetConfig } from './sheet-config';\n\n/** Lifecycle states a sheet passes through. */\nexport type SheetState = OverlayContainerState;\n\n/** Event emitted when the sheet's animation state transitions. */\nexport type SheetAnimationEvent = OverlayContainerAnimationEvent;\n\n// Sheet uses a `data-[state]` + `data-[side]` driven CSS transition rather than\n// the project's `animate.enter`/`animate.leave` keyframes. Same rationale as\n// the dialog container (see `dialog-container.ts`):\n// 1. The ref owns the open/close lifecycle (state signal, observables) and\n// needs runtime-configurable enter/exit durations per `Sheet.open()` call\n// — `animate.enter` only accepts a static class name.\n// 2. The transform direction depends on `side`, and encoding four pairs of\n// keyframe classes (slide-in/out × 4 sides) is noisier than four\n// `data-[side=…]` selectors on a single transition rule.\n// All other library overlays (popover, menu, tooltip) use animate.enter/leave;\n// this divergence is intentional and isolated to the sheet container.\nconst sheetContainerVariants = tv(\n {\n slots: {\n host: 'fixed flex flex-col outline-none bg-surface-raised text-fg shadow-md overflow-hidden transition-[transform,opacity] ease-out motion-reduce:transition-none opacity-0 data-[state=open]:opacity-100',\n },\n variants: {\n side: {\n right: {\n host: 'h-screen right-0 top-0 border-l border-border data-[state=opening]:translate-x-full data-[state=closing]:translate-x-full data-[state=open]:translate-x-0',\n },\n left: {\n host: 'h-screen left-0 top-0 border-r border-border data-[state=opening]:-translate-x-full data-[state=closing]:-translate-x-full data-[state=open]:translate-x-0',\n },\n top: {\n host: 'w-screen left-0 top-0 border-b border-border data-[state=opening]:-translate-y-full data-[state=closing]:-translate-y-full data-[state=open]:translate-y-0',\n },\n bottom: {\n host: 'w-screen left-0 bottom-0 border-t border-border data-[state=opening]:translate-y-full data-[state=closing]:translate-y-full data-[state=open]:translate-y-0',\n },\n },\n size: {\n xs: { host: '' },\n sm: { host: '' },\n md: { host: '' },\n lg: { host: '' },\n xl: { host: '' },\n full: { host: '' },\n },\n },\n // Sheets are axis-aware: `size` controls width on horizontal sides and\n // height on vertical sides. Encoded as compound variants so a single\n // {side, size} pair resolves to one set of utility classes.\n compoundVariants: [\n // ── Right-anchored ─────────────────────────────────────────────\n { side: 'right', size: 'xs', class: { host: 'w-full max-w-xs' } },\n { side: 'right', size: 'sm', class: { host: 'w-full max-w-sm' } },\n { side: 'right', size: 'md', class: { host: 'w-full max-w-md' } },\n { side: 'right', size: 'lg', class: { host: 'w-full max-w-xl' } },\n { side: 'right', size: 'xl', class: { host: 'w-full max-w-2xl' } },\n { side: 'right', size: 'full', class: { host: 'w-screen max-w-none' } },\n // ── Left-anchored ──────────────────────────────────────────────\n { side: 'left', size: 'xs', class: { host: 'w-full max-w-xs' } },\n { side: 'left', size: 'sm', class: { host: 'w-full max-w-sm' } },\n { side: 'left', size: 'md', class: { host: 'w-full max-w-md' } },\n { side: 'left', size: 'lg', class: { host: 'w-full max-w-xl' } },\n { side: 'left', size: 'xl', class: { host: 'w-full max-w-2xl' } },\n { side: 'left', size: 'full', class: { host: 'w-screen max-w-none' } },\n // ── Top-anchored ───────────────────────────────────────────────\n { side: 'top', size: 'xs', class: { host: 'h-[20vh]' } },\n { side: 'top', size: 'sm', class: { host: 'h-[33vh]' } },\n { side: 'top', size: 'md', class: { host: 'h-[50vh]' } },\n { side: 'top', size: 'lg', class: { host: 'h-[66vh]' } },\n { side: 'top', size: 'xl', class: { host: 'h-[80vh]' } },\n { side: 'top', size: 'full', class: { host: 'h-screen' } },\n // ── Bottom-anchored ────────────────────────────────────────────\n { side: 'bottom', size: 'xs', class: { host: 'h-[20vh]' } },\n { side: 'bottom', size: 'sm', class: { host: 'h-[33vh]' } },\n { side: 'bottom', size: 'md', class: { host: 'h-[50vh]' } },\n { side: 'bottom', size: 'lg', class: { host: 'h-[66vh]' } },\n { side: 'bottom', size: 'xl', class: { host: 'h-[80vh]' } },\n { side: 'bottom', size: 'full', class: { host: 'h-screen' } },\n ],\n defaultVariants: { side: 'right', size: 'md' },\n },\n { twMerge: true },\n);\n\n/**\n * Sheet container rendered inside the CDK overlay. Wraps the user-provided\n * content in a Tailwind-styled, edge-anchored surface and coordinates slide\n * enter/exit transitions with {@link SheetRef}.\n *\n * The animation state machine, `aria-describedby` queue, and panel-class\n * merge are shared with `DialogContainer` via {@link OverlayContainerCoordinator}\n * (component-scoped — see `providers: [OverlayContainerCoordinator]`).\n *\n * @docs-private\n */\n@Component({\n selector: 'tw-sheet-container',\n template: '<ng-template cdkPortalOutlet />',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [CdkPortalOutlet],\n providers: [OverlayContainerCoordinator],\n host: {\n tabindex: '-1',\n '[attr.id]': '_config.id || null',\n '[attr.role]': '_config.role',\n '[attr.aria-modal]': '_config.ariaModal',\n '[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledByQueue[0]',\n '[attr.aria-label]': '_config.ariaLabel',\n '[attr.aria-describedby]': 'ariaDescribedByAttr()',\n '[attr.data-state]': 'state()',\n '[attr.data-side]': 'sideAttr()',\n '[class]': 'hostClasses()',\n '[style.transition-duration.ms]': 'transitionDuration()',\n },\n})\nexport class SheetContainer extends CdkDialogContainer<SheetConfig> {\n private readonly coordinator = inject(OverlayContainerCoordinator);\n\n /** Lifecycle state of the sheet's enter/exit animation. */\n readonly state: Signal<SheetState> = this.coordinator.state;\n\n /** Emits whenever the animation state transitions. */\n readonly animationStateChanged: EventEmitter<SheetAnimationEvent> =\n this.coordinator.animationStateChanged;\n\n /** Resolved enter-animation duration in ms. */\n readonly enterAnimationDuration: number;\n /** Resolved exit-animation duration in ms. */\n readonly exitAnimationDuration: number;\n\n protected readonly sideAttr = computed(() => this._config.side ?? 'right');\n\n private readonly variants = computed(() => {\n const side = this._config.side ?? 'right';\n const size = this._config.size ?? 'md';\n return sheetContainerVariants({ side, size });\n });\n\n protected readonly hostClasses = computed(() =>\n mergeOverlayPanelClass(this.variants().host(), this._config.panelClass),\n );\n\n protected readonly ariaDescribedByAttr = computed(\n () =>\n this._config.ariaDescribedBy ||\n this.coordinator.describedByIds()[0] ||\n null,\n );\n\n protected readonly transitionDuration = this.coordinator.transitionDuration;\n\n constructor() {\n super();\n this.enterAnimationDuration = coerceOverlayDuration(this._config.enterAnimationDuration, 200);\n this.exitAnimationDuration = coerceOverlayDuration(this._config.exitAnimationDuration, 160);\n this.coordinator.setDurations(this.enterAnimationDuration, this.exitAnimationDuration);\n }\n\n protected override _contentAttached(): void {\n super._contentAttached();\n this.coordinator.startEnterAnimation();\n }\n\n /** Triggered by the sheet ref to play the exit transition before disposing the overlay. */\n _startExitAnimation(): void {\n this.coordinator.startExitAnimation();\n }\n\n /** Registers a description id for the container's `aria-describedby`. */\n _addAriaDescribedBy(id: string): void {\n this.coordinator.addAriaDescribedBy(id);\n }\n\n /** Removes a previously registered description id. */\n _removeAriaDescribedBy(id: string): void {\n this.coordinator.removeAriaDescribedBy(id);\n }\n}\n","import {\n type ComponentRef,\n type Injector,\n type StaticProvider,\n type TemplateRef,\n} from '@angular/core';\nimport { Dialog, DialogConfig as CdkDialogConfig } from '@angular/cdk/dialog';\nimport {\n createBlockScrollStrategy,\n createCloseScrollStrategy,\n createGlobalPositionStrategy,\n createNoopScrollStrategy,\n createRepositionScrollStrategy,\n type GlobalPositionStrategy,\n type ScrollStrategy,\n} from '@angular/cdk/overlay';\nimport type { ComponentType } from '@angular/cdk/portal';\nimport {\n TW_SHEET_DATA,\n SheetConfig,\n type SheetScrollStrategy,\n type SheetSide,\n} from './sheet-config';\nimport { SheetContainer } from './sheet-container';\nimport { SheetRef } from './sheet-ref';\n\n/**\n * Rendering half of the sheet feature: the only module that pulls in\n * `@angular/cdk/dialog`, the overlay position/scroll strategies, and the\n * Tailwind `SheetContainer`. Reached exclusively through a dynamic `import()`\n * in {@link Sheet}, which keeps that graph out of a consumer's initial bundle.\n * Nothing here may be imported as a value from `sheet.ts`.\n *\n * @docs-private\n */\nexport function openRenderedSheet<R, D, C>(\n injector: Injector,\n content: ComponentType<C> | TemplateRef<C>,\n merged: SheetConfig<D, R>,\n sheetRef: SheetRef<R, C>,\n): void {\n // `Dialog` is `providedIn: 'root'`, so resolving it here — rather than\n // injecting it into the service — keeps the CDK symbol in this lazy chunk.\n const cdkDialog = injector.get(Dialog);\n\n const cdkRef = cdkDialog.open<R, D, C>(content, {\n id: merged.id,\n role: merged.role,\n data: merged.data,\n panelClass: merged.panelClass,\n backdropClass: merged.backdropClass || 'tw-sheet-backdrop',\n hasBackdrop: merged.hasBackdrop,\n // Sheet sizing happens on the container element (axis-aware width/height\n // utilities). The overlay pane itself is the full-edge bounding box.\n direction: merged.direction,\n ariaDescribedBy: merged.ariaDescribedBy,\n ariaLabelledBy: merged.ariaLabelledBy,\n ariaLabel: merged.ariaLabel,\n ariaModal: merged.ariaModal,\n autoFocus: merged.autoFocus,\n restoreFocus: merged.restoreFocus,\n scrollStrategy:\n merged.scrollStrategy ?? resolveScrollStrategy(injector, merged.scrollBehavior),\n positionStrategy:\n merged.positionStrategy ?? resolvePositionStrategy(injector, merged.side ?? 'right'),\n closeOnNavigation: merged.closeOnNavigation,\n viewContainerRef: merged.viewContainerRef,\n injector: merged.injector,\n // We handle close/Escape/backdrop ourselves so we can run the exit slide animation.\n disableClose: true,\n closeOnOverlayDetachments: false,\n container: {\n type: SheetContainer,\n providers: () => [\n { provide: SheetConfig, useValue: merged },\n { provide: CdkDialogConfig, useValue: merged },\n ],\n },\n providers: (cdkRef, _cdkConfig, container) => {\n sheetRef._attach(cdkRef, container as SheetContainer);\n const providers: StaticProvider[] = [\n { provide: SheetRef, useValue: sheetRef },\n { provide: TW_SHEET_DATA, useValue: merged.data ?? null },\n ];\n if (Array.isArray(merged.providers)) providers.push(...merged.providers);\n return providers;\n },\n });\n\n sheetRef._setComponent(\n cdkRef.componentInstance as C | null,\n cdkRef.componentRef as ComponentRef<C> | null,\n );\n}\n\nfunction resolveScrollStrategy(\n injector: Injector,\n strategy: SheetScrollStrategy | undefined,\n): ScrollStrategy {\n switch (strategy) {\n case 'close':\n return createCloseScrollStrategy(injector);\n case 'reposition':\n return createRepositionScrollStrategy(injector);\n case 'noop':\n return createNoopScrollStrategy();\n case 'block':\n default:\n return createBlockScrollStrategy(injector);\n }\n}\n\nfunction resolvePositionStrategy(injector: Injector, side: SheetSide): GlobalPositionStrategy {\n const strategy = createGlobalPositionStrategy(injector);\n switch (side) {\n case 'left':\n return strategy.top('0').left('0').bottom('0');\n case 'top':\n return strategy.top('0').left('0').right('0');\n case 'bottom':\n return strategy.bottom('0').left('0').right('0');\n case 'right':\n default:\n return strategy.top('0').right('0').bottom('0');\n }\n}\n"],"names":["CdkDialogConfig"],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { ComponentHarness, HarnessPredicate, TestKey } from '@angular/cdk/testing';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Harness for a sheet opened with `Sheet.open()`.
|
|
5
|
+
*
|
|
6
|
+
* ## Loading it
|
|
7
|
+
*
|
|
8
|
+
* A sheet is **service-opened**, not template-declared: nothing in the test
|
|
9
|
+
* fixture's own DOM represents it, and the container renders into the CDK
|
|
10
|
+
* overlay container on `document.body`. This harness's host *is* that container,
|
|
11
|
+
* so it must be loaded from
|
|
12
|
+
* `TestbedHarnessEnvironment.documentRootLoader(fixture)` — the ordinary
|
|
13
|
+
* `loader(fixture)` searches inside `fixture.nativeElement` and will never find
|
|
14
|
+
* it. Overlay panels belonging to template-declared components (`tw-select`,
|
|
15
|
+
* `tw-popover-overlay`, `tw-menu`) are the opposite case: those harnesses host
|
|
16
|
+
* on the in-fixture trigger and reach their panel internally, so the plain
|
|
17
|
+
* fixture loader is correct there.
|
|
18
|
+
*
|
|
19
|
+
* ## Waiting for it
|
|
20
|
+
*
|
|
21
|
+
* `Sheet` loads its render layer through a dynamic `import()`, so the container
|
|
22
|
+
* does **not** exist synchronously after `open()`. Await the ref's public
|
|
23
|
+
* {@link SheetRef.whenComponentReady} before asking for the harness — it
|
|
24
|
+
* resolves once the chunk has landed and the overlay is attached, for template
|
|
25
|
+
* sheets (with `null`) as well as component sheets.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const ref = sheet.open(FiltersSheet, { side: 'left' });
|
|
30
|
+
* await ref.whenComponentReady();
|
|
31
|
+
* const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
|
|
32
|
+
* const harness = await rootLoader.getHarness(SheetHarness);
|
|
33
|
+
* expect(await harness.getSide()).toBe('left');
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class SheetHarness extends ComponentHarness {
|
|
37
|
+
static hostSelector = 'tw-sheet-container';
|
|
38
|
+
title = this.locatorForOptional('[twSheetTitle], tw-sheet-title');
|
|
39
|
+
content = this.locatorForOptional('[twSheetContent], tw-sheet-content');
|
|
40
|
+
/** Any descendant of the container that currently holds DOM focus. */
|
|
41
|
+
focusedDescendant = this.locatorForOptional(':focus');
|
|
42
|
+
/**
|
|
43
|
+
* Overlay backdrops, which are siblings of the sheet's overlay pane rather
|
|
44
|
+
* than descendants of the container — hence the document-root lookup.
|
|
45
|
+
*/
|
|
46
|
+
backdrops = this.documentRootLocatorFactory().locatorForAll('.cdk-overlay-backdrop');
|
|
47
|
+
/** Predicate for `locatorFor` / `locatorForAll`. */
|
|
48
|
+
static with(options = {}) {
|
|
49
|
+
return new HarnessPredicate(SheetHarness, options)
|
|
50
|
+
.addOption('id', options.id, async (h, id) => HarnessPredicate.stringMatches(await h.getId(), id))
|
|
51
|
+
.addOption('title', options.title, async (h, title) => HarnessPredicate.stringMatches(await h.getTitleText(), title))
|
|
52
|
+
.addOption('side', options.side, async (h, side) => (await h.getSide()) === side);
|
|
53
|
+
}
|
|
54
|
+
/** The sheet's id. Matches the `id` on the `SheetRef` returned by `open()`. */
|
|
55
|
+
async getId() {
|
|
56
|
+
return (await this.host()).getAttribute('id');
|
|
57
|
+
}
|
|
58
|
+
/** The sheet's ARIA role — `'dialog'`, or `'alertdialog'` when so configured. */
|
|
59
|
+
async getRole() {
|
|
60
|
+
return (await this.host()).getAttribute('role');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The edge the sheet is anchored to, read from the container's `data-side`
|
|
64
|
+
* attribute. This is the one axis a sheet has that a dialog does not.
|
|
65
|
+
*/
|
|
66
|
+
async getSide() {
|
|
67
|
+
return (await (await this.host()).getAttribute('data-side'));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Text of the projected `[twSheetTitle]` element, trimmed, or `null` when the
|
|
71
|
+
* sheet's content does not use the title directive.
|
|
72
|
+
*/
|
|
73
|
+
async getTitleText() {
|
|
74
|
+
const title = await this.title();
|
|
75
|
+
return title ? (await title.text()).trim() : null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Text of the projected `[twSheetContent]` region, trimmed, or `null` when
|
|
79
|
+
* the sheet's content does not use the content directive.
|
|
80
|
+
*/
|
|
81
|
+
async getContentText() {
|
|
82
|
+
const content = await this.content();
|
|
83
|
+
return content ? (await content.text()).trim() : null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether DOM focus currently sits on the sheet container or anywhere inside
|
|
87
|
+
* it — the observable consequence of the CDK focus trap. CDK moves focus
|
|
88
|
+
* asynchronously, so let the fixture settle after opening before asserting.
|
|
89
|
+
*/
|
|
90
|
+
async containsFocus() {
|
|
91
|
+
if (await (await this.host()).isFocused())
|
|
92
|
+
return true;
|
|
93
|
+
return (await this.focusedDescendant()) !== null;
|
|
94
|
+
}
|
|
95
|
+
/** Whether the sheet rendered a backdrop. */
|
|
96
|
+
async hasBackdrop() {
|
|
97
|
+
return (await this.backdrops()).length > 0;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clicks the backdrop — the pointer dismiss gesture. Does nothing observable
|
|
101
|
+
* when the sheet was opened with `disableClose: true` or
|
|
102
|
+
* `closeOnBackdropClick: false`, which is how a test asserts those flags.
|
|
103
|
+
*
|
|
104
|
+
* Throws when no backdrop is rendered. With several overlays stacked, the
|
|
105
|
+
* last backdrop in the overlay container is used, i.e. the topmost one.
|
|
106
|
+
*/
|
|
107
|
+
async clickBackdrop() {
|
|
108
|
+
const backdrops = await this.backdrops();
|
|
109
|
+
if (backdrops.length === 0) {
|
|
110
|
+
throw new Error('SheetHarness.clickBackdrop: no backdrop is rendered. The sheet was opened with `hasBackdrop: false`.');
|
|
111
|
+
}
|
|
112
|
+
await backdrops[backdrops.length - 1].click();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Sends Escape to the sheet — the keyboard dismiss gesture. Deliberately a
|
|
116
|
+
* no-op when the sheet was opened with `disableClose: true` or
|
|
117
|
+
* `closeOnEscape: false`.
|
|
118
|
+
*/
|
|
119
|
+
async pressEscape() {
|
|
120
|
+
await (await this.host()).sendKeys(TestKey.ESCAPE);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Generated bundle index. Do not edit.
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
export { SheetHarness };
|
|
129
|
+
//# sourceMappingURL=cdevhub-ngx-tw-sheet-testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-sheet-testing.mjs","sources":["../../../projects/ngx-tw/sheet/testing/sheet-harness.ts","../../../projects/ngx-tw/sheet/testing/cdevhub-ngx-tw-sheet-testing.ts"],"sourcesContent":["import { ComponentHarness, HarnessPredicate, TestKey } from '@angular/cdk/testing';\nimport type { BaseHarnessFilters, TestElement } from '@angular/cdk/testing';\n// Imported through the package entry point, not a `../` path: a secondary entry\n// point's `rootDir` is its own directory, so ng-packagr rejects a relative\n// import that climbs out of `sheet/testing`.\nimport type { SheetSide } from '@cdevhub/ngx-tw/sheet';\n\n/** Filters accepted by `SheetHarness.with`. */\nexport interface SheetHarnessFilters extends BaseHarnessFilters {\n /** Match by the sheet's id — the same value as `SheetRef.id`. */\n id?: string | RegExp;\n /** Match by the text of the projected `[twSheetTitle]` element. */\n title?: string | RegExp;\n /** Match by the edge the sheet is anchored to. */\n side?: SheetSide;\n}\n\n/**\n * Harness for a sheet opened with `Sheet.open()`.\n *\n * ## Loading it\n *\n * A sheet is **service-opened**, not template-declared: nothing in the test\n * fixture's own DOM represents it, and the container renders into the CDK\n * overlay container on `document.body`. This harness's host *is* that container,\n * so it must be loaded from\n * `TestbedHarnessEnvironment.documentRootLoader(fixture)` — the ordinary\n * `loader(fixture)` searches inside `fixture.nativeElement` and will never find\n * it. Overlay panels belonging to template-declared components (`tw-select`,\n * `tw-popover-overlay`, `tw-menu`) are the opposite case: those harnesses host\n * on the in-fixture trigger and reach their panel internally, so the plain\n * fixture loader is correct there.\n *\n * ## Waiting for it\n *\n * `Sheet` loads its render layer through a dynamic `import()`, so the container\n * does **not** exist synchronously after `open()`. Await the ref's public\n * {@link SheetRef.whenComponentReady} before asking for the harness — it\n * resolves once the chunk has landed and the overlay is attached, for template\n * sheets (with `null`) as well as component sheets.\n *\n * @example\n * ```ts\n * const ref = sheet.open(FiltersSheet, { side: 'left' });\n * await ref.whenComponentReady();\n * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);\n * const harness = await rootLoader.getHarness(SheetHarness);\n * expect(await harness.getSide()).toBe('left');\n * ```\n */\nexport class SheetHarness extends ComponentHarness {\n static hostSelector = 'tw-sheet-container';\n\n private readonly title = this.locatorForOptional(\n '[twSheetTitle], tw-sheet-title',\n );\n private readonly content = this.locatorForOptional(\n '[twSheetContent], tw-sheet-content',\n );\n /** Any descendant of the container that currently holds DOM focus. */\n private readonly focusedDescendant = this.locatorForOptional(':focus');\n /**\n * Overlay backdrops, which are siblings of the sheet's overlay pane rather\n * than descendants of the container — hence the document-root lookup.\n */\n private readonly backdrops =\n this.documentRootLocatorFactory().locatorForAll('.cdk-overlay-backdrop');\n\n /** Predicate for `locatorFor` / `locatorForAll`. */\n static with(options: SheetHarnessFilters = {}): HarnessPredicate<SheetHarness> {\n return new HarnessPredicate(SheetHarness, options)\n .addOption('id', options.id, async (h, id) =>\n HarnessPredicate.stringMatches(await h.getId(), id),\n )\n .addOption('title', options.title, async (h, title) =>\n HarnessPredicate.stringMatches(await h.getTitleText(), title),\n )\n .addOption('side', options.side, async (h, side) => (await h.getSide()) === side);\n }\n\n /** The sheet's id. Matches the `id` on the `SheetRef` returned by `open()`. */\n async getId(): Promise<string | null> {\n return (await this.host()).getAttribute('id');\n }\n\n /** The sheet's ARIA role — `'dialog'`, or `'alertdialog'` when so configured. */\n async getRole(): Promise<string | null> {\n return (await this.host()).getAttribute('role');\n }\n\n /**\n * The edge the sheet is anchored to, read from the container's `data-side`\n * attribute. This is the one axis a sheet has that a dialog does not.\n */\n async getSide(): Promise<SheetSide | null> {\n return (await (await this.host()).getAttribute('data-side')) as SheetSide | null;\n }\n\n /**\n * Text of the projected `[twSheetTitle]` element, trimmed, or `null` when the\n * sheet's content does not use the title directive.\n */\n async getTitleText(): Promise<string | null> {\n const title: TestElement | null = await this.title();\n return title ? (await title.text()).trim() : null;\n }\n\n /**\n * Text of the projected `[twSheetContent]` region, trimmed, or `null` when\n * the sheet's content does not use the content directive.\n */\n async getContentText(): Promise<string | null> {\n const content: TestElement | null = await this.content();\n return content ? (await content.text()).trim() : null;\n }\n\n /**\n * Whether DOM focus currently sits on the sheet container or anywhere inside\n * it — the observable consequence of the CDK focus trap. CDK moves focus\n * asynchronously, so let the fixture settle after opening before asserting.\n */\n async containsFocus(): Promise<boolean> {\n if (await (await this.host()).isFocused()) return true;\n return (await this.focusedDescendant()) !== null;\n }\n\n /** Whether the sheet rendered a backdrop. */\n async hasBackdrop(): Promise<boolean> {\n return (await this.backdrops()).length > 0;\n }\n\n /**\n * Clicks the backdrop — the pointer dismiss gesture. Does nothing observable\n * when the sheet was opened with `disableClose: true` or\n * `closeOnBackdropClick: false`, which is how a test asserts those flags.\n *\n * Throws when no backdrop is rendered. With several overlays stacked, the\n * last backdrop in the overlay container is used, i.e. the topmost one.\n */\n async clickBackdrop(): Promise<void> {\n const backdrops = await this.backdrops();\n if (backdrops.length === 0) {\n throw new Error(\n 'SheetHarness.clickBackdrop: no backdrop is rendered. The sheet was opened with `hasBackdrop: false`.',\n );\n }\n await backdrops[backdrops.length - 1].click();\n }\n\n /**\n * Sends Escape to the sheet — the keyboard dismiss gesture. Deliberately a\n * no-op when the sheet was opened with `disableClose: true` or\n * `closeOnEscape: false`.\n */\n async pressEscape(): Promise<void> {\n await (await this.host()).sendKeys(TestKey.ESCAPE);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;AACG,MAAO,YAAa,SAAQ,gBAAgB,CAAA;AAChD,IAAA,OAAO,YAAY,GAAG,oBAAoB;AAEzB,IAAA,KAAK,GAAG,IAAI,CAAC,kBAAkB,CAC9C,gCAAgC,CACjC;AACgB,IAAA,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAChD,oCAAoC,CACrC;;AAEgB,IAAA,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC;AACtE;;;AAGG;IACc,SAAS,GACxB,IAAI,CAAC,0BAA0B,EAAE,CAAC,aAAa,CAAC,uBAAuB,CAAC;;AAG1E,IAAA,OAAO,IAAI,CAAC,OAAA,GAA+B,EAAE,EAAA;AAC3C,QAAA,OAAO,IAAI,gBAAgB,CAAC,YAAY,EAAE,OAAO;aAC9C,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KACvC,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC;aAEpD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,KAAK,KAChD,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,KAAK,CAAC;aAE9D,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IACrF;;AAGA,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC;IAC/C;;AAGA,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC;IACjD;AAEA;;;AAGG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,QAAQ,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC;IAC7D;AAEA;;;AAGG;AACH,IAAA,MAAM,YAAY,GAAA;AAChB,QAAA,MAAM,KAAK,GAAuB,MAAM,IAAI,CAAC,KAAK,EAAE;AACpD,QAAA,OAAO,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI;IACnD;AAEA;;;AAGG;AACH,IAAA,MAAM,cAAc,GAAA;AAClB,QAAA,MAAM,OAAO,GAAuB,MAAM,IAAI,CAAC,OAAO,EAAE;AACxD,QAAA,OAAO,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI;IACvD;AAEA;;;;AAIG;AACH,IAAA,MAAM,aAAa,GAAA;QACjB,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE;AAAE,YAAA,OAAO,IAAI;QACtD,OAAO,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,MAAM,IAAI;IAClD;;AAGA,IAAA,MAAM,WAAW,GAAA;QACf,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;IAC5C;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,aAAa,GAAA;AACjB,QAAA,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE;AACxC,QAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AAC1B,YAAA,MAAM,IAAI,KAAK,CACb,sGAAsG,CACvG;QACH;QACA,MAAM,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;IAC/C;AAEA;;;;AAIG;AACH,IAAA,MAAM,WAAW,GAAA;AACf,QAAA,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;IACpD;;;AC5JF;;AAEG;;;;"}
|