@umbra.ui/core 0.1.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/dist/components/controls/Dropdown/types.d.ts +5 -0
- package/dist/components/controls/Dropdown/types.d.ts.map +1 -0
- package/dist/components/controls/Dropdown/types.js +1 -0
- package/dist/components/controls/SegmentedControl/types.d.ts +6 -0
- package/dist/components/controls/SegmentedControl/types.d.ts.map +1 -0
- package/dist/components/controls/SegmentedControl/types.js +1 -0
- package/dist/components/dialogs/Alert/types.d.ts +7 -0
- package/dist/components/dialogs/Alert/types.d.ts.map +1 -0
- package/dist/components/dialogs/Alert/types.js +1 -0
- package/dist/components/dialogs/Toast/types.d.ts +34 -0
- package/dist/components/dialogs/Toast/types.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/types.js +10 -0
- package/dist/components/dialogs/Toast/useToast.d.ts +36 -0
- package/dist/components/dialogs/Toast/useToast.d.ts.map +1 -0
- package/dist/components/dialogs/Toast/useToast.js +90 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts +3 -0
- package/dist/components/indicators/Tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/tooltip.js +33 -0
- package/dist/components/indicators/Tooltip/types.d.ts +14 -0
- package/dist/components/indicators/Tooltip/types.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/types.js +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts +18 -0
- package/dist/components/indicators/Tooltip/useTooltip.d.ts.map +1 -0
- package/dist/components/indicators/Tooltip/useTooltip.js +57 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts +14 -0
- package/dist/components/inputs/Tags/tag-bar-styles.d.ts.map +1 -0
- package/dist/components/inputs/Tags/tag-bar-styles.js +313 -0
- package/dist/components/inputs/Tags/types.d.ts +93 -0
- package/dist/components/inputs/Tags/types.d.ts.map +1 -0
- package/dist/components/inputs/Tags/types.js +216 -0
- package/dist/components/inputs/search/types.d.ts +9 -0
- package/dist/components/inputs/search/types.d.ts.map +1 -0
- package/dist/components/inputs/search/types.js +1 -0
- package/dist/components/navigation/adaptive/types.d.ts +16 -0
- package/dist/components/navigation/adaptive/types.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/types.js +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts +27 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useAdaptiveLayout.js +40 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts +6 -0
- package/dist/components/navigation/adaptive/useBreakpoints.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useBreakpoints.js +37 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts +93 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useContainerMonitor.js +145 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts +31 -0
- package/dist/components/navigation/adaptive/useViewAnimation.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewAnimation.js +591 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts +52 -0
- package/dist/components/navigation/adaptive/useViewResize.d.ts.map +1 -0
- package/dist/components/navigation/adaptive/useViewResize.js +146 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts +25 -0
- package/dist/components/navigation/navstack/useNavigationStack.d.ts.map +1 -0
- package/dist/components/navigation/navstack/useNavigationStack.js +133 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts +20 -0
- package/dist/components/navigation/slideover/useSlideoverController.d.ts.map +1 -0
- package/dist/components/navigation/slideover/useSlideoverController.js +267 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts +20 -0
- package/dist/components/navigation/splitview/useSplitViewController.d.ts.map +1 -0
- package/dist/components/navigation/splitview/useSplitViewController.js +325 -0
- package/dist/components/navigation/tabcontroller/types.d.ts +21 -0
- package/dist/components/navigation/tabcontroller/types.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/types.js +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts +5 -0
- package/dist/components/navigation/tabcontroller/useTabController.d.ts.map +1 -0
- package/dist/components/navigation/tabcontroller/useTabController.js +10 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/navigation/types.d.ts.map +1 -0
- package/dist/components/navigation/types.js +1 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts +11 -0
- package/dist/components/pickers/CollectionPicker/types.d.ts.map +1 -0
- package/dist/components/pickers/CollectionPicker/types.js +1 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts +13 -0
- package/dist/components/pickers/ColorPicker/colors.d.ts.map +1 -0
- package/dist/components/pickers/ColorPicker/colors.js +266 -0
- package/dist/components/pickers/FilePicker/types.d.ts +10 -0
- package/dist/components/pickers/FilePicker/types.d.ts.map +1 -0
- package/dist/components/pickers/FilePicker/types.js +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +196 -0
- package/dist/theme.d.ts +73 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +279 -0
- package/dist/themes/blank.d.ts +7 -0
- package/dist/themes/blank.d.ts.map +1 -0
- package/dist/themes/blank.js +543 -0
- package/dist/themes/crimson-dark.d.ts +4 -0
- package/dist/themes/crimson-dark.d.ts.map +1 -0
- package/dist/themes/crimson-dark.js +552 -0
- package/dist/themes/cyan-light.d.ts +4 -0
- package/dist/themes/cyan-light.d.ts.map +1 -0
- package/dist/themes/cyan-light.js +552 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.d.ts.map +1 -0
- package/dist/themes/dark.js +551 -0
- package/dist/themes/gold-dark.d.ts +4 -0
- package/dist/themes/gold-dark.d.ts.map +1 -0
- package/dist/themes/gold-dark.js +552 -0
- package/dist/themes/grass-dark.d.ts +4 -0
- package/dist/themes/grass-dark.d.ts.map +1 -0
- package/dist/themes/grass-dark.js +552 -0
- package/dist/themes/indigo.d.ts +4 -0
- package/dist/themes/indigo.d.ts.map +1 -0
- package/dist/themes/indigo.js +552 -0
- package/dist/themes/light.d.ts +4 -0
- package/dist/themes/light.d.ts.map +1 -0
- package/dist/themes/light.js +551 -0
- package/dist/themes/orange-dark.d.ts +4 -0
- package/dist/themes/orange-dark.d.ts.map +1 -0
- package/dist/themes/orange-dark.js +551 -0
- package/dist/themes/orange-light.d.ts +4 -0
- package/dist/themes/orange-light.d.ts.map +1 -0
- package/dist/themes/orange-light.js +551 -0
- package/package.json +62 -0
- package/src/components/controls/Button/Button.vue +417 -0
- package/src/components/controls/Button/README.md +348 -0
- package/src/components/controls/Button/theme.css +200 -0
- package/src/components/controls/Checkbox/Checkbox.vue +164 -0
- package/src/components/controls/Checkbox/README.md +441 -0
- package/src/components/controls/Checkbox/theme.css +36 -0
- package/src/components/controls/Dropdown/Dropdown.vue +476 -0
- package/src/components/controls/Dropdown/README.md +370 -0
- package/src/components/controls/Dropdown/theme.css +50 -0
- package/src/components/controls/Dropdown/types.ts +6 -0
- package/src/components/controls/IconButton/IconButton.vue +267 -0
- package/src/components/controls/IconButton/README.md +502 -0
- package/src/components/controls/IconButton/theme.css +89 -0
- package/src/components/controls/Radio/README.md +591 -0
- package/src/components/controls/Radio/Radio.vue +89 -0
- package/src/components/controls/Radio/theme.css +14 -0
- package/src/components/controls/RangeSlider/README.md +608 -0
- package/src/components/controls/RangeSlider/RangeSlider.vue +535 -0
- package/src/components/controls/RangeSlider/theme.css +80 -0
- package/src/components/controls/SegmentedControl/README.md +587 -0
- package/src/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
- package/src/components/controls/SegmentedControl/theme.css +60 -0
- package/src/components/controls/SegmentedControl/types.ts +5 -0
- package/src/components/controls/Slider/README.md +627 -0
- package/src/components/controls/Slider/Slider.vue +260 -0
- package/src/components/controls/Slider/theme.css +74 -0
- package/src/components/controls/Stepper/README.md +601 -0
- package/src/components/controls/Stepper/Stepper.vue +103 -0
- package/src/components/controls/Stepper/theme.css +53 -0
- package/src/components/controls/Switch/README.md +667 -0
- package/src/components/controls/Switch/Switch.vue +127 -0
- package/src/components/controls/Switch/theme.css +42 -0
- package/src/components/dialogs/Alert/Alert.vue +218 -0
- package/src/components/dialogs/Alert/README.md +450 -0
- package/src/components/dialogs/Alert/theme.css +44 -0
- package/src/components/dialogs/Alert/types.ts +11 -0
- package/src/components/dialogs/Toast/README.md +522 -0
- package/src/components/dialogs/Toast/Toast.vue +296 -0
- package/src/components/dialogs/Toast/ToastContainer.vue +330 -0
- package/src/components/dialogs/Toast/theme.css +44 -0
- package/src/components/dialogs/Toast/types.ts +46 -0
- package/src/components/dialogs/Toast/useToast.ts +127 -0
- package/src/components/indicators/ProgressBar/ProgressBar.vue +98 -0
- package/src/components/indicators/ProgressBar/README.md +744 -0
- package/src/components/indicators/ProgressBar/theme.css +36 -0
- package/src/components/indicators/Tooltip/README.md +723 -0
- package/src/components/indicators/Tooltip/TooltipProvider.vue +142 -0
- package/src/components/indicators/Tooltip/theme.css +18 -0
- package/src/components/indicators/Tooltip/tooltip.ts +48 -0
- package/src/components/indicators/Tooltip/types.ts +15 -0
- package/src/components/indicators/Tooltip/useTooltip.ts +71 -0
- package/src/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
- package/src/components/inputs/AutogrowTextView/README.md +643 -0
- package/src/components/inputs/AutogrowTextView/theme.css +28 -0
- package/src/components/inputs/InputCard/InputCard.vue +600 -0
- package/src/components/inputs/InputCard/README.md +636 -0
- package/src/components/inputs/InputEmail/InputEmail.vue +698 -0
- package/src/components/inputs/InputEmail/README.md +764 -0
- package/src/components/inputs/InputNumber/InputNumber.vue +300 -0
- package/src/components/inputs/InputNumber/README.md +749 -0
- package/src/components/inputs/InputPhone/InputPhone.vue +645 -0
- package/src/components/inputs/InputPhone/README.md +636 -0
- package/src/components/inputs/InputSecure/InputSecure.vue +646 -0
- package/src/components/inputs/InputSecure/README.md +771 -0
- package/src/components/inputs/InputText/InputText.vue +225 -0
- package/src/components/inputs/InputText/README.md +844 -0
- package/src/components/inputs/OTP/OTP.vue +349 -0
- package/src/components/inputs/OTP/README.md +736 -0
- package/src/components/inputs/OTP/theme.css +50 -0
- package/src/components/inputs/StringCapture/README.md +718 -0
- package/src/components/inputs/StringCapture/StringCapture.vue +315 -0
- package/src/components/inputs/StringCapture/theme.css +86 -0
- package/src/components/inputs/Tags/README.md +897 -0
- package/src/components/inputs/Tags/TagBar.vue +793 -0
- package/src/components/inputs/Tags/TagCreation.vue +219 -0
- package/src/components/inputs/Tags/TagPicker.vue +380 -0
- package/src/components/inputs/Tags/tag-bar-styles.ts +354 -0
- package/src/components/inputs/Tags/theme.css +121 -0
- package/src/components/inputs/Tags/types.ts +346 -0
- package/src/components/inputs/search/README.md +759 -0
- package/src/components/inputs/search/SearchBar.vue +394 -0
- package/src/components/inputs/search/SearchResults.vue +310 -0
- package/src/components/inputs/search/theme.css +187 -0
- package/src/components/inputs/search/types.ts +8 -0
- package/src/components/inputs/theme.css +102 -0
- package/src/components/menus/ActionMenu/ActionMenu.vue +383 -0
- package/src/components/menus/ActionMenu/README.md +825 -0
- package/src/components/menus/ActionMenu/theme.css +93 -0
- package/src/components/models/Popover/Popover.vue +551 -0
- package/src/components/models/Popover/README.md +885 -0
- package/src/components/models/Popover/theme.css +52 -0
- package/src/components/models/Sheet/README.md +1159 -0
- package/src/components/models/Sheet/Sheet.vue +465 -0
- package/src/components/models/Sheet/theme.css +72 -0
- package/src/components/models/Sidebar/README.md +1228 -0
- package/src/components/models/Sidebar/Sidebar.vue +480 -0
- package/src/components/models/Sidebar/theme.css +90 -0
- package/src/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
- package/src/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
- package/src/components/navigation/adaptive/README.md +768 -0
- package/src/components/navigation/adaptive/types.ts +19 -0
- package/src/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
- package/src/components/navigation/adaptive/useBreakpoints.ts +41 -0
- package/src/components/navigation/adaptive/useContainerMonitor.ts +214 -0
- package/src/components/navigation/adaptive/useViewAnimation.ts +721 -0
- package/src/components/navigation/adaptive/useViewResize.ts +211 -0
- package/src/components/navigation/navstack/NavigationStack.vue +180 -0
- package/src/components/navigation/navstack/README.md +994 -0
- package/src/components/navigation/navstack/useNavigationStack.ts +164 -0
- package/src/components/navigation/slideover/README.md +1275 -0
- package/src/components/navigation/slideover/SlideoverController.vue +287 -0
- package/src/components/navigation/slideover/useSlideoverController.ts +320 -0
- package/src/components/navigation/splitview/README.md +1115 -0
- package/src/components/navigation/splitview/SplitViewController.vue +176 -0
- package/src/components/navigation/splitview/useSplitViewController.ts +388 -0
- package/src/components/navigation/tabcontroller/README.md +919 -0
- package/src/components/navigation/tabcontroller/TabController.vue +307 -0
- package/src/components/navigation/tabcontroller/TabItem.vue +57 -0
- package/src/components/navigation/tabcontroller/types.ts +24 -0
- package/src/components/navigation/tabcontroller/useTabController.ts +18 -0
- package/src/components/navigation/theme.css +91 -0
- package/src/components/navigation/types.ts +7 -0
- package/src/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
- package/src/components/pickers/CollectionPicker/README.md +1115 -0
- package/src/components/pickers/CollectionPicker/theme.css +14 -0
- package/src/components/pickers/CollectionPicker/types.ts +11 -0
- package/src/components/pickers/ColorPicker/ColorPicker.vue +376 -0
- package/src/components/pickers/ColorPicker/README.md +1439 -0
- package/src/components/pickers/ColorPicker/colors.ts +299 -0
- package/src/components/pickers/ColorPicker/theme.css +32 -0
- package/src/components/pickers/DatePicker/DatePicker.vue +660 -0
- package/src/components/pickers/DatePicker/README.md +1195 -0
- package/src/components/pickers/DatePicker/theme.css +22 -0
- package/src/components/pickers/FilePicker/FilePicker.vue +534 -0
- package/src/components/pickers/FilePicker/README.md +1542 -0
- package/src/components/pickers/FilePicker/theme.css +48 -0
- package/src/components/pickers/FilePicker/types.ts +10 -0
- package/src/components/pickers/IconPicker/IconPicker.vue +327 -0
- package/src/components/pickers/IconPicker/README.md +1161 -0
- package/src/components/pickers/IconPicker/theme.css +28 -0
- package/src/components/pickers/theme.css +82 -0
- package/src/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
- package/src/components/views/MarkdownViewer/README.md +833 -0
- package/src/components/views/MarkdownViewer/theme.css +130 -0
- package/src/index.ts +263 -0
- package/src/theme.ts +378 -0
- package/src/themes/crimson-dark.ts +556 -0
- package/src/themes/cyan-light.ts +556 -0
- package/src/themes/dark.ts +557 -0
- package/src/themes/gold-dark.ts +556 -0
- package/src/themes/grass-dark.ts +556 -0
- package/src/themes/indigo.ts +556 -0
- package/src/themes/light.ts +557 -0
- package/src/themes/orange-dark.ts +557 -0
- package/src/themes/orange-light.ts +557 -0
- package/src/vue.d.ts +45 -0
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
import { nextTick, ref, type Ref } from "vue";
|
|
2
|
+
import { Flip } from "gsap/Flip";
|
|
3
|
+
import gsap from "gsap";
|
|
4
|
+
import { InternalView } from "./types";
|
|
5
|
+
|
|
6
|
+
gsap.registerPlugin(Flip);
|
|
7
|
+
|
|
8
|
+
const animationInProgress = ref<boolean>(false);
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
# FLIP Order of Operations
|
|
12
|
+
Step 1: Get State
|
|
13
|
+
Step 3: Manipulate DOM
|
|
14
|
+
Step 4: Animate
|
|
15
|
+
Step 5: Update Data (vue reactive state)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export const useViewAnimation = (
|
|
19
|
+
views: Ref<InternalView[]>,
|
|
20
|
+
instanceKey: string,
|
|
21
|
+
containerDimensions: Ref<{ width: number; height: number }>,
|
|
22
|
+
padding: string,
|
|
23
|
+
gap: string
|
|
24
|
+
) => {
|
|
25
|
+
/*
|
|
26
|
+
* Basic animation function
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const animate = async (
|
|
30
|
+
targets: HTMLElement[],
|
|
31
|
+
manipulateDOMFn: () => void,
|
|
32
|
+
updateDataFn: () => void
|
|
33
|
+
) => {
|
|
34
|
+
if (animationInProgress.value) {
|
|
35
|
+
console.warn("Animation already in progress");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
animationInProgress.value = true;
|
|
39
|
+
// Step 1: Get State
|
|
40
|
+
const state = Flip.getState(targets);
|
|
41
|
+
|
|
42
|
+
// Step 2: Manipulate DOM
|
|
43
|
+
manipulateDOMFn();
|
|
44
|
+
|
|
45
|
+
// Step 3: Animate
|
|
46
|
+
return Flip.from(state, {
|
|
47
|
+
duration: 0.3,
|
|
48
|
+
ease: "power1.inOut",
|
|
49
|
+
absolute: true,
|
|
50
|
+
onComplete: () => {
|
|
51
|
+
animationInProgress.value = false;
|
|
52
|
+
},
|
|
53
|
+
}).then(() => {
|
|
54
|
+
// Step 5: Update Data
|
|
55
|
+
updateDataFn();
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
Utility Functions
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
// Helper functions to get unique element IDs
|
|
64
|
+
const getOffscreenLeadingId = () => `${instanceKey}-offscreen-leading`;
|
|
65
|
+
const getOffscreenTrailingId = () => `${instanceKey}-offscreen-trailing`;
|
|
66
|
+
const getOnscreenId = () => `${instanceKey}-onscreen`;
|
|
67
|
+
const getViewId = (view: InternalView) => `${instanceKey}-view-${view.id}`;
|
|
68
|
+
const getDarkenId = () => `${instanceKey}-darken`;
|
|
69
|
+
const getOverlayId = () => `${instanceKey}-overlay`;
|
|
70
|
+
|
|
71
|
+
const getViewElements = (): HTMLElement[] => {
|
|
72
|
+
return views.value
|
|
73
|
+
.map((view) => document.getElementById(getViewId(view)))
|
|
74
|
+
.filter((element): element is HTMLElement => element !== null);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getAllViewsBefore = (id: string): InternalView[] => {
|
|
78
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
79
|
+
return views.value.slice(0, targetIndex);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getAllViewsBeforeIndex = (index: number): InternalView[] => {
|
|
83
|
+
return views.value.slice(0, index);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const getAllViewsAfterIndex = (index: number): InternalView[] => {
|
|
87
|
+
return views.value.slice(index + 1);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const getAllViewsAfter = (id: string): InternalView[] => {
|
|
91
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
92
|
+
|
|
93
|
+
if (targetIndex === -1) {
|
|
94
|
+
return []; // View not found
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return views.value.slice(targetIndex + 1);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const getAllViewsAfterWithLocation = (
|
|
101
|
+
id: string,
|
|
102
|
+
location: string
|
|
103
|
+
): InternalView[] => {
|
|
104
|
+
const viewsAfter = getAllViewsAfter(id);
|
|
105
|
+
return viewsAfter.filter((view) => view.location === location);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getAllViewElementsAfterWithLocation = (
|
|
109
|
+
id: string,
|
|
110
|
+
location: string
|
|
111
|
+
): HTMLElement[] => {
|
|
112
|
+
const viewsAfter = getAllViewsAfterWithLocation(id, location);
|
|
113
|
+
|
|
114
|
+
// Map to HTMLElements and filter out null values
|
|
115
|
+
return viewsAfter
|
|
116
|
+
.map((view) => document.getElementById(getViewId(view)))
|
|
117
|
+
.filter((element): element is HTMLElement => element !== null);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const getAllViewElementsBefore = (id: string): HTMLElement[] => {
|
|
121
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
122
|
+
|
|
123
|
+
if (targetIndex === -1) {
|
|
124
|
+
return []; // View not found
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get all views before the target index
|
|
128
|
+
const precedingViews = views.value.slice(0, targetIndex);
|
|
129
|
+
|
|
130
|
+
// Map to HTMLElements and filter out null values
|
|
131
|
+
return precedingViews
|
|
132
|
+
.map((view) => document.getElementById(getViewId(view)))
|
|
133
|
+
.filter((element): element is HTMLElement => element !== null);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const getSingleViewBefore = (id: string): InternalView | null => {
|
|
137
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
138
|
+
|
|
139
|
+
if (targetIndex === -1 || targetIndex === 0) {
|
|
140
|
+
return null; // View not found or is first view
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return views.value[targetIndex - 1];
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const getSingleViewAfter = (id: string): InternalView | null => {
|
|
147
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
148
|
+
if (targetIndex === -1 || targetIndex === views.value.length - 1) {
|
|
149
|
+
return null; // View not found or is last view
|
|
150
|
+
}
|
|
151
|
+
return views.value[targetIndex + 1];
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const getSingleViewElementBefore = (id: string): HTMLElement | null => {
|
|
155
|
+
const precedingView = getSingleViewBefore(id);
|
|
156
|
+
|
|
157
|
+
if (!precedingView) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return document.getElementById(getViewId(precedingView));
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const isOnscreen = (view: InternalView) => {
|
|
165
|
+
return view.location === "onscreen";
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const hasPrecedingViews = (id: string, location: string) => {
|
|
169
|
+
const targetIndex = views.value.findIndex((view) => view.id === id);
|
|
170
|
+
if (targetIndex === -1) {
|
|
171
|
+
return false; // View not found
|
|
172
|
+
}
|
|
173
|
+
// Check if ANY preceding view has the specified location
|
|
174
|
+
return views.value
|
|
175
|
+
.slice(0, targetIndex)
|
|
176
|
+
.some((view) => view.location === location);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const calculateContentWidth = (
|
|
180
|
+
containerWidth: number,
|
|
181
|
+
paddingString: string
|
|
182
|
+
): number => {
|
|
183
|
+
// Handle empty or invalid padding
|
|
184
|
+
if (!paddingString || paddingString === "0") {
|
|
185
|
+
return containerWidth;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Split padding string by spaces and filter out empty strings
|
|
189
|
+
const values = paddingString
|
|
190
|
+
.trim()
|
|
191
|
+
.split(/\s+/)
|
|
192
|
+
.map((v) => parseFloat(v));
|
|
193
|
+
|
|
194
|
+
// Determine horizontal padding based on number of values
|
|
195
|
+
let horizontalPadding = 0;
|
|
196
|
+
|
|
197
|
+
switch (values.length) {
|
|
198
|
+
case 1:
|
|
199
|
+
// padding: 10px (all sides)
|
|
200
|
+
horizontalPadding = values[0] * 2;
|
|
201
|
+
break;
|
|
202
|
+
case 2:
|
|
203
|
+
// padding: 10px 20px (vertical horizontal)
|
|
204
|
+
horizontalPadding = values[1] * 2;
|
|
205
|
+
break;
|
|
206
|
+
case 3:
|
|
207
|
+
// padding: 10px 20px 15px (top horizontal bottom)
|
|
208
|
+
horizontalPadding = values[1] * 2;
|
|
209
|
+
break;
|
|
210
|
+
case 4:
|
|
211
|
+
// padding: 10px 20px 15px 25px (top right bottom left)
|
|
212
|
+
horizontalPadding = values[1] + values[3];
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return containerWidth - horizontalPadding;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const getFirstViewInOnscreen = () => {
|
|
220
|
+
return views.value.find((v) => v.location === "onscreen");
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const getFirstViewInOverlay = () => {
|
|
224
|
+
return views.value.find((v) => v.location === "overlay");
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* Internal Functions: Splitview
|
|
229
|
+
For Splitview:
|
|
230
|
+
- show presents view(s) onscreen from the left.
|
|
231
|
+
- hide dismisses view(s) to offscreenfrom the left.
|
|
232
|
+
- push presents a view from the left.
|
|
233
|
+
- pop dismisses a view to the left.
|
|
234
|
+
*/
|
|
235
|
+
|
|
236
|
+
type NavigationType = "push" | "pop" | "show" | "hide";
|
|
237
|
+
|
|
238
|
+
const splitViewShow = async (id: string) => {
|
|
239
|
+
const view = views.value.find((v) => v.id === id);
|
|
240
|
+
if (view?.location === "onscreen") return;
|
|
241
|
+
await splitViewNavigate(id, "show");
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const splitViewHide = async (id: string) => {
|
|
245
|
+
// Prevent hiding the last view (would result in nothing being shown)
|
|
246
|
+
const viewIndex = views.value.findIndex((view) => view.id === id);
|
|
247
|
+
if (viewIndex === views.value.length - 1) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
await splitViewNavigate(id, "hide");
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const splitViewPush = async (id: string | null = null) => {
|
|
255
|
+
// if id is provided, push from that id
|
|
256
|
+
if (id) {
|
|
257
|
+
await splitViewNavigate(id, "push");
|
|
258
|
+
return;
|
|
259
|
+
} else {
|
|
260
|
+
const firstInOnscreen = getFirstViewInOnscreen()?.id;
|
|
261
|
+
if (!firstInOnscreen) {
|
|
262
|
+
console.error("No view to push from");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
await splitViewNavigate(firstInOnscreen, "push");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const splitViewPop = async (id: string | null = null) => {
|
|
271
|
+
// if id is provided, pop from that id
|
|
272
|
+
if (id) {
|
|
273
|
+
await splitViewNavigate(id, "pop");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
// if id is not provided, pop from the view to the right of the first view in onscreen (yes, I know it's a little weird)
|
|
277
|
+
else {
|
|
278
|
+
const firstInOnscreen = getFirstViewInOnscreen()?.id;
|
|
279
|
+
if (!firstInOnscreen) return;
|
|
280
|
+
const nextInOnscreen = getSingleViewAfter(firstInOnscreen)?.id;
|
|
281
|
+
if (!nextInOnscreen) {
|
|
282
|
+
console.warn("nothing left to pop from");
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
await splitViewNavigate(nextInOnscreen, "pop");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const splitViewNavigate = async (id: string, type: NavigationType) => {
|
|
291
|
+
const elements = getViewElements();
|
|
292
|
+
|
|
293
|
+
// Get the appropriate view elements based on type
|
|
294
|
+
let viewElements: (HTMLElement | null | undefined)[] = [];
|
|
295
|
+
|
|
296
|
+
switch (type) {
|
|
297
|
+
case "push":
|
|
298
|
+
viewElements = [getSingleViewElementBefore(id)];
|
|
299
|
+
break;
|
|
300
|
+
case "pop":
|
|
301
|
+
viewElements = getAllViewElementsBefore(id);
|
|
302
|
+
break;
|
|
303
|
+
case "show":
|
|
304
|
+
// Get the view with the given id AND all views after it that have location "leading"
|
|
305
|
+
const currentView = document.getElementById(
|
|
306
|
+
getViewId(views.value.find((v) => v.id === id)!)
|
|
307
|
+
);
|
|
308
|
+
const viewsAfterWithLeading = getAllViewElementsAfterWithLocation(
|
|
309
|
+
id,
|
|
310
|
+
"leading"
|
|
311
|
+
);
|
|
312
|
+
viewElements = [currentView, ...viewsAfterWithLeading];
|
|
313
|
+
break;
|
|
314
|
+
case "hide":
|
|
315
|
+
// Get the current view AND all views before it
|
|
316
|
+
const hideCurrentView = document.getElementById(
|
|
317
|
+
getViewId(views.value.find((v) => v.id === id)!)
|
|
318
|
+
);
|
|
319
|
+
viewElements = [hideCurrentView, ...getAllViewElementsBefore(id)];
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Early return for push if no element found
|
|
324
|
+
if (type === "push" && !viewElements[0]) return;
|
|
325
|
+
|
|
326
|
+
const manipulateDOM = () => {
|
|
327
|
+
switch (type) {
|
|
328
|
+
case "push": {
|
|
329
|
+
const onscreen = document.getElementById(getOnscreenId());
|
|
330
|
+
if (!onscreen) return;
|
|
331
|
+
|
|
332
|
+
const viewElement = viewElements[0];
|
|
333
|
+
if (viewElement) {
|
|
334
|
+
viewElement.parentNode?.removeChild(viewElement);
|
|
335
|
+
viewElement.style.order = "";
|
|
336
|
+
onscreen.insertBefore(viewElement, onscreen.children[0] || null);
|
|
337
|
+
}
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
case "pop": {
|
|
342
|
+
const offscreenLeading = document.getElementById(
|
|
343
|
+
getOffscreenLeadingId()
|
|
344
|
+
);
|
|
345
|
+
if (!offscreenLeading) return;
|
|
346
|
+
|
|
347
|
+
viewElements.forEach((view) => {
|
|
348
|
+
if (view) {
|
|
349
|
+
view.parentNode?.removeChild(view);
|
|
350
|
+
offscreenLeading.appendChild(view);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
case "show": {
|
|
357
|
+
const onscreen = document.getElementById(getOnscreenId());
|
|
358
|
+
if (!onscreen) return;
|
|
359
|
+
|
|
360
|
+
// Show the view with the given id and all views after it that have location "leading"
|
|
361
|
+
// Add them at the beginning of onscreen in reverse order to maintain correct sequence
|
|
362
|
+
viewElements.reverse().forEach((view) => {
|
|
363
|
+
if (view) {
|
|
364
|
+
view.parentNode?.removeChild(view);
|
|
365
|
+
view.style.order = "";
|
|
366
|
+
onscreen.insertBefore(view, onscreen.children[0] || null);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
case "hide": {
|
|
373
|
+
const offscreenLeading = document.getElementById(
|
|
374
|
+
getOffscreenLeadingId()
|
|
375
|
+
);
|
|
376
|
+
if (!offscreenLeading) return;
|
|
377
|
+
|
|
378
|
+
// Hide the current view and all views before it
|
|
379
|
+
viewElements.forEach((view) => {
|
|
380
|
+
if (view) {
|
|
381
|
+
view.parentNode?.removeChild(view);
|
|
382
|
+
offscreenLeading.appendChild(view);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const updateData = async () => {
|
|
391
|
+
switch (type) {
|
|
392
|
+
case "push": {
|
|
393
|
+
const prevIndex = views.value.findIndex(
|
|
394
|
+
(view) => view.id === getSingleViewBefore(id)?.id
|
|
395
|
+
);
|
|
396
|
+
views.value[prevIndex].location = "onscreen";
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
case "pop": {
|
|
401
|
+
const beforeViews = getAllViewsBefore(id);
|
|
402
|
+
beforeViews.forEach((view) => {
|
|
403
|
+
view.location = "leading";
|
|
404
|
+
});
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
case "show": {
|
|
409
|
+
// Update the view with the given id to be onscreen
|
|
410
|
+
const currentViewIndex = views.value.findIndex((v) => v.id === id);
|
|
411
|
+
if (currentViewIndex !== -1) {
|
|
412
|
+
views.value[currentViewIndex].location = "onscreen";
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Update all views after the given id that have location "leading" to be onscreen
|
|
416
|
+
const viewsAfterWithLeading = getAllViewsAfterWithLocation(
|
|
417
|
+
id,
|
|
418
|
+
"leading"
|
|
419
|
+
);
|
|
420
|
+
viewsAfterWithLeading.forEach((view) => {
|
|
421
|
+
view.location = "onscreen";
|
|
422
|
+
});
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
case "hide": {
|
|
427
|
+
// Update the current view and all views before it to be leading/offscreen
|
|
428
|
+
const currentViewIndex = views.value.findIndex((v) => v.id === id);
|
|
429
|
+
if (currentViewIndex !== -1) {
|
|
430
|
+
views.value[currentViewIndex].location = "leading";
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const beforeViews = getAllViewsBefore(id);
|
|
434
|
+
beforeViews.forEach((view) => {
|
|
435
|
+
view.location = "leading";
|
|
436
|
+
});
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
await animate(elements, manipulateDOM, updateData);
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
/*
|
|
446
|
+
* Internal Functions: Slideover
|
|
447
|
+
For Slideover:
|
|
448
|
+
- show presents the overlay and the view(s) from the left.
|
|
449
|
+
- hide dismisses the overlay and its views.
|
|
450
|
+
- push presents another view to the overlay from the left.
|
|
451
|
+
- pop dismisses a view from the overlay to the left.
|
|
452
|
+
*/
|
|
453
|
+
|
|
454
|
+
const slideoverShow = async (id: string) => {
|
|
455
|
+
// Get the view with the given id AND all views after it that have location "leading"
|
|
456
|
+
const currentView = views.value.find((v) => v.id === id);
|
|
457
|
+
if (currentView?.location === "onscreen") {
|
|
458
|
+
console.warn("This view is already onscreen.");
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const viewsAfterWithLeading = getAllViewsAfterWithLocation(id, "leading");
|
|
462
|
+
const viewsToShow = [currentView, ...viewsAfterWithLeading];
|
|
463
|
+
|
|
464
|
+
for (const view of viewsToShow) {
|
|
465
|
+
if (view) {
|
|
466
|
+
view.location = "overlay";
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
await nextTick();
|
|
471
|
+
|
|
472
|
+
const overlay = document.getElementById(getOverlayId());
|
|
473
|
+
if (!overlay) return;
|
|
474
|
+
isOverlayOpen.value = true;
|
|
475
|
+
overlay.style.pointerEvents = "auto";
|
|
476
|
+
overlay.style.transform = "translateX(0)";
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const slideoverHide = async () => {
|
|
480
|
+
const overlay = document.getElementById(getOverlayId());
|
|
481
|
+
if (!overlay) return;
|
|
482
|
+
isOverlayOpen.value = false;
|
|
483
|
+
overlay.style.pointerEvents = "none";
|
|
484
|
+
overlay.style.transform = "translateX(calc((110% + 10px) * -1))";
|
|
485
|
+
|
|
486
|
+
setTimeout(() => {
|
|
487
|
+
for (const view of views.value) {
|
|
488
|
+
if (!view) return;
|
|
489
|
+
if (view.location === "overlay") {
|
|
490
|
+
view.location = "leading";
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}, 330);
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const slideoverPush = async (id: string | null = null) => {
|
|
497
|
+
let viewId = id;
|
|
498
|
+
if (!viewId) {
|
|
499
|
+
const firstInOnscreen = getFirstViewInOnscreen()?.id;
|
|
500
|
+
if (!firstInOnscreen) return;
|
|
501
|
+
const prevView = getSingleViewBefore(firstInOnscreen);
|
|
502
|
+
if (!prevView) {
|
|
503
|
+
console.warn("no more views to push to");
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
viewId = prevView.id;
|
|
507
|
+
}
|
|
508
|
+
// exit and show the overlay if it's not open
|
|
509
|
+
if (!isOverlayOpen.value) {
|
|
510
|
+
slideoverShow(viewId);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// get the elements
|
|
515
|
+
const overlay = document.getElementById(getOverlayId());
|
|
516
|
+
if (!overlay) return;
|
|
517
|
+
const leadingViews = views.value
|
|
518
|
+
.filter((view) => view.location === "leading")
|
|
519
|
+
.map((view) => document.getElementById(getViewId(view)))
|
|
520
|
+
.filter((el): el is HTMLElement => el !== null);
|
|
521
|
+
const overlayViews = views.value
|
|
522
|
+
.filter((view) => view.location === "overlay")
|
|
523
|
+
.map((view) => document.getElementById(getViewId(view)))
|
|
524
|
+
.filter((el): el is HTMLElement => el !== null);
|
|
525
|
+
const targets = [...leadingViews, ...overlayViews, overlay];
|
|
526
|
+
|
|
527
|
+
// manupulate the DOM
|
|
528
|
+
const manipulateDOM = () => {
|
|
529
|
+
const view = getSingleViewElementBefore(viewId);
|
|
530
|
+
if (!view) return;
|
|
531
|
+
view.parentNode?.removeChild(view);
|
|
532
|
+
view.style.order = "";
|
|
533
|
+
overlay.insertBefore(view, overlay.children[0] || null);
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// update the data
|
|
537
|
+
const updateData = () => {
|
|
538
|
+
const data = getSingleViewBefore(viewId);
|
|
539
|
+
if (!data) return;
|
|
540
|
+
data.location = "overlay";
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
animate(targets, manipulateDOM, updateData);
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
const slideoverPop = async (id: string | null = null) => {
|
|
547
|
+
// exit if the overlay is not open
|
|
548
|
+
if (!isOverlayOpen.value) {
|
|
549
|
+
console.warn("No views to pop from");
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
// if id is provided, pop from that id
|
|
553
|
+
let viewId = id;
|
|
554
|
+
// if id is not provided, pop from the view to the right of the first view in overlay
|
|
555
|
+
if (!viewId) {
|
|
556
|
+
const firstInOverlay = getFirstViewInOverlay()?.id;
|
|
557
|
+
if (!firstInOverlay) return;
|
|
558
|
+
const nextView = getSingleViewAfter(firstInOverlay);
|
|
559
|
+
if (!nextView) {
|
|
560
|
+
console.warn("nothing left to pop from");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
// if the next view is not in overlay, dismiss the overlay (since we are at the end)
|
|
564
|
+
if (nextView.location !== "overlay") {
|
|
565
|
+
console.warn("No more views in overlay... dismissing");
|
|
566
|
+
slideoverHide();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
viewId = nextView.id;
|
|
570
|
+
}
|
|
571
|
+
const leading = document.getElementById(getOffscreenLeadingId());
|
|
572
|
+
const overlay = document.getElementById(getOverlayId());
|
|
573
|
+
if (!leading || !overlay) {
|
|
574
|
+
console.error("Elements are null");
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const elements = getViewElements();
|
|
578
|
+
const before = getAllViewElementsBefore(viewId);
|
|
579
|
+
|
|
580
|
+
const targets = [...elements, overlay];
|
|
581
|
+
|
|
582
|
+
const manipulateDOM = () => {
|
|
583
|
+
const offscreenLeading = document.getElementById(getOffscreenLeadingId());
|
|
584
|
+
if (!offscreenLeading) return;
|
|
585
|
+
leading.style.zIndex = "10";
|
|
586
|
+
before.forEach((view) => {
|
|
587
|
+
view.parentNode?.removeChild(view);
|
|
588
|
+
offscreenLeading.appendChild(view);
|
|
589
|
+
});
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const updateData = () => {
|
|
593
|
+
const beforeViews = getAllViewsBefore(viewId);
|
|
594
|
+
beforeViews.forEach((view) => {
|
|
595
|
+
view.location = "leading";
|
|
596
|
+
});
|
|
597
|
+
leading.style.zIndex = "";
|
|
598
|
+
};
|
|
599
|
+
await animate(targets, manipulateDOM, updateData);
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
/*
|
|
603
|
+
* Internal Functions: Navstack
|
|
604
|
+
For Navstack:
|
|
605
|
+
- show presents any view fullscreen from either the left or the right depending on location in the stack
|
|
606
|
+
- push presents next view fullscreen from the right, and dismisses current view to the left.
|
|
607
|
+
- pop dismisses current view to the right, and pushes preceeding view fullscreen from the left.
|
|
608
|
+
*/
|
|
609
|
+
|
|
610
|
+
const navstackShow = async (id: string) => {
|
|
611
|
+
const index = views.value.findIndex((view) => view.id === id);
|
|
612
|
+
navstackNavigateTo(index);
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
const navstackPush = async () => {
|
|
616
|
+
const currentIndex = views.value.findIndex(
|
|
617
|
+
(view) => view.location === "onscreen"
|
|
618
|
+
);
|
|
619
|
+
navstackNavigateTo(currentIndex + 1);
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
const navstackPop = async (id: string) => {
|
|
623
|
+
const currentIndex = views.value.findIndex(
|
|
624
|
+
(view) => view.location === "onscreen"
|
|
625
|
+
);
|
|
626
|
+
navstackNavigateTo(currentIndex - 1);
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const navstackNavigateTo = async (index: number) => {
|
|
630
|
+
const onscreen = document.getElementById(getOnscreenId());
|
|
631
|
+
const offscreenLeading = document.getElementById(getOffscreenLeadingId());
|
|
632
|
+
const offscreenTrailing = document.getElementById(getOffscreenTrailingId());
|
|
633
|
+
if (!onscreen || !offscreenLeading || !offscreenTrailing) return;
|
|
634
|
+
const currentIndex = views.value.findIndex(
|
|
635
|
+
(view) => view.location === "onscreen"
|
|
636
|
+
);
|
|
637
|
+
if (currentIndex === -1) return;
|
|
638
|
+
const oldView = views.value[currentIndex];
|
|
639
|
+
const newView = views.value[index];
|
|
640
|
+
|
|
641
|
+
// Ensure index is within bounds
|
|
642
|
+
if (index < 0 || index >= views.value.length) {
|
|
643
|
+
console.warn(`Navigation index ${index} out of bounds`);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const currentView = document.getElementById(getViewId(oldView));
|
|
648
|
+
if (!currentView) return;
|
|
649
|
+
|
|
650
|
+
const nextView = document.getElementById(getViewId(newView));
|
|
651
|
+
if (!nextView) return;
|
|
652
|
+
|
|
653
|
+
// determine which offscreen container to use
|
|
654
|
+
const offscreenContainerOutflow =
|
|
655
|
+
index > currentIndex ? offscreenLeading : offscreenTrailing;
|
|
656
|
+
|
|
657
|
+
const targets = [currentView, nextView];
|
|
658
|
+
const manipulateDOM = () => {
|
|
659
|
+
currentView.style.width = `${calculateContentWidth(
|
|
660
|
+
containerDimensions.value.width,
|
|
661
|
+
padding
|
|
662
|
+
)}px`;
|
|
663
|
+
nextView.style.width = `${calculateContentWidth(
|
|
664
|
+
containerDimensions.value.width,
|
|
665
|
+
padding
|
|
666
|
+
)}px`;
|
|
667
|
+
currentView.parentNode?.removeChild(currentView);
|
|
668
|
+
offscreenContainerOutflow.appendChild(currentView);
|
|
669
|
+
nextView.parentNode?.removeChild(nextView);
|
|
670
|
+
onscreen.appendChild(nextView);
|
|
671
|
+
};
|
|
672
|
+
const updateData = () => {
|
|
673
|
+
// set up all views before the new view to leading
|
|
674
|
+
const prevViews = getAllViewsBeforeIndex(index);
|
|
675
|
+
prevViews.forEach((view) => {
|
|
676
|
+
view.location = "leading";
|
|
677
|
+
});
|
|
678
|
+
// set up all views after the new view to trailing
|
|
679
|
+
const nextViews = getAllViewsAfterIndex(index);
|
|
680
|
+
nextViews.forEach((view) => {
|
|
681
|
+
view.location = "trailing";
|
|
682
|
+
});
|
|
683
|
+
// set up the new view to onscreen
|
|
684
|
+
newView.location = "onscreen";
|
|
685
|
+
currentView.style.width = "";
|
|
686
|
+
nextView.style.width = "";
|
|
687
|
+
};
|
|
688
|
+
await animate(targets, manipulateDOM, updateData);
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
/*
|
|
692
|
+
State
|
|
693
|
+
*/
|
|
694
|
+
const isOverlayOpen = ref(false);
|
|
695
|
+
|
|
696
|
+
return {
|
|
697
|
+
splitViewShow,
|
|
698
|
+
splitViewHide,
|
|
699
|
+
splitViewPush,
|
|
700
|
+
splitViewPop,
|
|
701
|
+
slideoverShow,
|
|
702
|
+
slideoverHide,
|
|
703
|
+
slideoverPush,
|
|
704
|
+
slideoverPop,
|
|
705
|
+
navstackShow,
|
|
706
|
+
navstackPush,
|
|
707
|
+
navstackPop,
|
|
708
|
+
getOffscreenLeadingId,
|
|
709
|
+
getOffscreenTrailingId,
|
|
710
|
+
getOnscreenId,
|
|
711
|
+
getViewId,
|
|
712
|
+
getDarkenId,
|
|
713
|
+
getOverlayId,
|
|
714
|
+
getViewElements,
|
|
715
|
+
isOnscreen,
|
|
716
|
+
hasPrecedingViews,
|
|
717
|
+
isOverlayOpen,
|
|
718
|
+
getSingleViewBefore,
|
|
719
|
+
getSingleViewAfter,
|
|
720
|
+
};
|
|
721
|
+
};
|