@dolanske/vui 1.1.4 → 1.2.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.
@@ -2,6 +2,7 @@
2
2
  import { Icon } from '@iconify/vue'
3
3
  import { ref } from 'vue'
4
4
  import Button from '../components/Button/Button.vue'
5
+ import Flex from '../components/Flex/Flex.vue'
5
6
  import Tab from '../components/Tabs/Tab.vue'
6
7
  import Tabs from '../components/Tabs/Tabs.vue'
7
8
  // import Flex from '../components/Flex/Flex.vue'
@@ -9,8 +10,8 @@ import Tabs from '../components/Tabs/Tabs.vue'
9
10
  const activeTab = ref('Home')
10
11
 
11
12
  // Dynamic test
12
- // const dynamicTabs = ref(['First', 'Second', "Third"])
13
- // const activeDynamic = ref(dynamicTabs.value[0])
13
+ const dynamicTabs = ref(['First', 'Second', 'Third'])
14
+ const activeDynamic = ref(dynamicTabs.value[0])
14
15
  </script>
15
16
 
16
17
  <template>
@@ -24,9 +25,9 @@ const activeTab = ref('Home')
24
25
  <th>Base</th>
25
26
  <td>
26
27
  <Tabs v-model="activeTab">
27
- <Tab label="Home" />
28
- <Tab label="About" />
29
- <Tab label="You" />
28
+ <Tab value="Home" />
29
+ <Tab value="About" />
30
+ <Tab value="You" />
30
31
  </Tabs>
31
32
  </td>
32
33
  </tr>
@@ -34,9 +35,9 @@ const activeTab = ref('Home')
34
35
  <th>Filled</th>
35
36
  <td>
36
37
  <Tabs v-model="activeTab" variant="filled">
37
- <Tab label="Home" />
38
- <Tab label="About" />
39
- <Tab label="You" />
38
+ <Tab value="Home" />
39
+ <Tab value="About" />
40
+ <Tab value="You" />
40
41
  </Tabs>
41
42
  </td>
42
43
  </tr>
@@ -44,17 +45,17 @@ const activeTab = ref('Home')
44
45
  <th>Expanded</th>
45
46
  <td class="w-100">
46
47
  <Tabs v-model="activeTab" expand>
47
- <Tab label="Home" />
48
- <Tab label="About" />
49
- <Tab label="You" />
48
+ <Tab value="Home" />
49
+ <Tab value="About" />
50
+ <Tab value="You" />
50
51
  </Tabs>
51
52
 
52
53
  <div class="mb-xl" />
53
54
 
54
55
  <Tabs v-model="activeTab" expand variant="filled">
55
- <Tab label="Home" />
56
- <Tab label="About" />
57
- <Tab label="You" />
56
+ <Tab value="Home" />
57
+ <Tab value="About" />
58
+ <Tab value="You" />
58
59
  </Tabs>
59
60
  </td>
60
61
  </tr>
@@ -70,17 +71,17 @@ const activeTab = ref('Home')
70
71
  Sidebar
71
72
  </Button>
72
73
  </template>
73
- <Tab label="Home" />
74
- <Tab label="About" />
75
- <Tab label="You" />
74
+ <Tab value="Home" />
75
+ <Tab value="About" />
76
+ <Tab value="You" />
76
77
  </Tabs>
77
78
 
78
79
  <div class="mb-xl" />
79
80
 
80
81
  <Tabs v-model="activeTab" variant="filled">
81
- <Tab label="Home" />
82
- <Tab label="About" />
83
- <Tab label="You" />
82
+ <Tab value="Home" />
83
+ <Tab value="About" />
84
+ <Tab value="You" />
84
85
 
85
86
  <template #end>
86
87
  <Button icon="ph:x" plain />
@@ -100,17 +101,17 @@ const activeTab = ref('Home')
100
101
  Sidebar
101
102
  </Button>
102
103
  </template>
103
- <Tab label="Home" />
104
- <Tab label="About" />
105
- <Tab label="You" />
104
+ <Tab value="Home" />
105
+ <Tab value="About" />
106
+ <Tab value="You" />
106
107
  </Tabs>
