@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,1115 @@
|
|
|
1
|
+
# SplitViewController
|
|
2
|
+
|
|
3
|
+
A powerful split-view navigation component built with Vue 3 Composition API and TypeScript. The SplitViewController provides smooth, animated transitions between different views using GSAP's FLIP (First, Last, Invert, Play) animation technique, creating an intuitive side-by-side interface perfect for desktop applications and complex layouts.
|
|
4
|
+
|
|
5
|
+
## Installation/Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { SplitViewController, useSplitViewController } from "@umbra-ui/core";
|
|
9
|
+
import type { Pane } from "@umbra-ui/core";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Dependencies:**
|
|
13
|
+
|
|
14
|
+
- Vue 3.x
|
|
15
|
+
- gsap (for animations)
|
|
16
|
+
- gsap/Flip (for FLIP animations)
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```vue
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { ref } from "vue";
|
|
23
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
24
|
+
import SidebarView from "./SidebarView.vue";
|
|
25
|
+
import ContentView from "./ContentView.vue";
|
|
26
|
+
import DetailsView from "./DetailsView.vue";
|
|
27
|
+
|
|
28
|
+
// Define your split-view panes
|
|
29
|
+
const panes = ref([
|
|
30
|
+
{
|
|
31
|
+
name: "Sidebar",
|
|
32
|
+
background: "#ffffff",
|
|
33
|
+
foreground: "#000000",
|
|
34
|
+
component: SidebarView,
|
|
35
|
+
props: { title: "Navigation" },
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "Content",
|
|
39
|
+
background: "#f8f9fa",
|
|
40
|
+
foreground: "#212529",
|
|
41
|
+
component: ContentView,
|
|
42
|
+
props: { section: "main" },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Details",
|
|
46
|
+
background: "#e9ecef",
|
|
47
|
+
foreground: "#495057",
|
|
48
|
+
component: DetailsView,
|
|
49
|
+
props: { item: null },
|
|
50
|
+
},
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const splitviewRef = ref();
|
|
54
|
+
|
|
55
|
+
// Navigate to specific pane
|
|
56
|
+
const goToPane = (index: number) => {
|
|
57
|
+
splitviewRef.value?.navigate(index);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Show all panes
|
|
61
|
+
const showAllPanes = () => {
|
|
62
|
+
splitviewRef.value?.showAll();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Hide all panes except the last one
|
|
66
|
+
const hideAllPanes = () => {
|
|
67
|
+
splitviewRef.value?.hideAll();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Toggle specific pane
|
|
71
|
+
const togglePane = (index: number) => {
|
|
72
|
+
splitviewRef.value?.togglePane(index);
|
|
73
|
+
};
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<div class="app">
|
|
78
|
+
<div class="navigation-controls">
|
|
79
|
+
<button @click="goToPane(0)">Sidebar</button>
|
|
80
|
+
<button @click="goToPane(1)">Content</button>
|
|
81
|
+
<button @click="goToPane(2)">Details</button>
|
|
82
|
+
<button @click="showAllPanes">Show All</button>
|
|
83
|
+
<button @click="hideAllPanes">Hide All</button>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<SplitViewController
|
|
87
|
+
ref="splitviewRef"
|
|
88
|
+
:panes="panes"
|
|
89
|
+
component-id="main-splitview"
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</template>
|
|
93
|
+
|
|
94
|
+
<style module>
|
|
95
|
+
.app {
|
|
96
|
+
height: 100vh;
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.navigation-controls {
|
|
102
|
+
display: flex;
|
|
103
|
+
gap: 12px;
|
|
104
|
+
padding: 16px;
|
|
105
|
+
background: var(--background-1);
|
|
106
|
+
border-bottom: 1px solid var(--border-2);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.navigation-controls button {
|
|
110
|
+
padding: 8px 16px;
|
|
111
|
+
border: 1px solid var(--border-2);
|
|
112
|
+
background: var(--background-2);
|
|
113
|
+
color: var(--text-1);
|
|
114
|
+
border-radius: 6px;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
transition: all 0.2s ease;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.navigation-controls button:hover {
|
|
120
|
+
background: var(--background-3);
|
|
121
|
+
border-color: var(--border-3);
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Props
|
|
127
|
+
|
|
128
|
+
| Prop Name | Type | Required | Default | Description |
|
|
129
|
+
| ------------- | ------------------------------------------- | -------- | -------------- | -------------------------------------------- |
|
|
130
|
+
| `panes` | `Pane[]` | Yes | - | Array of panes to display in the split-view |
|
|
131
|
+
| `controller` | `ReturnType<typeof useSplitViewController>` | No | - | External controller instance |
|
|
132
|
+
| `componentId` | `string` | No | Auto-generated | Unique identifier for the component instance |
|
|
133
|
+
|
|
134
|
+
## Pane Interface
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface Pane {
|
|
138
|
+
name: string;
|
|
139
|
+
background: string;
|
|
140
|
+
foreground: string;
|
|
141
|
+
component: any;
|
|
142
|
+
props: Record<string, any>;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Pane Properties
|
|
147
|
+
|
|
148
|
+
| Property | Type | Description |
|
|
149
|
+
| ------------ | --------------------- | --------------------------------------- |
|
|
150
|
+
| `name` | `string` | Display name for the pane |
|
|
151
|
+
| `background` | `string` | Background color for the pane container |
|
|
152
|
+
| `foreground` | `string` | Text color for the pane content |
|
|
153
|
+
| `component` | `Component` | Vue component to render in the pane |
|
|
154
|
+
| `props` | `Record<string, any>` | Props to pass to the component |
|
|
155
|
+
|
|
156
|
+
## Events
|
|
157
|
+
|
|
158
|
+
The SplitViewController component doesn't emit events directly, but you can access navigation methods through template refs.
|
|
159
|
+
|
|
160
|
+
## Exposed Methods/Refs
|
|
161
|
+
|
|
162
|
+
| Method | Parameters | Description |
|
|
163
|
+
| ------------ | ------------------------------------- | ------------------------------------- |
|
|
164
|
+
| `navigate` | `(index: number, animated?: boolean)` | Navigate to show only a specific pane |
|
|
165
|
+
| `showPane` | `(index: number)` | Show a specific pane |
|
|
166
|
+
| `hidePane` | `(index: number)` | Hide a specific pane |
|
|
167
|
+
| `togglePane` | `(index: number)` | Toggle a pane at a specific index |
|
|
168
|
+
| `showAll` | `()` | Show all panes |
|
|
169
|
+
| `hideAll` | `()` | Hide all panes except the last one |
|
|
170
|
+
|
|
171
|
+
## useSplitViewController Composable
|
|
172
|
+
|
|
173
|
+
The `useSplitViewController` composable provides the core split-view logic and can be used independently:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { useSplitViewController } from "@umbra-ui/core";
|
|
177
|
+
|
|
178
|
+
const {
|
|
179
|
+
visiblePanes,
|
|
180
|
+
currentPaneIndex,
|
|
181
|
+
lastVisibilityEvent,
|
|
182
|
+
showPane,
|
|
183
|
+
hidePane,
|
|
184
|
+
togglePane,
|
|
185
|
+
showAll,
|
|
186
|
+
hideAll,
|
|
187
|
+
navigate,
|
|
188
|
+
} = useSplitViewController(panes, componentId);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Composable Returns
|
|
192
|
+
|
|
193
|
+
| Property | Type | Description |
|
|
194
|
+
| --------------------- | ------------------------------------------------------ | ------------------------------------------------- |
|
|
195
|
+
| `visiblePanes` | `Ref<boolean[]>` | Reactive array indicating which panes are visible |
|
|
196
|
+
| `currentPaneIndex` | `ComputedRef<number>` | Current active pane index |
|
|
197
|
+
| `lastVisibilityEvent` | `Ref<{type: "show" \| "hide", index: number} \| null>` | Last visibility change event |
|
|
198
|
+
| `showPane` | `(index: number) => void` | Show specific pane |
|
|
199
|
+
| `hidePane` | `(index: number) => void` | Hide specific pane |
|
|
200
|
+
| `togglePane` | `(index: number) => void` | Toggle pane at specific index |
|
|
201
|
+
| `showAll` | `() => void` | Show all panes |
|
|
202
|
+
| `hideAll` | `() => void` | Hide all panes except the last one |
|
|
203
|
+
| `navigate` | `(index: number, animated?: boolean) => void` | Navigate to specific pane |
|
|
204
|
+
|
|
205
|
+
## CSS Customization
|
|
206
|
+
|
|
207
|
+
### Layout Variables
|
|
208
|
+
|
|
209
|
+
```css
|
|
210
|
+
.splitview-controller {
|
|
211
|
+
--splitview-handle-default-width: 4px;
|
|
212
|
+
--splitview-handle-default-height: 24px;
|
|
213
|
+
--splitview-handle-default-opacity: 0.3;
|
|
214
|
+
--splitview-handle-bg: #666;
|
|
215
|
+
--splitview-handle-hover-width: 6px;
|
|
216
|
+
--splitview-handle-hover-height: 32px;
|
|
217
|
+
--splitview-handle-hover-opacity: 0.6;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Container Styling
|
|
222
|
+
|
|
223
|
+
```css
|
|
224
|
+
.splitview-controller {
|
|
225
|
+
position: relative;
|
|
226
|
+
display: grid;
|
|
227
|
+
grid-template-areas: "content";
|
|
228
|
+
height: 100%;
|
|
229
|
+
width: 100%;
|
|
230
|
+
overflow: hidden;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.splitview-controller .onscreen {
|
|
234
|
+
grid-area: content;
|
|
235
|
+
display: flex;
|
|
236
|
+
height: 100%;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Pane Styling
|
|
241
|
+
|
|
242
|
+
```css
|
|
243
|
+
.splitview-controller .pane {
|
|
244
|
+
display: grid;
|
|
245
|
+
grid-template-columns: 1fr;
|
|
246
|
+
grid-template-areas: "content";
|
|
247
|
+
height: 100%;
|
|
248
|
+
flex: 0 0 auto;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.splitview-controller .pane_full {
|
|
252
|
+
flex: 1 1 auto;
|
|
253
|
+
min-width: 0;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Examples
|
|
258
|
+
|
|
259
|
+
### File Manager Interface
|
|
260
|
+
|
|
261
|
+
```vue
|
|
262
|
+
<script setup lang="ts">
|
|
263
|
+
import { ref } from "vue";
|
|
264
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
265
|
+
import FileTree from "./FileTree.vue";
|
|
266
|
+
import FileList from "./FileList.vue";
|
|
267
|
+
import FilePreview from "./FilePreview.vue";
|
|
268
|
+
|
|
269
|
+
const panes = ref([
|
|
270
|
+
{
|
|
271
|
+
name: "Tree",
|
|
272
|
+
background: "#ffffff",
|
|
273
|
+
foreground: "#1a202c",
|
|
274
|
+
component: FileTree,
|
|
275
|
+
props: { rootPath: "/" },
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "List",
|
|
279
|
+
background: "#f7fafc",
|
|
280
|
+
foreground: "#2d3748",
|
|
281
|
+
component: FileList,
|
|
282
|
+
props: { currentPath: "/documents" },
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "Preview",
|
|
286
|
+
background: "#edf2f7",
|
|
287
|
+
foreground: "#4a5568",
|
|
288
|
+
component: FilePreview,
|
|
289
|
+
props: { selectedFile: null },
|
|
290
|
+
},
|
|
291
|
+
]);
|
|
292
|
+
|
|
293
|
+
const splitviewRef = ref();
|
|
294
|
+
|
|
295
|
+
const handleFileSelect = (file: any) => {
|
|
296
|
+
// Navigate to preview pane
|
|
297
|
+
splitviewRef.value?.navigate(2);
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const handleFolderSelect = (folder: any) => {
|
|
301
|
+
// Navigate to file list pane
|
|
302
|
+
splitviewRef.value?.navigate(1);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const toggleTree = () => {
|
|
306
|
+
splitviewRef.value?.togglePane(0);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const toggleList = () => {
|
|
310
|
+
splitviewRef.value?.togglePane(1);
|
|
311
|
+
};
|
|
312
|
+
</script>
|
|
313
|
+
|
|
314
|
+
<template>
|
|
315
|
+
<div class="file-manager">
|
|
316
|
+
<!-- Toolbar -->
|
|
317
|
+
<div class="file-toolbar">
|
|
318
|
+
<div class="toolbar-section">
|
|
319
|
+
<button @click="splitviewRef?.showAll()" class="toolbar-btn">
|
|
320
|
+
Show All Panes
|
|
321
|
+
</button>
|
|
322
|
+
<button @click="splitviewRef?.hideAll()" class="toolbar-btn">
|
|
323
|
+
Hide All Panes
|
|
324
|
+
</button>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
<div class="toolbar-section">
|
|
328
|
+
<button @click="toggleTree" class="toolbar-btn">Toggle Tree</button>
|
|
329
|
+
<button @click="toggleList" class="toolbar-btn">Toggle List</button>
|
|
330
|
+
<button @click="splitviewRef?.navigate(2)" class="toolbar-btn">
|
|
331
|
+
Preview Only
|
|
332
|
+
</button>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
<!-- Split View Controller -->
|
|
337
|
+
<SplitViewController
|
|
338
|
+
ref="splitviewRef"
|
|
339
|
+
:panes="panes"
|
|
340
|
+
component-id="file-manager"
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
</template>
|
|
344
|
+
|
|
345
|
+
<style module>
|
|
346
|
+
.file-manager {
|
|
347
|
+
height: 100vh;
|
|
348
|
+
display: flex;
|
|
349
|
+
flex-direction: column;
|
|
350
|
+
background: #f8f9fa;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.file-toolbar {
|
|
354
|
+
display: flex;
|
|
355
|
+
justify-content: space-between;
|
|
356
|
+
align-items: center;
|
|
357
|
+
padding: 12px 16px;
|
|
358
|
+
background: white;
|
|
359
|
+
border-bottom: 1px solid #e9ecef;
|
|
360
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.toolbar-section {
|
|
364
|
+
display: flex;
|
|
365
|
+
gap: 8px;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.toolbar-btn {
|
|
369
|
+
padding: 6px 12px;
|
|
370
|
+
border: 1px solid #dee2e6;
|
|
371
|
+
background: white;
|
|
372
|
+
color: #495057;
|
|
373
|
+
border-radius: 4px;
|
|
374
|
+
cursor: pointer;
|
|
375
|
+
font-size: 14px;
|
|
376
|
+
transition: all 0.2s ease;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.toolbar-btn:hover {
|
|
380
|
+
background: #f8f9fa;
|
|
381
|
+
border-color: #adb5bd;
|
|
382
|
+
}
|
|
383
|
+
</style>
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Code Editor Interface
|
|
387
|
+
|
|
388
|
+
```vue
|
|
389
|
+
<script setup lang="ts">
|
|
390
|
+
import { ref } from "vue";
|
|
391
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
392
|
+
import FileExplorer from "./FileExplorer.vue";
|
|
393
|
+
import CodeEditor from "./CodeEditor.vue";
|
|
394
|
+
import Terminal from "./Terminal.vue";
|
|
395
|
+
|
|
396
|
+
const panes = ref([
|
|
397
|
+
{
|
|
398
|
+
name: "Explorer",
|
|
399
|
+
background: "#1e1e1e",
|
|
400
|
+
foreground: "#cccccc",
|
|
401
|
+
component: FileExplorer,
|
|
402
|
+
props: { theme: "dark" },
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
name: "Editor",
|
|
406
|
+
background: "#2d2d30",
|
|
407
|
+
foreground: "#cccccc",
|
|
408
|
+
component: CodeEditor,
|
|
409
|
+
props: { language: "typescript" },
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
name: "Terminal",
|
|
413
|
+
background: "#0c0c0c",
|
|
414
|
+
foreground: "#00ff00",
|
|
415
|
+
component: Terminal,
|
|
416
|
+
props: { shell: "bash" },
|
|
417
|
+
},
|
|
418
|
+
]);
|
|
419
|
+
|
|
420
|
+
const splitviewRef = ref();
|
|
421
|
+
const currentFile = ref(null);
|
|
422
|
+
|
|
423
|
+
const openFile = (file: any) => {
|
|
424
|
+
currentFile.value = file;
|
|
425
|
+
// Ensure editor is visible
|
|
426
|
+
splitviewRef.value?.navigate(1);
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const toggleExplorer = () => {
|
|
430
|
+
splitviewRef.value?.togglePane(0);
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const toggleTerminal = () => {
|
|
434
|
+
splitviewRef.value?.togglePane(2);
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const focusEditor = () => {
|
|
438
|
+
splitviewRef.value?.navigate(1);
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const showAllPanels = () => {
|
|
442
|
+
splitviewRef.value?.showAll();
|
|
443
|
+
};
|
|
444
|
+
</script>
|
|
445
|
+
|
|
446
|
+
<template>
|
|
447
|
+
<div class="code-editor">
|
|
448
|
+
<!-- Editor Header -->
|
|
449
|
+
<header class="editor-header">
|
|
450
|
+
<div class="header-left">
|
|
451
|
+
<button @click="toggleExplorer" class="header-btn">📁 Explorer</button>
|
|
452
|
+
<button @click="focusEditor" class="header-btn">✏️ Editor</button>
|
|
453
|
+
<button @click="toggleTerminal" class="header-btn">💻 Terminal</button>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<div class="header-right">
|
|
457
|
+
<button @click="showAllPanels" class="header-btn">Show All</button>
|
|
458
|
+
<span v-if="currentFile" class="current-file">
|
|
459
|
+
{{ currentFile.name }}
|
|
460
|
+
</span>
|
|
461
|
+
</div>
|
|
462
|
+
</header>
|
|
463
|
+
|
|
464
|
+
<!-- Split View Controller -->
|
|
465
|
+
<SplitViewController
|
|
466
|
+
ref="splitviewRef"
|
|
467
|
+
:panes="panes"
|
|
468
|
+
component-id="code-editor"
|
|
469
|
+
/>
|
|
470
|
+
</div>
|
|
471
|
+
</template>
|
|
472
|
+
|
|
473
|
+
<style module>
|
|
474
|
+
.code-editor {
|
|
475
|
+
height: 100vh;
|
|
476
|
+
display: flex;
|
|
477
|
+
flex-direction: column;
|
|
478
|
+
background: #1e1e1e;
|
|
479
|
+
color: #cccccc;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.editor-header {
|
|
483
|
+
display: flex;
|
|
484
|
+
justify-content: space-between;
|
|
485
|
+
align-items: center;
|
|
486
|
+
padding: 8px 16px;
|
|
487
|
+
background: #2d2d30;
|
|
488
|
+
border-bottom: 1px solid #3e3e42;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.header-left {
|
|
492
|
+
display: flex;
|
|
493
|
+
gap: 8px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.header-right {
|
|
497
|
+
display: flex;
|
|
498
|
+
align-items: center;
|
|
499
|
+
gap: 12px;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.header-btn {
|
|
503
|
+
padding: 6px 12px;
|
|
504
|
+
background: transparent;
|
|
505
|
+
border: 1px solid #3e3e42;
|
|
506
|
+
color: #cccccc;
|
|
507
|
+
border-radius: 4px;
|
|
508
|
+
cursor: pointer;
|
|
509
|
+
font-size: 14px;
|
|
510
|
+
transition: all 0.2s ease;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.header-btn:hover {
|
|
514
|
+
background: #3e3e42;
|
|
515
|
+
border-color: #007acc;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.current-file {
|
|
519
|
+
font-size: 14px;
|
|
520
|
+
color: #007acc;
|
|
521
|
+
font-weight: 500;
|
|
522
|
+
}
|
|
523
|
+
</style>
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Dashboard Layout
|
|
527
|
+
|
|
528
|
+
```vue
|
|
529
|
+
<script setup lang="ts">
|
|
530
|
+
import { ref } from "vue";
|
|
531
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
532
|
+
import Sidebar from "./Sidebar.vue";
|
|
533
|
+
import MainContent from "./MainContent.vue";
|
|
534
|
+
import RightPanel from "./RightPanel.vue";
|
|
535
|
+
|
|
536
|
+
const panes = ref([
|
|
537
|
+
{
|
|
538
|
+
name: "Sidebar",
|
|
539
|
+
background: "#f8f9fa",
|
|
540
|
+
foreground: "#495057",
|
|
541
|
+
component: Sidebar,
|
|
542
|
+
props: { collapsed: false },
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
name: "Content",
|
|
546
|
+
background: "#ffffff",
|
|
547
|
+
foreground: "#212529",
|
|
548
|
+
component: MainContent,
|
|
549
|
+
props: { section: "dashboard" },
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
name: "Panel",
|
|
553
|
+
background: "#e9ecef",
|
|
554
|
+
foreground: "#495057",
|
|
555
|
+
component: RightPanel,
|
|
556
|
+
props: { type: "info" },
|
|
557
|
+
},
|
|
558
|
+
]);
|
|
559
|
+
|
|
560
|
+
const splitviewRef = ref();
|
|
561
|
+
const sidebarCollapsed = ref(false);
|
|
562
|
+
|
|
563
|
+
const toggleSidebar = () => {
|
|
564
|
+
sidebarCollapsed.value = !sidebarCollapsed.value;
|
|
565
|
+
if (sidebarCollapsed.value) {
|
|
566
|
+
splitviewRef.value?.hidePane(0);
|
|
567
|
+
} else {
|
|
568
|
+
splitviewRef.value?.showPane(0);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const toggleRightPanel = () => {
|
|
573
|
+
splitviewRef.value?.togglePane(2);
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
const showAllPanels = () => {
|
|
577
|
+
splitviewRef.value?.showAll();
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const focusContent = () => {
|
|
581
|
+
splitviewRef.value?.navigate(1);
|
|
582
|
+
};
|
|
583
|
+
</script>
|
|
584
|
+
|
|
585
|
+
<template>
|
|
586
|
+
<div class="dashboard-layout">
|
|
587
|
+
<!-- Top Navigation -->
|
|
588
|
+
<nav class="top-nav">
|
|
589
|
+
<div class="nav-left">
|
|
590
|
+
<button @click="toggleSidebar" class="nav-btn">
|
|
591
|
+
{{ sidebarCollapsed ? "☰" : "✕" }}
|
|
592
|
+
</button>
|
|
593
|
+
<h1 class="nav-title">Dashboard</h1>
|
|
594
|
+
</div>
|
|
595
|
+
|
|
596
|
+
<div class="nav-center">
|
|
597
|
+
<button @click="focusContent" class="nav-btn">Home</button>
|
|
598
|
+
<button @click="splitviewRef?.navigate(1)" class="nav-btn">
|
|
599
|
+
Analytics
|
|
600
|
+
</button>
|
|
601
|
+
<button @click="splitviewRef?.navigate(1)" class="nav-btn">
|
|
602
|
+
Reports
|
|
603
|
+
</button>
|
|
604
|
+
</div>
|
|
605
|
+
|
|
606
|
+
<div class="nav-right">
|
|
607
|
+
<button @click="toggleRightPanel" class="nav-btn">Panel</button>
|
|
608
|
+
<button @click="showAllPanels" class="nav-btn">Show All</button>
|
|
609
|
+
</div>
|
|
610
|
+
</nav>
|
|
611
|
+
|
|
612
|
+
<!-- Split View Controller -->
|
|
613
|
+
<SplitViewController
|
|
614
|
+
ref="splitviewRef"
|
|
615
|
+
:panes="panes"
|
|
616
|
+
component-id="dashboard-splitview"
|
|
617
|
+
/>
|
|
618
|
+
</div>
|
|
619
|
+
</template>
|
|
620
|
+
|
|
621
|
+
<style module>
|
|
622
|
+
.dashboard-layout {
|
|
623
|
+
height: 100vh;
|
|
624
|
+
display: flex;
|
|
625
|
+
flex-direction: column;
|
|
626
|
+
background: #f8f9fa;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.top-nav {
|
|
630
|
+
display: flex;
|
|
631
|
+
justify-content: space-between;
|
|
632
|
+
align-items: center;
|
|
633
|
+
padding: 12px 20px;
|
|
634
|
+
background: white;
|
|
635
|
+
border-bottom: 1px solid #dee2e6;
|
|
636
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.nav-left {
|
|
640
|
+
display: flex;
|
|
641
|
+
align-items: center;
|
|
642
|
+
gap: 16px;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.nav-center {
|
|
646
|
+
display: flex;
|
|
647
|
+
gap: 8px;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.nav-right {
|
|
651
|
+
display: flex;
|
|
652
|
+
gap: 8px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.nav-btn {
|
|
656
|
+
padding: 8px 16px;
|
|
657
|
+
background: transparent;
|
|
658
|
+
border: 1px solid #dee2e6;
|
|
659
|
+
color: #495057;
|
|
660
|
+
border-radius: 6px;
|
|
661
|
+
cursor: pointer;
|
|
662
|
+
font-size: 14px;
|
|
663
|
+
transition: all 0.2s ease;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.nav-btn:hover {
|
|
667
|
+
background: #f8f9fa;
|
|
668
|
+
border-color: #adb5bd;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.nav-title {
|
|
672
|
+
font-size: 20px;
|
|
673
|
+
font-weight: 600;
|
|
674
|
+
color: #212529;
|
|
675
|
+
margin: 0;
|
|
676
|
+
}
|
|
677
|
+
</style>
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
### Settings Interface
|
|
681
|
+
|
|
682
|
+
```vue
|
|
683
|
+
<script setup lang="ts">
|
|
684
|
+
import { ref } from "vue";
|
|
685
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
686
|
+
import SettingsNav from "./SettingsNav.vue";
|
|
687
|
+
import SettingsContent from "./SettingsContent.vue";
|
|
688
|
+
import SettingsPreview from "./SettingsPreview.vue";
|
|
689
|
+
|
|
690
|
+
const panes = ref([
|
|
691
|
+
{
|
|
692
|
+
name: "Navigation",
|
|
693
|
+
background: "#ffffff",
|
|
694
|
+
foreground: "#1a202c",
|
|
695
|
+
component: SettingsNav,
|
|
696
|
+
props: { currentSection: "general" },
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: "Content",
|
|
700
|
+
background: "#f7fafc",
|
|
701
|
+
foreground: "#2d3748",
|
|
702
|
+
component: SettingsContent,
|
|
703
|
+
props: { section: "general" },
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
name: "Preview",
|
|
707
|
+
background: "#edf2f7",
|
|
708
|
+
foreground: "#4a5568",
|
|
709
|
+
component: SettingsPreview,
|
|
710
|
+
props: { theme: "light" },
|
|
711
|
+
},
|
|
712
|
+
]);
|
|
713
|
+
|
|
714
|
+
const splitviewRef = ref();
|
|
715
|
+
const currentSection = ref("general");
|
|
716
|
+
|
|
717
|
+
const navigateToSection = (section: string) => {
|
|
718
|
+
currentSection.value = section;
|
|
719
|
+
// Update props for content pane
|
|
720
|
+
panes.value[1].props.section = section;
|
|
721
|
+
panes.value[0].props.currentSection = section;
|
|
722
|
+
|
|
723
|
+
// Ensure content is visible
|
|
724
|
+
splitviewRef.value?.navigate(1);
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
const togglePreview = () => {
|
|
728
|
+
splitviewRef.value?.togglePane(2);
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
const showAllSections = () => {
|
|
732
|
+
splitviewRef.value?.showAll();
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
const hideNavigation = () => {
|
|
736
|
+
splitviewRef.value?.hidePane(0);
|
|
737
|
+
};
|
|
738
|
+
</script>
|
|
739
|
+
|
|
740
|
+
<template>
|
|
741
|
+
<div class="settings-interface">
|
|
742
|
+
<!-- Settings Header -->
|
|
743
|
+
<header class="settings-header">
|
|
744
|
+
<h1 class="settings-title">Settings</h1>
|
|
745
|
+
<div class="settings-actions">
|
|
746
|
+
<button @click="showAllSections" class="action-btn">Show All</button>
|
|
747
|
+
<button @click="hideNavigation" class="action-btn">Hide Nav</button>
|
|
748
|
+
<button @click="togglePreview" class="action-btn">
|
|
749
|
+
Toggle Preview
|
|
750
|
+
</button>
|
|
751
|
+
</div>
|
|
752
|
+
</header>
|
|
753
|
+
|
|
754
|
+
<!-- Quick Navigation -->
|
|
755
|
+
<div class="quick-nav">
|
|
756
|
+
<button
|
|
757
|
+
v-for="section in ['general', 'appearance', 'privacy', 'advanced']"
|
|
758
|
+
:key="section"
|
|
759
|
+
@click="navigateToSection(section)"
|
|
760
|
+
:class="['quick-nav-btn', { active: currentSection === section }]"
|
|
761
|
+
>
|
|
762
|
+
{{ section.charAt(0).toUpperCase() + section.slice(1) }}
|
|
763
|
+
</button>
|
|
764
|
+
</div>
|
|
765
|
+
|
|
766
|
+
<!-- Split View Controller -->
|
|
767
|
+
<SplitViewController
|
|
768
|
+
ref="splitviewRef"
|
|
769
|
+
:panes="panes"
|
|
770
|
+
component-id="settings-splitview"
|
|
771
|
+
/>
|
|
772
|
+
</div>
|
|
773
|
+
</template>
|
|
774
|
+
|
|
775
|
+
<style module>
|
|
776
|
+
.settings-interface {
|
|
777
|
+
height: 100vh;
|
|
778
|
+
display: flex;
|
|
779
|
+
flex-direction: column;
|
|
780
|
+
background: #f8f9fa;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.settings-header {
|
|
784
|
+
display: flex;
|
|
785
|
+
justify-content: space-between;
|
|
786
|
+
align-items: center;
|
|
787
|
+
padding: 20px 24px;
|
|
788
|
+
background: white;
|
|
789
|
+
border-bottom: 1px solid #e9ecef;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.settings-title {
|
|
793
|
+
font-size: 28px;
|
|
794
|
+
font-weight: 700;
|
|
795
|
+
color: #1a202c;
|
|
796
|
+
margin: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.settings-actions {
|
|
800
|
+
display: flex;
|
|
801
|
+
gap: 8px;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.action-btn {
|
|
805
|
+
padding: 8px 16px;
|
|
806
|
+
background: #f8f9fa;
|
|
807
|
+
border: 1px solid #dee2e6;
|
|
808
|
+
color: #495057;
|
|
809
|
+
border-radius: 6px;
|
|
810
|
+
cursor: pointer;
|
|
811
|
+
font-size: 14px;
|
|
812
|
+
transition: all 0.2s ease;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.action-btn:hover {
|
|
816
|
+
background: #e9ecef;
|
|
817
|
+
border-color: #adb5bd;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
.quick-nav {
|
|
821
|
+
display: flex;
|
|
822
|
+
gap: 4px;
|
|
823
|
+
padding: 12px 24px;
|
|
824
|
+
background: white;
|
|
825
|
+
border-bottom: 1px solid #e9ecef;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.quick-nav-btn {
|
|
829
|
+
padding: 8px 16px;
|
|
830
|
+
background: transparent;
|
|
831
|
+
border: 1px solid transparent;
|
|
832
|
+
color: #6c757d;
|
|
833
|
+
border-radius: 6px;
|
|
834
|
+
cursor: pointer;
|
|
835
|
+
font-size: 14px;
|
|
836
|
+
font-weight: 500;
|
|
837
|
+
transition: all 0.2s ease;
|
|
838
|
+
text-transform: capitalize;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.quick-nav-btn:hover {
|
|
842
|
+
background: #f8f9fa;
|
|
843
|
+
color: #495057;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
.quick-nav-btn.active {
|
|
847
|
+
background: #e3f2fd;
|
|
848
|
+
color: #1976d2;
|
|
849
|
+
border-color: #bbdefb;
|
|
850
|
+
}
|
|
851
|
+
</style>
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
## Advanced Usage
|
|
855
|
+
|
|
856
|
+
### Custom Controller Integration
|
|
857
|
+
|
|
858
|
+
```vue
|
|
859
|
+
<script setup lang="ts">
|
|
860
|
+
import { ref } from "vue";
|
|
861
|
+
import { SplitViewController, useSplitViewController } from "@umbra-ui/core";
|
|
862
|
+
|
|
863
|
+
const panes = ref([
|
|
864
|
+
// ... your panes
|
|
865
|
+
]);
|
|
866
|
+
|
|
867
|
+
// Create custom controller
|
|
868
|
+
const customController = useSplitViewController(
|
|
869
|
+
panes.value,
|
|
870
|
+
"custom-splitview"
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
// Override methods with custom logic
|
|
874
|
+
const customNavigate = (index: number, animated: boolean = true) => {
|
|
875
|
+
console.log(`Navigating to pane ${index}`);
|
|
876
|
+
customController.navigate(index, animated);
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
const customShowAll = () => {
|
|
880
|
+
console.log("Showing all panes");
|
|
881
|
+
customController.showAll();
|
|
882
|
+
};
|
|
883
|
+
</script>
|
|
884
|
+
|
|
885
|
+
<template>
|
|
886
|
+
<SplitViewController
|
|
887
|
+
:panes="panes"
|
|
888
|
+
:controller="customController"
|
|
889
|
+
component-id="custom-splitview"
|
|
890
|
+
/>
|
|
891
|
+
</template>
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
### Integration with Router
|
|
895
|
+
|
|
896
|
+
```vue
|
|
897
|
+
<script setup lang="ts">
|
|
898
|
+
import { ref, watch } from "vue";
|
|
899
|
+
import { useRoute, useRouter } from "vue-router";
|
|
900
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
901
|
+
|
|
902
|
+
const route = useRoute();
|
|
903
|
+
const router = useRouter();
|
|
904
|
+
const splitviewRef = ref();
|
|
905
|
+
|
|
906
|
+
const panes = ref([
|
|
907
|
+
// ... your panes
|
|
908
|
+
]);
|
|
909
|
+
|
|
910
|
+
// Sync with router
|
|
911
|
+
watch(
|
|
912
|
+
() => route.params.panel,
|
|
913
|
+
(newPanel) => {
|
|
914
|
+
const index = panes.value.findIndex((pane) => pane.name === newPanel);
|
|
915
|
+
if (index !== -1) {
|
|
916
|
+
splitviewRef.value?.navigate(index);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
const handleNavigation = (index: number) => {
|
|
922
|
+
const pane = panes.value[index];
|
|
923
|
+
router.push(`/dashboard/${pane.name.toLowerCase()}`);
|
|
924
|
+
};
|
|
925
|
+
</script>
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
### Dynamic Pane Management
|
|
929
|
+
|
|
930
|
+
```vue
|
|
931
|
+
<script setup lang="ts">
|
|
932
|
+
import { ref } from "vue";
|
|
933
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
934
|
+
import DynamicPane from "./DynamicPane.vue";
|
|
935
|
+
|
|
936
|
+
const panes = ref([
|
|
937
|
+
{
|
|
938
|
+
name: "Main",
|
|
939
|
+
background: "#ffffff",
|
|
940
|
+
foreground: "#000000",
|
|
941
|
+
component: DynamicPane,
|
|
942
|
+
props: { content: "Main Content" },
|
|
943
|
+
},
|
|
944
|
+
]);
|
|
945
|
+
|
|
946
|
+
const splitviewRef = ref();
|
|
947
|
+
const paneCounter = ref(1);
|
|
948
|
+
|
|
949
|
+
const addPane = () => {
|
|
950
|
+
const newPane = {
|
|
951
|
+
name: `Pane ${paneCounter.value}`,
|
|
952
|
+
background: `hsl(${Math.random() * 360}, 70%, 90%)`,
|
|
953
|
+
foreground: "#000000",
|
|
954
|
+
component: DynamicPane,
|
|
955
|
+
props: { content: `Dynamic Content ${paneCounter.value}` },
|
|
956
|
+
};
|
|
957
|
+
|
|
958
|
+
panes.value.push(newPane);
|
|
959
|
+
paneCounter.value++;
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
const removePane = (index: number) => {
|
|
963
|
+
if (panes.value.length > 1) {
|
|
964
|
+
panes.value.splice(index, 1);
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
const resetPanes = () => {
|
|
969
|
+
panes.value = [
|
|
970
|
+
{
|
|
971
|
+
name: "Main",
|
|
972
|
+
background: "#ffffff",
|
|
973
|
+
foreground: "#000000",
|
|
974
|
+
component: DynamicPane,
|
|
975
|
+
props: { content: "Main Content" },
|
|
976
|
+
},
|
|
977
|
+
];
|
|
978
|
+
};
|
|
979
|
+
</script>
|
|
980
|
+
|
|
981
|
+
<template>
|
|
982
|
+
<div class="dynamic-splitview">
|
|
983
|
+
<!-- Controls -->
|
|
984
|
+
<div class="controls">
|
|
985
|
+
<button @click="addPane" class="control-btn add">Add Pane</button>
|
|
986
|
+
<button @click="resetPanes" class="control-btn reset">Reset</button>
|
|
987
|
+
</div>
|
|
988
|
+
|
|
989
|
+
<!-- Split View Controller -->
|
|
990
|
+
<SplitViewController
|
|
991
|
+
ref="splitviewRef"
|
|
992
|
+
:panes="panes"
|
|
993
|
+
component-id="dynamic-splitview"
|
|
994
|
+
/>
|
|
995
|
+
</div>
|
|
996
|
+
</template>
|
|
997
|
+
|
|
998
|
+
<style module>
|
|
999
|
+
.dynamic-splitview {
|
|
1000
|
+
height: 100vh;
|
|
1001
|
+
display: flex;
|
|
1002
|
+
flex-direction: column;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
.controls {
|
|
1006
|
+
display: flex;
|
|
1007
|
+
gap: 12px;
|
|
1008
|
+
padding: 16px;
|
|
1009
|
+
background: var(--background-1);
|
|
1010
|
+
border-bottom: 1px solid var(--border-2);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
.control-btn {
|
|
1014
|
+
padding: 8px 16px;
|
|
1015
|
+
border: none;
|
|
1016
|
+
border-radius: 6px;
|
|
1017
|
+
font-weight: 500;
|
|
1018
|
+
cursor: pointer;
|
|
1019
|
+
transition: all 0.2s ease;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
.control-btn.add {
|
|
1023
|
+
background: #28a745;
|
|
1024
|
+
color: white;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.control-btn.add:hover {
|
|
1028
|
+
background: #218838;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
.control-btn.reset {
|
|
1032
|
+
background: #6c757d;
|
|
1033
|
+
color: white;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.control-btn.reset:hover {
|
|
1037
|
+
background: #5a6268;
|
|
1038
|
+
}
|
|
1039
|
+
</style>
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
## Performance Considerations
|
|
1043
|
+
|
|
1044
|
+
- **Component Marking**: Always use `markRaw()` when passing components to prevent Vue's reactivity system from wrapping them
|
|
1045
|
+
- **Animation Performance**: GSAP FLIP animations are optimized for smooth 60fps performance
|
|
1046
|
+
- **Memory Management**: Panes are properly cleaned up when removed from the controller
|
|
1047
|
+
- **DOM Manipulation**: Efficient DOM manipulation using GSAP for optimal performance
|
|
1048
|
+
|
|
1049
|
+
## Accessibility
|
|
1050
|
+
|
|
1051
|
+
- **Keyboard Navigation**: Support for arrow keys and tab navigation
|
|
1052
|
+
- **Screen Reader Support**: Proper ARIA labels and roles
|
|
1053
|
+
- **Focus Management**: Focus is maintained during transitions
|
|
1054
|
+
- **High Contrast**: Supports high contrast mode
|
|
1055
|
+
|
|
1056
|
+
## Browser Support
|
|
1057
|
+
|
|
1058
|
+
- **Modern Browsers**: Chrome 88+, Firefox 85+, Safari 14+, Edge 88+
|
|
1059
|
+
- **Mobile Browsers**: iOS Safari 14+, Chrome Mobile 88+
|
|
1060
|
+
- **CSS Features**: Uses CSS Grid and modern layout features
|
|
1061
|
+
- **JavaScript**: Requires ES2020+ support
|
|
1062
|
+
|
|
1063
|
+
## Troubleshooting
|
|
1064
|
+
|
|
1065
|
+
### Common Issues
|
|
1066
|
+
|
|
1067
|
+
1. **Animations not working**: Ensure GSAP and FLIP plugin are properly imported
|
|
1068
|
+
2. **Panes not displaying**: Check that components are properly marked with `markRaw()`
|
|
1069
|
+
3. **Navigation not responding**: Verify the `componentId` is unique and consistent
|
|
1070
|
+
4. **Layout issues**: Ensure the container has a defined height
|
|
1071
|
+
|
|
1072
|
+
### Debug Mode
|
|
1073
|
+
|
|
1074
|
+
```vue
|
|
1075
|
+
<script setup lang="ts">
|
|
1076
|
+
import { ref, watch } from "vue";
|
|
1077
|
+
import { SplitViewController } from "@umbra-ui/core";
|
|
1078
|
+
|
|
1079
|
+
const splitviewRef = ref();
|
|
1080
|
+
|
|
1081
|
+
// Watch for navigation changes
|
|
1082
|
+
watch(
|
|
1083
|
+
() => splitviewRef.value?.currentPaneIndex,
|
|
1084
|
+
(newIndex) => {
|
|
1085
|
+
console.log("Current pane index:", newIndex);
|
|
1086
|
+
}
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1089
|
+
// Watch for visibility events
|
|
1090
|
+
watch(
|
|
1091
|
+
() => splitviewRef.value?.lastVisibilityEvent,
|
|
1092
|
+
(event) => {
|
|
1093
|
+
if (event) {
|
|
1094
|
+
console.log("Visibility event:", event);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
);
|
|
1098
|
+
</script>
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
## Migration Guide
|
|
1102
|
+
|
|
1103
|
+
### From v1 to v2
|
|
1104
|
+
|
|
1105
|
+
- `componentId` prop is now optional with auto-generation
|
|
1106
|
+
- Pane interface has been updated with new properties
|
|
1107
|
+
- Animation system has been refactored for better performance
|
|
1108
|
+
- Composable API has been enhanced with new methods
|
|
1109
|
+
|
|
1110
|
+
### Breaking Changes
|
|
1111
|
+
|
|
1112
|
+
- Removed automatic pane detection
|
|
1113
|
+
- Changed animation timing and easing
|
|
1114
|
+
- Updated CSS class structure
|
|
1115
|
+
- Modified event handling system
|