@blotch/dolan 22.2.2 → 22.2.4
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/dist/commands/add.d.ts +6 -2
- package/dist/commands/add.js +41 -11
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.js +162 -9
- package/dist/commands/add.test.js.map +1 -1
- package/dist/commands/diff.d.ts +2 -1
- package/dist/commands/diff.js +38 -25
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/diff.test.js +72 -11
- package/dist/commands/diff.test.js.map +1 -1
- package/dist/commands/doctor.js +228 -34
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +367 -10
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/eject.js +7 -0
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/eject.test.js +39 -0
- package/dist/commands/eject.test.js.map +1 -1
- package/dist/commands/info.js +3 -2
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.d.ts +37 -1
- package/dist/commands/init.js +169 -40
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +392 -27
- package/dist/commands/init.test.js.map +1 -1
- package/dist/commands/install-packages.d.ts +6 -0
- package/dist/commands/install-packages.js +20 -0
- package/dist/commands/install-packages.js.map +1 -0
- package/dist/commands/install-packages.test.d.ts +1 -0
- package/dist/commands/install-packages.test.js +55 -0
- package/dist/commands/install-packages.test.js.map +1 -0
- package/dist/commands/list.js +21 -14
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/list.test.js +62 -5
- package/dist/commands/list.test.js.map +1 -1
- package/dist/commands/outdated.js +11 -10
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/outdated.test.js +20 -5
- package/dist/commands/outdated.test.js.map +1 -1
- package/dist/commands/remove.d.ts +4 -0
- package/dist/commands/remove.js +17 -4
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/remove.test.js +53 -2
- package/dist/commands/remove.test.js.map +1 -1
- package/dist/commands/theme.js +1 -1
- package/dist/commands/theme.js.map +1 -1
- package/dist/commands/update.d.ts +11 -0
- package/dist/commands/update.js +174 -58
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +587 -33
- package/dist/commands/update.test.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lockfile.d.ts +7 -0
- package/dist/lockfile.js +36 -0
- package/dist/lockfile.js.map +1 -1
- package/dist/lockfile.test.d.ts +1 -0
- package/dist/lockfile.test.js +25 -0
- package/dist/lockfile.test.js.map +1 -0
- package/dist/registry.d.ts +14 -0
- package/dist/registry.js +78 -24
- package/dist/registry.js.map +1 -1
- package/dist/registry.test.js +119 -38
- package/dist/registry.test.js.map +1 -1
- package/dist/test-utils.d.ts +5 -0
- package/dist/test-utils.js +6 -1
- package/dist/test-utils.js.map +1 -1
- package/dist/testing/fire-lynx-event.d.ts +14 -0
- package/dist/testing/fire-lynx-event.js +19 -0
- package/dist/testing/fire-lynx-event.js.map +1 -0
- package/dist/testing/fire-lynx-event.test.d.ts +1 -0
- package/dist/testing/fire-lynx-event.test.js +44 -0
- package/dist/testing/fire-lynx-event.test.js.map +1 -0
- package/dist/testing/lynx-main-thread.d.ts +22 -0
- package/dist/testing/lynx-main-thread.js +11 -0
- package/dist/testing/lynx-main-thread.js.map +1 -0
- package/dist/testing/lynx-main-thread.test.d.ts +1 -0
- package/dist/testing/lynx-main-thread.test.js +24 -0
- package/dist/testing/lynx-main-thread.test.js.map +1 -0
- package/dist/testing/set-input-signal.d.ts +14 -0
- package/dist/testing/set-input-signal.js +21 -0
- package/dist/testing/set-input-signal.js.map +1 -0
- package/dist/testing/set-input-signal.test.d.ts +1 -0
- package/dist/testing/set-input-signal.test.js +20 -0
- package/dist/testing/set-input-signal.test.js.map +1 -0
- package/dist/ui/components/accordion/accordion.test.ts +158 -144
- package/dist/ui/components/accordion/accordion.ts +19 -14
- package/dist/ui/components/action-sheet/action-sheet.test.ts +283 -151
- package/dist/ui/components/action-sheet/action-sheet.ts +77 -43
- package/dist/ui/components/alert/alert.test.ts +67 -19
- package/dist/ui/components/alert/alert.ts +14 -16
- package/dist/ui/components/alert-dialog/alert-dialog.test.ts +208 -94
- package/dist/ui/components/alert-dialog/alert-dialog.ts +75 -38
- package/dist/ui/components/area-chart/area-chart.test.ts +134 -119
- package/dist/ui/components/area-chart/area-chart.ts +100 -315
- package/dist/ui/components/area-chart/index.ts +2 -3
- package/dist/ui/components/avatar/avatar.test.ts +89 -45
- package/dist/ui/components/badge/badge.test.ts +57 -23
- package/dist/ui/components/badge/badge.ts +12 -14
- package/dist/ui/components/bar-chart/bar-chart.test.ts +172 -45
- package/dist/ui/components/bar-chart/bar-chart.ts +140 -294
- package/dist/ui/components/bar-chart/index.ts +3 -3
- package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +386 -128
- package/dist/ui/components/bottom-sheet/bottom-sheet.ts +170 -53
- package/dist/ui/components/button/button.test.ts +611 -2
- package/dist/ui/components/button/button.ts +434 -49
- package/dist/ui/components/button/index.ts +2 -0
- package/dist/ui/components/button-group/button-group.test.ts +484 -2
- package/dist/ui/components/button-group/button-group.ts +380 -68
- package/dist/ui/components/button-group/index.ts +3 -0
- package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +183 -58
- package/dist/ui/components/candlestick-chart/candlestick-chart.ts +150 -323
- package/dist/ui/components/candlestick-chart/index.ts +3 -4
- package/dist/ui/components/card/card.test.ts +82 -62
- package/dist/ui/components/chart/chart-focus.test.ts +132 -0
- package/dist/ui/components/chart/chart-focus.ts +115 -0
- package/dist/ui/components/chart/chart-presets.test.ts +335 -0
- package/dist/ui/components/chart/chart-presets.ts +278 -0
- package/dist/ui/components/chart/chart-scene.test.ts +589 -0
- package/dist/ui/components/chart/chart-scene.ts +483 -0
- package/dist/ui/components/chart/chart-theme.test.ts +85 -0
- package/dist/ui/components/chart/chart-theme.ts +210 -0
- package/dist/ui/components/chart/chart-zoom.test.ts +159 -0
- package/dist/ui/components/chart/chart-zoom.ts +162 -0
- package/dist/ui/components/chart/chart.test.ts +1017 -0
- package/dist/ui/components/chart/chart.ts +934 -0
- package/dist/ui/components/chart/index.ts +24 -0
- package/dist/ui/components/checkbox/checkbox.test.ts +124 -42
- package/dist/ui/components/checkbox/checkbox.ts +23 -23
- package/dist/ui/components/collapsible/collapsible.test.ts +158 -81
- package/dist/ui/components/collapsible/collapsible.ts +19 -14
- package/dist/ui/components/context-menu/context-menu.test.ts +224 -0
- package/dist/ui/components/context-menu/context-menu.ts +110 -0
- package/dist/ui/components/context-menu/index.ts +1 -0
- package/dist/ui/components/dialog/dialog.test.ts +213 -108
- package/dist/ui/components/dialog/dialog.ts +72 -35
- package/dist/ui/components/dock/dock-scroll.test.ts +130 -0
- package/dist/ui/components/dock/dock-scroll.ts +133 -0
- package/dist/ui/components/dock/dock.test.ts +749 -0
- package/dist/ui/components/dock/dock.ts +960 -0
- package/dist/ui/components/dock/index.ts +2 -0
- package/dist/ui/components/empty-state/empty-state.test.ts +28 -39
- package/dist/ui/components/glass/concentric-radius.test.ts +13 -0
- package/dist/ui/components/glass/concentric-radius.ts +17 -0
- package/dist/ui/components/glass/glass-design.test.ts +78 -0
- package/dist/ui/components/glass/glass-design.ts +119 -0
- package/dist/ui/components/glass/glass.test.ts +338 -0
- package/dist/ui/components/glass/glass.ts +360 -0
- package/dist/ui/components/glass/index.ts +18 -0
- package/dist/ui/components/icon/icon-theme.test.ts +169 -0
- package/dist/ui/components/icon/icon-theme.ts +227 -0
- package/dist/ui/components/icon/icon.test.ts +85 -25
- package/dist/ui/components/icon/icon.ts +38 -21
- package/dist/ui/components/input/input.test.ts +178 -101
- package/dist/ui/components/input/input.ts +15 -12
- package/dist/ui/components/label/label.test.ts +11 -24
- package/dist/ui/components/line-chart/index.ts +2 -3
- package/dist/ui/components/line-chart/line-chart.test.ts +149 -56
- package/dist/ui/components/line-chart/line-chart.ts +83 -241
- package/dist/ui/components/list/list.test.ts +119 -21
- package/dist/ui/components/list/list.ts +21 -15
- package/dist/ui/components/menu/index.ts +25 -0
- package/dist/ui/components/menu/menu-placement.test.ts +153 -0
- package/dist/ui/components/menu/menu-placement.ts +159 -0
- package/dist/ui/components/menu/menu-popup.test.ts +632 -0
- package/dist/ui/components/menu/menu-popup.ts +544 -0
- package/dist/ui/components/menu/menu.test.ts +429 -0
- package/dist/ui/components/menu/menu.ts +415 -0
- package/dist/ui/components/nav-drawer/nav-drawer.test.ts +435 -191
- package/dist/ui/components/nav-drawer/nav-drawer.ts +127 -56
- package/dist/ui/components/pagination/pagination.test.ts +177 -65
- package/dist/ui/components/pagination/pagination.ts +55 -8
- package/dist/ui/components/progress/progress.test.ts +102 -46
- package/dist/ui/components/progress/progress.ts +52 -54
- package/dist/ui/components/radio-group/radio-group.test.ts +128 -83
- package/dist/ui/components/radio-group/radio-group.ts +24 -24
- package/dist/ui/components/scatter-chart/index.ts +2 -3
- package/dist/ui/components/scatter-chart/scatter-chart.test.ts +131 -26
- package/dist/ui/components/scatter-chart/scatter-chart.ts +104 -250
- package/dist/ui/components/scroll-area/scroll-area.test.ts +95 -24
- package/dist/ui/components/scroll-area/scroll-area.ts +8 -8
- package/dist/ui/components/select/select.test.ts +138 -78
- package/dist/ui/components/select/select.ts +17 -11
- package/dist/ui/components/separator/separator.test.ts +18 -17
- package/dist/ui/components/sheet/sheet.test.ts +64 -11
- package/dist/ui/components/sheet/sheet.ts +9 -1
- package/dist/ui/components/skeleton/skeleton.test.ts +24 -7
- package/dist/ui/components/skeleton/skeleton.ts +10 -16
- package/dist/ui/components/spinner/spinner.test.ts +67 -22
- package/dist/ui/components/spinner/spinner.ts +48 -41
- package/dist/ui/components/switch/switch.test.ts +116 -46
- package/dist/ui/components/switch/switch.ts +8 -13
- package/dist/ui/components/tab-bar/index.ts +1 -0
- package/dist/ui/components/tab-bar/tab-bar.test.ts +280 -0
- package/dist/ui/components/tab-bar/tab-bar.ts +230 -0
- package/dist/ui/components/tabs/tabs.test.ts +215 -157
- package/dist/ui/components/tabs/tabs.ts +110 -118
- package/dist/ui/components/textarea/textarea.test.ts +206 -100
- package/dist/ui/components/textarea/textarea.ts +14 -12
- package/dist/ui/components/toast/toast.test.ts +436 -315
- package/dist/ui/components/toast/toast.ts +62 -55
- package/dist/ui/components/toggle/toggle.test.ts +247 -140
- package/dist/ui/theme/chart-colors.test.ts +35 -0
- package/dist/ui/theme/dark.css +46 -2
- package/dist/ui/theme/default.css +63 -7
- package/dist/ui/theme/icon-colors.test.ts +35 -0
- package/dist/ui/theme/rgb-channels.test.ts +84 -0
- package/dist/ui/theme/tailwind-build.test.ts +114 -0
- package/dist/ui/theme/tailwind-css.test.ts +83 -0
- package/dist/ui/theme/tailwind-plugin.test.ts +42 -2
- package/dist/ui/theme/tailwind-plugin.ts +98 -25
- package/dist/ui/theme/tailwind.css +113 -0
- package/dist/ui/utils/animate.test.ts +13 -1
- package/dist/utils/analyze.d.ts +14 -0
- package/dist/utils/analyze.js +15 -0
- package/dist/utils/analyze.js.map +1 -1
- package/dist/utils/analyze.test.js +14 -1
- package/dist/utils/analyze.test.js.map +1 -1
- package/dist/utils/installed.d.ts +29 -0
- package/dist/utils/installed.js +43 -0
- package/dist/utils/installed.js.map +1 -0
- package/dist/utils/installed.test.d.ts +1 -0
- package/dist/utils/installed.test.js +57 -0
- package/dist/utils/installed.test.js.map +1 -0
- package/dist/utils/interactive.d.ts +9 -0
- package/dist/utils/interactive.js +10 -0
- package/dist/utils/interactive.js.map +1 -0
- package/dist/utils/interactive.test.d.ts +1 -0
- package/dist/utils/interactive.test.js +24 -0
- package/dist/utils/interactive.test.js.map +1 -0
- package/dist/utils/packages.d.ts +36 -0
- package/dist/utils/packages.js +70 -0
- package/dist/utils/packages.js.map +1 -0
- package/dist/utils/packages.test.d.ts +1 -0
- package/dist/utils/packages.test.js +89 -0
- package/dist/utils/packages.test.js.map +1 -0
- package/dist/utils/resolve-paths.d.ts +17 -1
- package/dist/utils/resolve-paths.js +21 -3
- package/dist/utils/resolve-paths.js.map +1 -1
- package/dist/utils/resolve-paths.test.js +38 -2
- package/dist/utils/resolve-paths.test.js.map +1 -1
- package/dist/utils/tailwind.d.ts +25 -0
- package/dist/utils/tailwind.js +51 -0
- package/dist/utils/tailwind.js.map +1 -0
- package/dist/utils/tailwind.test.d.ts +1 -0
- package/dist/utils/tailwind.test.js +71 -0
- package/dist/utils/tailwind.test.js.map +1 -0
- package/package.json +13 -1
- package/dist/ui/components/area-chart/area-chart-render.test.ts +0 -121
- package/dist/ui/components/bar-chart/bar-chart-render.test.ts +0 -174
- package/dist/ui/components/button/button-render.test.ts +0 -113
- package/dist/ui/components/button-group/button-group-render.test.ts +0 -146
- package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +0 -174
- package/dist/ui/components/cartesian-chart/cartesian-chart-render.test.ts +0 -188
- package/dist/ui/components/cartesian-chart/cartesian-chart.test.ts +0 -525
- package/dist/ui/components/cartesian-chart/cartesian-chart.ts +0 -1140
- package/dist/ui/components/cartesian-chart/index.ts +0 -18
- package/dist/ui/components/line-chart/line-chart-render.test.ts +0 -121
- package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +0 -157
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// cspell:words WAAPI tweens
|
|
2
2
|
import {
|
|
3
3
|
type ElementRef,
|
|
4
|
+
type OnDestroy,
|
|
4
5
|
Component,
|
|
5
6
|
ViewEncapsulation,
|
|
6
7
|
computed,
|
|
@@ -59,29 +60,44 @@ const BACKDROP_CLEAR_DISTANCE = 500;
|
|
|
59
60
|
*/
|
|
60
61
|
@Component({
|
|
61
62
|
selector: 'ui-bottom-sheet',
|
|
62
|
-
standalone: true,
|
|
63
63
|
imports: [LYNX_ELEMENTS],
|
|
64
64
|
encapsulation: ViewEncapsulation.None,
|
|
65
65
|
template: `
|
|
66
66
|
<overlay [attr.visible]="overlayVisible()" [style]="overlayStyle()">
|
|
67
|
+
<!--
|
|
68
|
+
The mouse drag's move/up listeners sit on the full-screen backdrop,
|
|
69
|
+
not the handle: a touch keeps targeting the element it started on, but
|
|
70
|
+
a mouse event targets whatever is under the cursor, so a cursor that
|
|
71
|
+
outruns the thin handle strip (or drags up off the panel) would stop
|
|
72
|
+
driving the drag. Mouse events bubble here from anywhere in the sheet,
|
|
73
|
+
including the handle and the panel. There's no mouseleave: like a
|
|
74
|
+
touch, the drag carries on until release, and Chrome doesn't deliver
|
|
75
|
+
mouseleave to Lynx web anyway (see onMouseDragMove for a release
|
|
76
|
+
outside the view).
|
|
77
|
+
-->
|
|
67
78
|
<view
|
|
68
79
|
#backdrop
|
|
69
80
|
class="h-full w-full"
|
|
70
81
|
[style]="backdropStyle()"
|
|
71
82
|
(bindtap)="onBackdropTap()"
|
|
83
|
+
(bindmousedown)="onBackdropMouseDown()"
|
|
84
|
+
(bindmousemove)="onMouseDragMove($event)"
|
|
85
|
+
(bindmouseup)="onDragEnd()"
|
|
72
86
|
>
|
|
73
87
|
<view
|
|
74
88
|
#panel
|
|
75
89
|
[class]="panelClass()"
|
|
76
90
|
[style]="panelPositionStyle()"
|
|
91
|
+
[accessibility-exclusive-focus]="overlayVisible()"
|
|
77
92
|
(catchtap)="onPanelTap()"
|
|
78
93
|
>
|
|
79
94
|
<view
|
|
80
95
|
class="items-center pb-3 pt-2 flex justify-center"
|
|
81
96
|
(catchtouchstart)="onHandleTouchStart($event)"
|
|
82
97
|
(catchtouchmove)="onHandleTouchMove($event)"
|
|
83
|
-
(catchtouchend)="
|
|
84
|
-
(catchtouchcancel)="
|
|
98
|
+
(catchtouchend)="onDragEnd()"
|
|
99
|
+
(catchtouchcancel)="onDragEnd()"
|
|
100
|
+
(catchmousedown)="onHandleMouseDown($event)"
|
|
85
101
|
>
|
|
86
102
|
<view class="h-1 w-10 rounded-full bg-muted" />
|
|
87
103
|
</view>
|
|
@@ -91,7 +107,7 @@ const BACKDROP_CLEAR_DISTANCE = 500;
|
|
|
91
107
|
</overlay>
|
|
92
108
|
`,
|
|
93
109
|
})
|
|
94
|
-
export class UiBottomSheet {
|
|
110
|
+
export class UiBottomSheet implements OnDestroy {
|
|
95
111
|
readonly open = model(false);
|
|
96
112
|
readonly userClass = input<string>('', { alias: 'class' });
|
|
97
113
|
|
|
@@ -110,11 +126,16 @@ export class UiBottomSheet {
|
|
|
110
126
|
: 'position: fixed; overflow: visible; width: 100vw; height: 100vh; top: 0; left: 0; z-index: 999; display: none;',
|
|
111
127
|
);
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
129
|
+
// Required: both are always in the template (the overlay is hidden, never
|
|
130
|
+
// removed), and nothing reads them before the first render.
|
|
131
|
+
readonly backdropRef = viewChild.required<ElementRef>('backdrop');
|
|
132
|
+
readonly panelRef = viewChild.required<ElementRef>('panel');
|
|
115
133
|
#backdropAnim?: AnimationHandle;
|
|
116
134
|
#panelAnim?: AnimationHandle;
|
|
117
135
|
#hasBeenOpen = false;
|
|
136
|
+
// The open and close sequences' pending timers, so ngOnDestroy can stop
|
|
137
|
+
// them.
|
|
138
|
+
readonly #timers = new Set<ReturnType<typeof setTimeout>>();
|
|
118
139
|
|
|
119
140
|
// --- Drag-to-dismiss state ---
|
|
120
141
|
// Live downward drag distance (px), applied to the panel as a translateY via
|
|
@@ -125,22 +146,35 @@ export class UiBottomSheet {
|
|
|
125
146
|
// True only between touchstart and touchend on the handle, so unrelated move
|
|
126
147
|
// events can't shift the sheet.
|
|
127
148
|
#isDragging = false;
|
|
149
|
+
// Set when a mouse drag that actually moved is released. The browser follows
|
|
150
|
+
// that mouseup with a click on the nearest element under both the mousedown
|
|
151
|
+
// and the mouseup, which is the backdrop whenever the cursor ended up off the
|
|
152
|
+
// panel, and Lynx web maps that click to the backdrop's tap. Without this, a
|
|
153
|
+
// drag released above the panel (where the sheet snaps back) would close it.
|
|
154
|
+
#ignoreNextBackdropTap = false;
|
|
155
|
+
// Whether the current drag is a mouse drag that has moved: only those are
|
|
156
|
+
// followed by a click. A moved touch produces no tap.
|
|
157
|
+
#mouseDragMoved = false;
|
|
128
158
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Opens or closes the sheet as `open` changes. A field rather than a
|
|
161
|
+
* constructor: Angular's test build keeps a function for a constructor that
|
|
162
|
+
* nothing calls, which an app's coverage report would show as uncovered.
|
|
163
|
+
*
|
|
164
|
+
* `#hasBeenOpen` prevents the close animation from running on the initial
|
|
165
|
+
* effect evaluation when `open` starts as false. Without this guard, the
|
|
166
|
+
* first run would call #doClose() and emit `closed` before the sheet
|
|
167
|
+
* has ever been opened.
|
|
168
|
+
*/
|
|
169
|
+
protected readonly openOrClose = effect(() => {
|
|
170
|
+
const isOpen = this.open();
|
|
171
|
+
if (isOpen) {
|
|
172
|
+
this.#hasBeenOpen = true;
|
|
173
|
+
this.#doOpen();
|
|
174
|
+
} else if (this.#hasBeenOpen) {
|
|
175
|
+
this.#doClose();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
144
178
|
|
|
145
179
|
protected readonly panelClass = computed(() =>
|
|
146
180
|
cn(
|
|
@@ -184,9 +218,24 @@ export class UiBottomSheet {
|
|
|
184
218
|
});
|
|
185
219
|
|
|
186
220
|
protected onBackdropTap(): void {
|
|
221
|
+
if (this.#ignoreNextBackdropTap) {
|
|
222
|
+
this.#ignoreNextBackdropTap = false;
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
187
225
|
this.open.set(false);
|
|
188
226
|
}
|
|
189
227
|
|
|
228
|
+
/**
|
|
229
|
+
* A fresh press starts a fresh click, so drop any ignore left over from a
|
|
230
|
+
* drag whose release didn't produce a backdrop click (one released over the
|
|
231
|
+
* panel, whose `catchtap` swallows it). Otherwise the next real backdrop tap
|
|
232
|
+
* would be ignored. The handle catches its own mousedown, which is fine: it
|
|
233
|
+
* starts a new drag that resets the flag on release.
|
|
234
|
+
*/
|
|
235
|
+
protected onBackdropMouseDown(): void {
|
|
236
|
+
this.#ignoreNextBackdropTap = false;
|
|
237
|
+
}
|
|
238
|
+
|
|
190
239
|
/**
|
|
191
240
|
* No-op tap handler for the panel. `catchtap` (vs `bindtap`) already stops
|
|
192
241
|
* the tap from bubbling to the backdrop — Lynx controls propagation via the
|
|
@@ -196,19 +245,14 @@ export class UiBottomSheet {
|
|
|
196
245
|
protected onPanelTap(): void {}
|
|
197
246
|
|
|
198
247
|
/**
|
|
199
|
-
* Begin a drag on the handle strip.
|
|
200
|
-
* translateY(0%) via fill:'forwards', which would override our inline
|
|
201
|
-
* transform — cancel it so `dragOffset` (applied through panelPositionStyle)
|
|
202
|
-
* actually moves the panel from here on.
|
|
248
|
+
* Begin a drag on the handle strip.
|
|
203
249
|
*/
|
|
204
250
|
protected onHandleTouchStart(e: {
|
|
205
251
|
touches?: ReadonlyArray<{ clientY: number }>;
|
|
206
252
|
}): void {
|
|
207
253
|
const y = e.touches?.[0]?.clientY;
|
|
208
254
|
if (y == null) return;
|
|
209
|
-
this.#
|
|
210
|
-
this.#isDragging = true;
|
|
211
|
-
this.#dragStartY = y;
|
|
255
|
+
this.#startDrag(y);
|
|
212
256
|
}
|
|
213
257
|
|
|
214
258
|
protected onHandleTouchMove(e: {
|
|
@@ -217,20 +261,53 @@ export class UiBottomSheet {
|
|
|
217
261
|
if (!this.#isDragging) return;
|
|
218
262
|
const y = e.touches?.[0]?.clientY;
|
|
219
263
|
if (y == null) return;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
264
|
+
this.#moveDrag(y);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* The mouse twin of onHandleTouchStart, so the handle drags on web. A
|
|
269
|
+
* desktop browser fires no touch events for a mouse, and Lynx web passes
|
|
270
|
+
* DOM events straight through rather than turning mouse input into touches.
|
|
271
|
+
* On a touch-only device no mouse events fire, so touch keeps driving it.
|
|
272
|
+
*
|
|
273
|
+
* Reads `y`, not `clientY`: Lynx PC reports a mouse event's clientY relative
|
|
274
|
+
* to the element under the cursor, which changes as the cursor moves across
|
|
275
|
+
* the sheet, while `y` is relative to the Lynx view on PC and web alike.
|
|
276
|
+
*/
|
|
277
|
+
protected onHandleMouseDown(e: { y: number }): void {
|
|
278
|
+
this.#startDrag(e.y);
|
|
223
279
|
}
|
|
224
280
|
|
|
225
281
|
/**
|
|
226
|
-
*
|
|
282
|
+
* Bound on the backdrop (see the template), so it also sees every move the
|
|
283
|
+
* cursor makes over an open sheet. Only those during a drag count.
|
|
284
|
+
*/
|
|
285
|
+
protected onMouseDragMove(e: { y: number; buttons: number }): void {
|
|
286
|
+
if (!this.#isDragging) return;
|
|
287
|
+
// No button held means the mouseup happened where the sheet couldn't see
|
|
288
|
+
// it: a release outside the Lynx view (past the edge of a docs preview, or
|
|
289
|
+
// outside the browser window) goes to the page, and web-core only listens
|
|
290
|
+
// inside the view. Treat the first move back as the release, or the panel
|
|
291
|
+
// would stay mid-drag.
|
|
292
|
+
if (e.buttons === 0) {
|
|
293
|
+
this.onDragEnd();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
this.#mouseDragMoved = true;
|
|
297
|
+
this.#moveDrag(e.y);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Release the drag, from a touchend, touchcancel or mouseup, or a mouse
|
|
302
|
+
* move with no button held. Past the threshold we set `open` to false and let the
|
|
227
303
|
* effect drive teardown (#doClose → drag-aware #animateOut), which keeps the
|
|
228
304
|
* two-way `open` binding in sync and reuses the `closed` emit. Otherwise the
|
|
229
305
|
* sheet springs back to fully open.
|
|
230
306
|
*/
|
|
231
|
-
protected
|
|
307
|
+
protected onDragEnd(): void {
|
|
232
308
|
if (!this.#isDragging) return;
|
|
233
309
|
this.#isDragging = false;
|
|
310
|
+
this.#ignoreNextBackdropTap = this.#mouseDragMoved;
|
|
234
311
|
if (this.dragOffset() > DISMISS_THRESHOLD) {
|
|
235
312
|
this.open.set(false);
|
|
236
313
|
} else {
|
|
@@ -238,15 +315,55 @@ export class UiBottomSheet {
|
|
|
238
315
|
}
|
|
239
316
|
}
|
|
240
317
|
|
|
318
|
+
/**
|
|
319
|
+
* The open slideIn holds the panel at translateY(0%) via fill:'forwards',
|
|
320
|
+
* which would override our inline transform — cancel it so `dragOffset`
|
|
321
|
+
* (applied through panelPositionStyle) actually moves the panel from here on.
|
|
322
|
+
*/
|
|
323
|
+
#startDrag(y: number): void {
|
|
324
|
+
this.#panelAnim?.cancel();
|
|
325
|
+
this.#isDragging = true;
|
|
326
|
+
this.#mouseDragMoved = false;
|
|
327
|
+
this.#dragStartY = y;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
#moveDrag(y: number): void {
|
|
331
|
+
// Clamp to >= 0: the sheet is already docked at the bottom, so only a
|
|
332
|
+
// downward (dismiss-direction) drag should move it.
|
|
333
|
+
this.dragOffset.set(Math.max(0, y - this.#dragStartY));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* The sheet can be destroyed while its open or close sequence is still
|
|
338
|
+
* running, for example by an `@if` around it or a route change right after
|
|
339
|
+
* closing it. The rest of the sequence then ran on the destroyed component:
|
|
340
|
+
* it animated detached elements and emitted `closed` from a destroyed
|
|
341
|
+
* output, which Angular warns about in dev builds (NG0953).
|
|
342
|
+
*/
|
|
343
|
+
ngOnDestroy(): void {
|
|
344
|
+
for (const timer of this.#timers) clearTimeout(timer);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* `setTimeout`, tracked so that ngOnDestroy can cancel it.
|
|
349
|
+
*/
|
|
350
|
+
#later(callback: () => void, ms: number): void {
|
|
351
|
+
const timer = setTimeout(() => {
|
|
352
|
+
this.#timers.delete(timer);
|
|
353
|
+
callback();
|
|
354
|
+
}, ms);
|
|
355
|
+
this.#timers.add(timer);
|
|
356
|
+
}
|
|
357
|
+
|
|
241
358
|
/**
|
|
242
359
|
* Two-phase open: make the overlay visible first so native elements exist
|
|
243
360
|
* in the tree, then animate on the next frame. Without this, animate()
|
|
244
361
|
* targets elements that haven't been flushed to native yet and silently fails.
|
|
245
362
|
*/
|
|
246
363
|
#doOpen(): void {
|
|
247
|
-
|
|
364
|
+
this.#later(() => {
|
|
248
365
|
this.overlayVisible.set(true);
|
|
249
|
-
|
|
366
|
+
this.#later(() => this.#animateIn(), 0);
|
|
250
367
|
}, 0);
|
|
251
368
|
}
|
|
252
369
|
|
|
@@ -257,9 +374,9 @@ export class UiBottomSheet {
|
|
|
257
374
|
* before the fade finishes.
|
|
258
375
|
*/
|
|
259
376
|
#doClose(): void {
|
|
260
|
-
|
|
377
|
+
this.#later(() => {
|
|
261
378
|
this.#animateOut();
|
|
262
|
-
|
|
379
|
+
this.#later(() => {
|
|
263
380
|
this.overlayVisible.set(false);
|
|
264
381
|
this.closed.emit();
|
|
265
382
|
// Reset for the next open: the sheet returns to its docked position
|
|
@@ -270,14 +387,18 @@ export class UiBottomSheet {
|
|
|
270
387
|
}
|
|
271
388
|
|
|
272
389
|
#animateIn(): void {
|
|
273
|
-
const backdrop = this.backdropRef()
|
|
274
|
-
const panel = this.panelRef()
|
|
275
|
-
if (!backdrop || !panel) return;
|
|
390
|
+
const backdrop = this.backdropRef().nativeElement;
|
|
391
|
+
const panel = this.panelRef().nativeElement;
|
|
276
392
|
|
|
277
393
|
this.#backdropAnim?.cancel();
|
|
278
394
|
this.#panelAnim?.cancel();
|
|
279
395
|
|
|
280
396
|
this.#backdropAnim = fadeIn(backdrop, { duration: DURATION.normal });
|
|
397
|
+
// Move a screen reader into the panel. It would otherwise stay on whatever
|
|
398
|
+
// opened it, which is now behind the overlay. With the panel's
|
|
399
|
+
// accessibility-exclusive-focus (see the template), it then can't leave
|
|
400
|
+
// the panel until it closes.
|
|
401
|
+
panel.invoke?.('requestAccessibilityFocus');
|
|
281
402
|
this.#panelAnim = slideIn(panel, 'up', {
|
|
282
403
|
duration: DURATION.slow,
|
|
283
404
|
easing: EASING.sheet,
|
|
@@ -285,9 +406,8 @@ export class UiBottomSheet {
|
|
|
285
406
|
}
|
|
286
407
|
|
|
287
408
|
#animateOut(): void {
|
|
288
|
-
const backdrop = this.backdropRef()
|
|
289
|
-
const panel = this.panelRef()
|
|
290
|
-
if (!backdrop || !panel) return;
|
|
409
|
+
const backdrop = this.backdropRef().nativeElement;
|
|
410
|
+
const panel = this.panelRef().nativeElement;
|
|
291
411
|
|
|
292
412
|
this.#backdropAnim?.cancel();
|
|
293
413
|
this.#panelAnim?.cancel();
|
|
@@ -321,17 +441,14 @@ export class UiBottomSheet {
|
|
|
321
441
|
* continuing smoothly from wherever the finger let go (px → 0px).
|
|
322
442
|
*/
|
|
323
443
|
#snapBack(fromOffset: number): void {
|
|
324
|
-
const panel = this.panelRef()?.nativeElement;
|
|
325
444
|
this.#panelAnim?.cancel();
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
);
|
|
334
|
-
}
|
|
445
|
+
this.#panelAnim = this.panelRef().nativeElement.animate(
|
|
446
|
+
[
|
|
447
|
+
{ transform: `translateY(${fromOffset}px)` },
|
|
448
|
+
{ transform: 'translateY(0px)' },
|
|
449
|
+
],
|
|
450
|
+
{ duration: DURATION.fast, easing: EASING.spring, fill: 'forwards' },
|
|
451
|
+
);
|
|
335
452
|
// Match the inline transform to the animation's resting state so the two
|
|
336
453
|
// agree once fill:'forwards' hands control back to the style binding.
|
|
337
454
|
this.dragOffset.set(0);
|