107
108
 
108
109
  <div class="mb-xl" />
109
110
 
110
111
  <Tabs v-model="activeTab" expand variant="filled">
111
- <Tab label="Home" />
112
- <Tab label="About" />
113
- <Tab label="You" />
112
+ <Tab value="Home" />
113
+ <Tab value="About" />
114
+ <Tab value="You" />
114
115
 
115
116
  <template #end>
116
117
  <Button icon="ph:x" plain />
@@ -118,18 +119,22 @@ const activeTab = ref('Home')
118
119
  </Tabs>
119
120
  </td>
120
121
  </tr>
121
- <!-- <tr>
122
+ <tr>
122
123
  <th>Dynamic</th>
123
124
  <td>
124
125
  <Flex>
125
- <Button @click="dynamicTabs.push(`Tab ${dynamicTabs.length}`)">Add</Button>
126
- <Button @click="dynamicTabs.shift()">Remove</Button>
126
+ <Button @click="dynamicTabs.push(`Tab ${dynamicTabs.length}`)">
127
+ Add
128
+ </Button>
129
+ <Button @click="dynamicTabs.shift()">
130
+ Remove
131
+ </Button>
127
132
  </Flex>
128
- <Tabs v-model="dynamicTabs">
129
- <Tab v-for="tab in dynamicTabs" />
133
+ <Tabs v-model="activeDynamic">
134
+ <Tab v-for="tab in dynamicTabs" :key="tab" :value="tab" />
130
135
  </Tabs>
131
136
  </td>
132
- </tr> -->
137
+ </tr>
133
138
  </tbody>
134
139
  </table>
135
140
  </div>
@@ -0,0 +1,61 @@
1
+ import type { ShallowRef, VNode } from 'vue'
2
+ import { computed, Fragment, shallowRef, watchEffect } from 'vue'
3
+
4
+ type VNodesProps<T extends object> = Array<VNode & { props: T }>
5
+
6
+ /**
7
+ * Flattens slot children and keeps them in sync reactively.
8
+ * @param slotFn The slot function (e.g., slots.default)
9
+ * @returns Computed array of flattened VNodes
10
+ */
11
+ export function useFlattenedSlot<T extends object>(slotFn?: () => VNode[] | undefined): ShallowRef<VNodesProps<T>> {
12
+ const rawChildren = shallowRef<VNodesProps<T>>([])
13
+
14
+ // Flatten VNodes recursively (handles Fragments)
15
+ function flatten(vnodes: VNode[]): VNodesProps<T> {
16
+ const result: VNode[] = []
17
+
18
+ const walk = (nodes: VNode[] | VNode | undefined): void => {
19
+ if (!nodes)
20
+ return
21
+
22
+ if (Array.isArray(nodes)) {
23
+ nodes.forEach(walk)
24
+ }
25
+ else if (nodes.type === Fragment || Array.isArray(nodes.children)) {
26
+ walk(nodes.children as VNode[])
27
+ }
28
+ else {
29
+ result.push(nodes)
30
+ }
31
+ }
32
+
33
+ walk(vnodes)
34
+ return result as VNodesProps<T>
35
+ }
36
+
37
+ // Re-compute children whenever slot content changes
38
+ watchEffect(() => {
39
+ const content = slotFn?.() ?? []
40
+ rawChildren.value = flatten(content)
41
+ })
42
+
43
+ return computed(() => rawChildren.value)
44
+ }
45
+
46
+ /**
47
+ * Checks whether all of the provided VNodes are of the same type. Throws an
48
+ * error if not. This function should be used in components that only allow a
49
+ * single type of component
50
+ *
51
+ * @param vnodes Array of VNodes to check
52
+ * @param name Expected name of the components
53
+ */
54
+ export function enforceSlotType(vnodes: ShallowRef<VNodesProps<any>>, name: string): void {
55
+ watchEffect(() => {
56
+ // @ts-expect-error Accessing internals
57
+ if (vnodes.value.some(item => item.type.__name !== name)) {
58
+ throw new Error(`You can only pass \`<${name} />\` components as children.`)
59
+ }
60
+ })
61
+ }