@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
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
fireEvent,
|
|
4
|
+
render,
|
|
5
|
+
waitForUpdate,
|
|
6
|
+
} from '@blotch/angular-lynx-testing-library';
|
|
7
|
+
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { UiDockScroll, UiDockState } from './dock-scroll';
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
imports: [LYNX_ELEMENTS, UiDockScroll],
|
|
13
|
+
template: `
|
|
14
|
+
@if (shown()) {
|
|
15
|
+
<scroll-view ui-dock-scroll scroll-orientation="vertical">
|
|
16
|
+
<view style="height: 2000px"></view>
|
|
17
|
+
</scroll-view>
|
|
18
|
+
}
|
|
19
|
+
`,
|
|
20
|
+
})
|
|
21
|
+
class ScrollHost {
|
|
22
|
+
readonly shown = signal(true);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const renderScroll = async () => {
|
|
26
|
+
const result = await render(ScrollHost);
|
|
27
|
+
const host = result.componentRef.instance as ScrollHost;
|
|
28
|
+
const state = result.componentRef.injector.get(UiDockState);
|
|
29
|
+
const scrollView = () => result.container.querySelector('scroll-view')!;
|
|
30
|
+
/**
|
|
31
|
+
* Scrolls the content to `scrollTop`, as Lynx reports it.
|
|
32
|
+
*/
|
|
33
|
+
const scrollTo = (scrollTop: number) =>
|
|
34
|
+
fireEvent.scroll(scrollView(), {
|
|
35
|
+
detail: { scrollTop, scrollHeight: 2000 },
|
|
36
|
+
});
|
|
37
|
+
return { ...result, host, state, scrollView, scrollTo };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
describe('UiDockScroll', () => {
|
|
41
|
+
it('minimizes the dock as content scrolls down, and expands it as it scrolls up', async () => {
|
|
42
|
+
const { state, scrollTo } = await renderScroll();
|
|
43
|
+
expect(state.minimized()).toBe(false);
|
|
44
|
+
|
|
45
|
+
// A little way down isn't enough: a small drag leaves the dock whole.
|
|
46
|
+
scrollTo(10);
|
|
47
|
+
scrollTo(20);
|
|
48
|
+
expect(state.minimized()).toBe(false);
|
|
49
|
+
scrollTo(30);
|
|
50
|
+
expect(state.minimized()).toBe(true);
|
|
51
|
+
|
|
52
|
+
// Further down keeps it minimized.
|
|
53
|
+
scrollTo(300);
|
|
54
|
+
expect(state.minimized()).toBe(true);
|
|
55
|
+
|
|
56
|
+
// A glance back up brings it back.
|
|
57
|
+
scrollTo(295);
|
|
58
|
+
scrollTo(290);
|
|
59
|
+
expect(state.minimized()).toBe(true);
|
|
60
|
+
scrollTo(287);
|
|
61
|
+
expect(state.minimized()).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('counts the distance again when content turns', async () => {
|
|
65
|
+
const { state, scrollTo } = await renderScroll();
|
|
66
|
+
scrollTo(100);
|
|
67
|
+
expect(state.minimized()).toBe(true);
|
|
68
|
+
scrollTo(80);
|
|
69
|
+
expect(state.minimized()).toBe(false);
|
|
70
|
+
|
|
71
|
+
// Down 20 after coming up 20 starts a new count, short of minimizing.
|
|
72
|
+
scrollTo(100);
|
|
73
|
+
expect(state.minimized()).toBe(false);
|
|
74
|
+
// An event with no movement keeps the count.
|
|
75
|
+
scrollTo(100);
|
|
76
|
+
scrollTo(104);
|
|
77
|
+
expect(state.minimized()).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('expands the dock at the top, including the bounce above it', async () => {
|
|
81
|
+
const { state, scrollTo } = await renderScroll();
|
|
82
|
+
scrollTo(200);
|
|
83
|
+
expect(state.minimized()).toBe(true);
|
|
84
|
+
|
|
85
|
+
scrollTo(5);
|
|
86
|
+
expect(state.minimized()).toBe(false);
|
|
87
|
+
|
|
88
|
+
scrollTo(200);
|
|
89
|
+
expect(state.minimized()).toBe(true);
|
|
90
|
+
scrollTo(-30);
|
|
91
|
+
expect(state.minimized()).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("ignores iOS's bounce back from past the end", async () => {
|
|
95
|
+
const { state, scrollTo, scrollView } = await renderScroll();
|
|
96
|
+
// The scroll view is 800px tall, so its content ends at 1200.
|
|
97
|
+
fireEvent.layoutchange(scrollView(), {
|
|
98
|
+
detail: { width: 400, height: 800 },
|
|
99
|
+
});
|
|
100
|
+
scrollTo(1150);
|
|
101
|
+
scrollTo(1250);
|
|
102
|
+
expect(state.minimized()).toBe(true);
|
|
103
|
+
|
|
104
|
+
// Bouncing back from 1250 to the end reads as scrolling up, but isn't.
|
|
105
|
+
scrollTo(1230);
|
|
106
|
+
scrollTo(1210);
|
|
107
|
+
expect(state.minimized()).toBe(true);
|
|
108
|
+
|
|
109
|
+
// Scrolling up from the end is.
|
|
110
|
+
scrollTo(1200);
|
|
111
|
+
scrollTo(1180);
|
|
112
|
+
expect(state.minimized()).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('expands the dock when the scroll view goes, and stops listening', async () => {
|
|
116
|
+
const { host, state, scrollTo, scrollView } = await renderScroll();
|
|
117
|
+
const removed = scrollView();
|
|
118
|
+
scrollTo(200);
|
|
119
|
+
expect(state.minimized()).toBe(true);
|
|
120
|
+
|
|
121
|
+
host.shown.set(false);
|
|
122
|
+
await waitForUpdate();
|
|
123
|
+
expect(state.minimized()).toBe(false);
|
|
124
|
+
|
|
125
|
+
fireEvent.scroll(removed, {
|
|
126
|
+
detail: { scrollTop: 600, scrollHeight: 2000 },
|
|
127
|
+
});
|
|
128
|
+
expect(state.minimized()).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
Directive,
|
|
4
|
+
ElementRef,
|
|
5
|
+
Injectable,
|
|
6
|
+
Renderer2,
|
|
7
|
+
inject,
|
|
8
|
+
signal,
|
|
9
|
+
} from '@angular/core';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Whether the dock is minimized, shared by the dock and the scroll views that
|
|
13
|
+
* minimize it. A service rather than an input, because the two sit in
|
|
14
|
+
* different parts of the app: the dock beside the `<router-outlet>`, and the
|
|
15
|
+
* scroll views inside the routed screens, which can't reach it.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* // Bring the dock back from code, after a search, for example.
|
|
19
|
+
* inject(UiDockState).minimized.set(false);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* This is what the app asks for. Whether the dock is minimized now is the
|
|
23
|
+
* dock's own `minimized()`: it stays whole where its design doesn't minimize.
|
|
24
|
+
*/
|
|
25
|
+
@Injectable({ providedIn: 'root' })
|
|
26
|
+
export class UiDockState {
|
|
27
|
+
/**
|
|
28
|
+
* Whether the dock should be minimized: on iOS 26 and later and the web,
|
|
29
|
+
* the bar shrinks to the selected item's icon, and on Android's Material
|
|
30
|
+
* design it slides away. The frosted design of iOS 15 to 25 doesn't
|
|
31
|
+
* minimize, as Apple's tab bars didn't, so there it stays expanded whatever
|
|
32
|
+
* this says.
|
|
33
|
+
*/
|
|
34
|
+
readonly minimized = signal(false);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* How far content scrolls the same way before the dock follows, in px: a
|
|
39
|
+
* longer way down than up, as iOS's tab bar does, so a small drag doesn't
|
|
40
|
+
* hide it, but a glance back up brings it back.
|
|
41
|
+
*/
|
|
42
|
+
const MINIMIZE_AFTER = 24;
|
|
43
|
+
const EXPAND_AFTER = 12;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Near enough to the top that the dock expands, in px: content scrolled back
|
|
47
|
+
* to its start always shows the whole dock.
|
|
48
|
+
*/
|
|
49
|
+
const TOP = 8;
|
|
50
|
+
|
|
51
|
+
/** What Lynx sends with `scroll` and `layoutchange`, as far as this reads. */
|
|
52
|
+
type ScrollDetail = { scrollTop: number; scrollHeight: number };
|
|
53
|
+
type LayoutDetail = { height: number };
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Minimizes the dock while this scroll view scrolls down, and expands it when
|
|
57
|
+
* it scrolls up or back to the top, as iOS 26 minimizes its tab bar
|
|
58
|
+
* (`tabBarMinimizeBehavior(.onScrollDown)`). Put it on each screen's
|
|
59
|
+
* `<scroll-view>` (or `<list>`) that should minimize the dock:
|
|
60
|
+
*
|
|
61
|
+
* ```html
|
|
62
|
+
* <scroll-view ui-dock-scroll scroll-orientation="vertical" class="h-full">
|
|
63
|
+
* …
|
|
64
|
+
* </scroll-view>
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* It listens to the scroll view's `scroll` events itself, outside Angular's
|
|
68
|
+
* templates: a template listener would run change detection for every event,
|
|
69
|
+
* many times a second while content moves, where this updates the dock only
|
|
70
|
+
* when it should change. AngularLynx already runs it on Lynx's main thread,
|
|
71
|
+
* beside the native scroll, so it needs no main-thread script.
|
|
72
|
+
*
|
|
73
|
+
* Leaving the screen expands the dock again, so the next screen starts with
|
|
74
|
+
* it whole.
|
|
75
|
+
*/
|
|
76
|
+
@Directive({ selector: 'scroll-view[ui-dock-scroll], list[ui-dock-scroll]' })
|
|
77
|
+
export class UiDockScroll {
|
|
78
|
+
readonly #state = inject(UiDockState);
|
|
79
|
+
readonly #renderer = inject(Renderer2);
|
|
80
|
+
readonly #element = inject(ElementRef).nativeElement;
|
|
81
|
+
|
|
82
|
+
/** The last scroll position, to tell which way content moved. */
|
|
83
|
+
#lastTop = 0;
|
|
84
|
+
/** How far content has moved the same way, negative upward. */
|
|
85
|
+
#travel = 0;
|
|
86
|
+
/** The scroll view's own height, once Lynx has laid it out. */
|
|
87
|
+
#viewport = 0;
|
|
88
|
+
|
|
89
|
+
protected readonly listeners = [
|
|
90
|
+
this.#renderer.listen(
|
|
91
|
+
this.#element,
|
|
92
|
+
'bindscroll',
|
|
93
|
+
(event: { detail: ScrollDetail }) => this.#scrolled(event.detail),
|
|
94
|
+
),
|
|
95
|
+
this.#renderer.listen(
|
|
96
|
+
this.#element,
|
|
97
|
+
'bindlayoutchange',
|
|
98
|
+
(event: { detail: LayoutDetail }) => {
|
|
99
|
+
this.#viewport = event.detail.height;
|
|
100
|
+
},
|
|
101
|
+
),
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
protected readonly cleanup = inject(DestroyRef).onDestroy(() => {
|
|
105
|
+
for (const remove of this.listeners) remove();
|
|
106
|
+
this.#state.minimized.set(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
#scrolled({ scrollTop, scrollHeight }: ScrollDetail): void {
|
|
110
|
+
const delta = scrollTop - this.#lastTop;
|
|
111
|
+
this.#lastTop = scrollTop;
|
|
112
|
+
|
|
113
|
+
// At the top, including iOS's bounce above it, the dock is whole.
|
|
114
|
+
if (scrollTop <= TOP) {
|
|
115
|
+
this.#travel = 0;
|
|
116
|
+
this.#state.minimized.set(false);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// iOS bounces past the end and back, which reads as scrolling up. The
|
|
120
|
+
// user didn't, so the dock stays as it is.
|
|
121
|
+
if (this.#viewport > 0 && scrollTop > scrollHeight - this.#viewport) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Count the distance moved one way, starting again when content turns.
|
|
126
|
+
this.#travel = delta * this.#travel >= 0 ? this.#travel + delta : delta;
|
|
127
|
+
if (this.#travel >= MINIMIZE_AFTER) {
|
|
128
|
+
this.#state.minimized.set(true);
|
|
129
|
+
} else if (this.#travel <= -EXPAND_AFTER) {
|
|
130
|
+
this.#state.minimized.set(false);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|