@indielayer/ui 1.0.0-alpha.7 → 1.0.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.
Files changed (209) hide show
  1. package/README.md +6 -3
  2. package/lib/index.cjs.js +1 -15
  3. package/lib/index.es.js +4453 -3651
  4. package/lib/nuxt.js +2 -1
  5. package/package.json +16 -6
  6. package/src/common/icons.ts +15 -0
  7. package/src/common/utils.ts +68 -0
  8. package/src/components/alert/Alert.theme.ts +57 -0
  9. package/src/components/alert/Alert.vue +51 -127
  10. package/src/components/alert/__tests__/Alert.spec.ts +14 -0
  11. package/src/components/avatar/Avatar.theme.ts +39 -0
  12. package/src/components/avatar/Avatar.vue +58 -96
  13. package/src/components/avatar/__tests__/Avatar.spec.ts +11 -0
  14. package/src/components/badge/Badge.theme.ts +13 -0
  15. package/src/components/badge/Badge.vue +58 -65
  16. package/src/components/badge/__tests__/Badge.spec.ts +11 -0
  17. package/src/components/breadcrumbs/Breadcrumbs.theme.ts +9 -0
  18. package/src/components/breadcrumbs/Breadcrumbs.vue +34 -24
  19. package/src/components/breadcrumbs/__tests__/Breadcrumbs.spec.ts +11 -0
  20. package/src/components/button/Button.theme.ts +234 -0
  21. package/src/components/button/Button.vue +94 -356
  22. package/src/components/button/ButtonGroup.theme.ts +5 -0
  23. package/src/components/button/ButtonGroup.vue +30 -29
  24. package/src/components/button/__tests__/ Button.spec.ts +11 -0
  25. package/src/components/button/__tests__/ ButtonGroup.spec.ts +11 -0
  26. package/src/components/card/Card.theme.ts +7 -0
  27. package/src/components/card/Card.vue +18 -11
  28. package/src/components/card/__tests__/Card.spec.ts +11 -0
  29. package/src/components/checkbox/Checkbox.theme.ts +92 -0
  30. package/src/components/checkbox/Checkbox.vue +69 -156
  31. package/src/components/checkbox/__tests__/Checkbox.spec.ts +11 -0
  32. package/src/components/collapse/Collapse.theme.ts +11 -0
  33. package/src/components/collapse/Collapse.vue +99 -118
  34. package/src/components/collapse/__tests__/Collapse.spec.ts +11 -0
  35. package/src/components/container/Container.theme.ts +7 -0
  36. package/src/components/container/Container.vue +17 -9
  37. package/src/components/container/__tests__/Container.spec.ts +11 -0
  38. package/src/components/divider/Divider.theme.ts +11 -0
  39. package/src/components/divider/Divider.vue +22 -18
  40. package/src/components/divider/__tests__/Divider.spec.ts +11 -0
  41. package/src/components/drawer/Drawer.theme.ts +9 -0
  42. package/src/components/drawer/Drawer.vue +160 -177
  43. package/src/components/drawer/__tests__/Drawer.spec.ts +11 -0
  44. package/src/components/form/Form.theme.ts +7 -0
  45. package/src/components/form/Form.vue +90 -73
  46. package/src/components/form/__tests__/Form.spec.ts +11 -0
  47. package/src/components/helpers/InputError.tsx +14 -0
  48. package/src/components/icon/Icon.theme.ts +16 -0
  49. package/src/components/icon/Icon.vue +72 -88
  50. package/src/components/icon/__tests__/Icon.spec.ts +11 -0
  51. package/src/components/image/Image.theme.ts +7 -0
  52. package/src/components/image/Image.vue +22 -23
  53. package/src/components/image/__tests__/Image.spec.ts +11 -0
  54. package/src/components/index.ts +3 -3
  55. package/src/components/input/Input.theme.ts +44 -0
  56. package/src/components/input/Input.vue +97 -130
  57. package/src/components/input/__tests__/Input.spec.ts +11 -0
  58. package/src/components/link/Link.theme.ts +26 -0
  59. package/src/components/link/Link.vue +41 -66
  60. package/src/components/link/__tests__/Link.spec.ts +11 -0
  61. package/src/components/menu/Menu.theme.ts +7 -0
  62. package/src/components/menu/Menu.vue +54 -45
  63. package/src/components/menu/MenuItem.theme.ts +107 -0
  64. package/src/components/menu/MenuItem.vue +97 -199
  65. package/src/components/menu/__tests__/Menu.spec.ts +11 -0
  66. package/src/components/menu/__tests__/MenuItem.spec.ts +11 -0
  67. package/src/components/modal/Modal.theme.ts +29 -0
  68. package/src/components/modal/Modal.vue +78 -101
  69. package/src/components/modal/__tests__/Modal.spec.ts +11 -0
  70. package/src/components/notifications/Notifications.theme.ts +11 -0
  71. package/src/components/notifications/Notifications.vue +233 -247
  72. package/src/components/notifications/__tests__/Notifications.spec.ts +11 -0
  73. package/src/components/pagination/Pagination.theme.ts +27 -0
  74. package/src/components/pagination/Pagination.vue +142 -164
  75. package/src/components/pagination/PaginationItem.theme.ts +14 -0
  76. package/src/components/pagination/PaginationItem.vue +26 -33
  77. package/src/components/pagination/__tests__/Pagination.spec.ts +11 -0
  78. package/src/components/pagination/__tests__/PaginationItem.spec.ts +11 -0
  79. package/src/components/popover/Popover.theme.ts +9 -0
  80. package/src/components/popover/Popover.vue +153 -101
  81. package/src/components/popover/PopoverContainer.theme.ts +7 -0
  82. package/src/components/popover/PopoverContainer.vue +17 -9
  83. package/src/components/popover/__tests__/Popover.spec.ts +11 -0
  84. package/src/components/popover/__tests__/PopoverContainer.spec.ts +11 -0
  85. package/src/components/progress/Progress.theme.ts +26 -0
  86. package/src/components/progress/Progress.vue +29 -53
  87. package/src/components/progress/__tests__/Progress.spec.ts +11 -0
  88. package/src/components/radio/Radio.theme.ts +121 -0
  89. package/src/components/radio/Radio.vue +81 -158
  90. package/src/components/radio/__tests__/Radio.spec.ts +11 -0
  91. package/src/components/scroll/Scroll.theme.ts +7 -0
  92. package/src/components/scroll/Scroll.vue +34 -36
  93. package/src/components/scroll/__tests__/Scroll.spec.ts +11 -0
  94. package/src/components/select/Select.theme.ts +54 -0
  95. package/src/components/select/Select.vue +219 -273
  96. package/src/components/select/__tests__/Select.spec.ts +11 -0
  97. package/src/components/skeleton/Skeleton.theme.ts +7 -0
  98. package/src/components/skeleton/Skeleton.vue +17 -9
  99. package/src/components/skeleton/__tests__/Skeleton.spec.ts +11 -0
  100. package/src/components/slider/Slider.theme.ts +30 -0
  101. package/src/components/slider/Slider.vue +135 -168
  102. package/src/components/slider/__tests__/Slider.spec.ts +11 -0
  103. package/src/components/spacer/{Spacer.vue → Spacer.tsx} +3 -6
  104. package/src/components/spacer/__tests__/Spacer.spec.ts +11 -0
  105. package/src/components/spinner/Spinner.vue +10 -34
  106. package/src/components/spinner/__tests__/Spinner.spec.ts +11 -0
  107. package/src/components/tab/Tab.theme.ts +22 -0
  108. package/src/components/tab/Tab.vue +89 -93
  109. package/src/components/tab/TabGroup.theme.ts +43 -0
  110. package/src/components/tab/TabGroup.vue +94 -127
  111. package/src/components/tab/__tests__/Tab.spec.ts +11 -0
  112. package/src/components/tab/__tests__/TabGroup.spec.ts +11 -0
  113. package/src/components/table/Table.theme.ts +19 -0
  114. package/src/components/table/Table.vue +136 -147
  115. package/src/components/table/{TableBody.vue → TableBody.tsx} +3 -8
  116. package/src/components/table/TableCell.theme.ts +27 -0
  117. package/src/components/table/TableCell.vue +30 -58
  118. package/src/components/table/TableHead.tsx +14 -0
  119. package/src/components/table/TableHeader.vue +18 -20
  120. package/src/components/table/TableRow.vue +23 -20
  121. package/src/components/table/__tests__/Table.spec.ts +11 -0
  122. package/src/components/tag/Tag.theme.ts +32 -0
  123. package/src/components/tag/Tag.vue +40 -68
  124. package/src/components/tag/__tests__/Tag.spec.ts +11 -0
  125. package/src/components/textarea/Textarea.theme.ts +62 -0
  126. package/src/components/textarea/Textarea.vue +100 -115
  127. package/src/components/textarea/__tests__/Textarea.spec.ts +11 -0
  128. package/src/components/toggle/Toggle.theme.ts +51 -0
  129. package/src/components/toggle/Toggle.vue +51 -81
  130. package/src/components/toggle/__tests__/Toggle.spec.ts +11 -0
  131. package/src/components/tooltip/Tooltip.theme.ts +51 -0
  132. package/src/components/tooltip/Tooltip.vue +9 -14
  133. package/src/components/tooltip/__tests__/Tooltip.spec.ts +11 -0
  134. package/src/composables/colors-utils.ts +68 -68
  135. package/src/composables/colors.ts +18 -6
  136. package/src/composables/common.ts +1 -0
  137. package/src/composables/css.ts +7 -2
  138. package/src/composables/index.ts +1 -1
  139. package/src/composables/inputtable.ts +1 -1
  140. package/src/composables/interactive.ts +8 -4
  141. package/src/composables/keys.ts +1 -0
  142. package/src/composables/notifications.ts +10 -0
  143. package/src/composables/theme.ts +88 -0
  144. package/src/create.ts +9 -4
  145. package/src/exports/nuxt.js +2 -1
  146. package/src/version.ts +1 -1
  147. package/volar.d.ts +1 -0
  148. package/lib/components/alert/Alert.vue.d.ts +0 -42
  149. package/lib/components/avatar/Avatar.vue.d.ts +0 -49
  150. package/lib/components/badge/Badge.vue.d.ts +0 -75
  151. package/lib/components/breadcrumbs/Breadcrumbs.vue.d.ts +0 -30
  152. package/lib/components/button/Button.vue.d.ts +0 -87
  153. package/lib/components/button/ButtonGroup.vue.d.ts +0 -49
  154. package/lib/components/card/Card.vue.d.ts +0 -17
  155. package/lib/components/checkbox/Checkbox.vue.d.ts +0 -81
  156. package/lib/components/collapse/Collapse.vue.d.ts +0 -47
  157. package/lib/components/container/Container.vue.d.ts +0 -14
  158. package/lib/components/divider/Divider.vue.d.ts +0 -10
  159. package/lib/components/drawer/Drawer.vue.d.ts +0 -73
  160. package/lib/components/form/Form.vue.d.ts +0 -46
  161. package/lib/components/icon/Icon.vue.d.ts +0 -40
  162. package/lib/components/image/Image.vue.d.ts +0 -8
  163. package/lib/components/index.d.ts +0 -45
  164. package/lib/components/input/Input.vue.d.ts +0 -117
  165. package/lib/components/link/Link.vue.d.ts +0 -36
  166. package/lib/components/menu/Menu.vue.d.ts +0 -62
  167. package/lib/components/menu/MenuItem.vue.d.ts +0 -114
  168. package/lib/components/modal/Modal.vue.d.ts +0 -34
  169. package/lib/components/notifications/Notifications.vue.d.ts +0 -104
  170. package/lib/components/pagination/Pagination.vue.d.ts +0 -58
  171. package/lib/components/pagination/PaginationItem.vue.d.ts +0 -32
  172. package/lib/components/popover/Popover.vue.d.ts +0 -64
  173. package/lib/components/popover/PopoverContainer.vue.d.ts +0 -14
  174. package/lib/components/progress/Progress.vue.d.ts +0 -42
  175. package/lib/components/radio/Radio.vue.d.ts +0 -79
  176. package/lib/components/scroll/Scroll.vue.d.ts +0 -29
  177. package/lib/components/select/Select.vue.d.ts +0 -100
  178. package/lib/components/skeleton/Skeleton.vue.d.ts +0 -14
  179. package/lib/components/slider/Slider.vue.d.ts +0 -96
  180. package/lib/components/spacer/Spacer.vue.d.ts +0 -2
  181. package/lib/components/spinner/Spinner.vue.d.ts +0 -16
  182. package/lib/components/tab/Tab.vue.d.ts +0 -52
  183. package/lib/components/tab/TabGroup.vue.d.ts +0 -61
  184. package/lib/components/table/Table.vue.d.ts +0 -82
  185. package/lib/components/table/TableBody.vue.d.ts +0 -2
  186. package/lib/components/table/TableCell.vue.d.ts +0 -33
  187. package/lib/components/table/TableHead.vue.d.ts +0 -2
  188. package/lib/components/table/TableHeader.vue.d.ts +0 -33
  189. package/lib/components/table/TableRow.vue.d.ts +0 -23
  190. package/lib/components/tag/Tag.vue.d.ts +0 -45
  191. package/lib/components/textarea/Textarea.vue.d.ts +0 -106
  192. package/lib/components/toggle/Toggle.vue.d.ts +0 -79
  193. package/lib/components/tooltip/Tooltip.vue.d.ts +0 -2
  194. package/lib/composables/colors-utils.d.ts +0 -8
  195. package/lib/composables/colors.d.ts +0 -26
  196. package/lib/composables/common.d.ts +0 -14
  197. package/lib/composables/css.d.ts +0 -5
  198. package/lib/composables/index.d.ts +0 -7
  199. package/lib/composables/inputtable.d.ts +0 -37
  200. package/lib/composables/interactive.d.ts +0 -10
  201. package/lib/composables/keys.d.ts +0 -7
  202. package/lib/composables/notification.d.ts +0 -1
  203. package/lib/create.d.ts +0 -12
  204. package/lib/index.d.ts +0 -6
  205. package/lib/install.d.ts +0 -4
  206. package/lib/style.css +0 -1
  207. package/lib/version.d.ts +0 -2
  208. package/src/components/table/TableHead.vue +0 -15
  209. package/src/composables/notification.ts +0 -10
@@ -1,120 +1,111 @@
1
1
  <script lang="ts">
2
- import { defineComponent, inject, reactive, computed, toRefs, ref, onMounted, onBeforeUnmount } from 'vue'
2
+ export default { name: 'XTab' }
3
+ </script>
4
+
5
+ <script setup lang="ts">
6
+ import { inject, reactive, computed, ref, onMounted } from 'vue'
3
7
  import { useMutationObserver } from '@vueuse/core'
4
8
  import { injectTabKey } from '../../composables/keys'
5
9
  import { useCommon } from '../../composables/common'
10
+ import { useTheme } from '../../composables/theme'
11
+
6
12
  import XIcon from '../icon/Icon.vue'
7
13
  import XLink from '../link/Link.vue'
8
14
 
9
- export default defineComponent({
10
- name: 'XTab',
15
+ import theme from './Tab.theme'
11
16
 
12
- components: {
13
- XIcon,
14
- XLink,
17
+ const props = defineProps({
18
+ ...useCommon.props(),
19
+ value: {
20
+ type: [String, Number],
15
21
  },
16
-
17
- props: {
18
- ...useCommon.props(),
19
- value: {
20
- type: [String, Number],
21
- },
22
- tag: {
23
- type: String,
24
- default: 'div',
25
- },
26
- to: String,
27
- label: String,
28
- icon: String,
29
- disabled: Boolean,
30
- exact: Boolean,
22
+ tag: {
23
+ type: String,
24
+ default: 'div',
31
25
  },
26
+ to: String,
27
+ label: String,
28
+ icon: String,
29
+ disabled: Boolean,
30
+ exact: Boolean,
31
+ })
32
32
 
33
- setup(props) {
34
- const cValue = computed(() => props.to || props.value )
35
- const cLabel = computed(() => props.label || props.value)
36
- const teleportTo = ref(null)
37
- const elRef = ref()
38
-
39
- const tabs = inject(injectTabKey, {
40
- tabsContentRef: ref(null),
41
- activateTab: () => {},
42
- state: reactive({
43
- active: null,
44
- variant: 'line',
45
- grow: false,
46
- }),
47
- })
33
+ const computedValue = computed(() => props.to || props.value )
34
+ const computedLabel = computed(() => props.label || props.value)
35
+ const teleportTo = ref(null)
36
+ const elRef = ref<HTMLElement | typeof XLink | null>(null)
37
+
38
+ const tabs = inject(injectTabKey, {
39
+ tabsContentRef: ref(null),
40
+ activateTab: () => {},
41
+ state: reactive({
42
+ active: false,
43
+ variant: 'line',
44
+ ghost: false,
45
+ grow: false,
46
+ exact: false,
47
+ size: 'md',
48
+ color: 'primary',
49
+ }),
50
+ })
48
51
 
49
- const cExact = computed(() => tabs.state.exact || props.exact)
50
- const cSize = computed(() => props.size || tabs.state.size)
52
+ const computedExact = computed(() => tabs.state.exact || props.exact)
53
+ const computedSize = computed(() => props.size || tabs.state.size)
51
54
 
52
- onMounted(() => {
53
- teleportTo.value = tabs.tabsContentRef.value
55
+ onMounted(() => {
56
+ teleportTo.value = tabs.tabsContentRef.value
54
57
 
55
- if (props.to) {
56
- check()
57
- useMutationObserver(elRef.value.$el, check, {
58
- attributes: true,
59
- attributeFilter: ['class'],
60
- })
61
- }
58
+ if (props.to && elRef.value) {
59
+ check()
60
+ useMutationObserver((elRef.value as typeof XLink).$el, check, {
61
+ attributes: true,
62
+ attributeFilter: ['class'],
62
63
  })
64
+ }
65
+ })
63
66
 
64
- function check() {
65
- if (elRef.value && elRef.value.$el && (props.to)) {
66
- const active = elRef.value?.$el.classList.contains(cExact.value ? 'router-link-exact-active' : 'router-link-active')
67
-
68
- if (active) tabs.activateTab(cValue.value)
69
- }
70
- }
67
+ function check() {
68
+ if (elRef.value && (elRef.value as typeof XLink).$el && (props.to)) {
69
+ const active = (elRef.value as typeof XLink).$el.classList.contains(computedExact.value ? 'router-link-exact-active' : 'router-link-active')
71
70
 
72
- const state = reactive({
73
- selected: computed(() => tabs.state.active === cValue.value),
74
- })
71
+ if (active) tabs.activateTab(computedValue.value)
72
+ }
73
+ }
75
74
 
76
- function onClickTab() {
77
- if (!props.to) tabs.activateTab(cValue.value)
78
- }
75
+ const selected = computed(() => tabs.state.active === computedValue.value)
79
76
 
80
- const sizeClasses = computed(() => {
81
- if (cSize.value === 'xs') return 'text-xs'
82
- else if (cSize.value === 'sm') return 'text-sm'
83
- else if (cSize.value === 'lg') return 'text-lg'
84
- else if (cSize.value === 'xl') return 'text-xl'
77
+ const color = computed(() => tabs.state.color)
85
78
 
86
- return ''
87
- })
79
+ function onClickTab() {
80
+ if (!props.to) tabs.activateTab(computedValue.value)
81
+ }
88
82
 
89
- return {
90
- ...toRefs(state),
91
- variant: tabs.state.variant,
92
- grow: tabs.state.grow,
93
- elRef,
94
- cLabel,
95
- cValue,
96
- cSize,
97
- tabs,
98
- sizeClasses,
99
- teleportTo,
100
- onClickTab,
101
- }
102
- },
103
- })
83
+ const { styles, classes, className } = useTheme('tab', theme, ref({
84
+ ...props,
85
+ size: computedSize.value,
86
+ exact: computedExact.value,
87
+ }), tabs.state)
104
88
  </script>
105
89
 
106
90
  <template>
107
- <li :data-value="cValue" class="shrink-0 font-medium" :class="{ 'flex-1': grow }">
91
+ <li
92
+ :data-value="computedValue"
93
+ :style="styles"
94
+ class="shrink-0 font-medium"
95
+ :class="[
96
+ className,
97
+ { 'flex-1': tabs.state.grow }
98
+ ]"
99
+ >
108
100
  <component
109
- :is="to ? 'x-link' : tag"
101
+ :is="to ? XLink : tag"
110
102
  ref="elRef"
111
103
  :to="to"
112
- class="py-2 transition-colors duration-150 ease-in-out whitespace-nowrap text-center"
104
+ :color="selected ? color : undefined"
113
105
  :class="[
114
- sizeClasses,
106
+ classes.wrapper,
115
107
  {
116
- 'px-8': variant === 'block',
117
- 'text-[color:var(--x-tabs-text)] dark:text-[color:var(--x-dark-tabs-text)]': selected,
108
+ 'text-[color:var(--x-tabs-text)] dark:text-[color:var(--x-tabs-dark-text)]': selected,
118
109
  'cursor-pointer': !disabled,
119
110
  'cursor-not-allowed': disabled,
120
111
  'cursor-not-allowed text-gray-500': disabled && !selected,
@@ -128,17 +119,22 @@ export default defineComponent({
128
119
  name="tab"
129
120
  :label="label"
130
121
  :value="value"
131
- :size="cSize"
122
+ :size="computedSize"
132
123
  :icon="icon"
133
124
  >
134
125
  <div class="flex items-center justify-center">
135
- <XIcon v-if="icon" :icon="icon" :size="cSize" class="mr-1.5 shrink-0" />
136
- <span>{{ cLabel }}</span>
126
+ <x-icon
127
+ v-if="icon"
128
+ :icon="icon"
129
+ :size="computedSize"
130
+ :class="classes.icon"
131
+ />
132
+ <div :class="classes.label">{{ computedLabel }}</div>
137
133
  </div>
138
134
  </slot>
139
- <Teleport v-if="selected && teleportTo" :to="teleportTo">
135
+ <teleport v-if="selected && teleportTo" :to="teleportTo">
140
136
  <slot></slot>
141
- </Teleport>
137
+ </teleport>
142
138
  </component>
143
139
  </li>
144
140
  </template>
@@ -0,0 +1,43 @@
1
+ import type { ThemeParams } from '../../composables/theme'
2
+
3
+ export default {
4
+ classes: {
5
+ wrapper: '',
6
+
7
+ list: ({ props, colors, css }: ThemeParams) => {
8
+ const c = ['flex min-w-full w-fit']
9
+
10
+ if (props.variant === 'line') c.push('border-b border-gray-200 dark:border-gray-700')
11
+ if (props.variant === 'line' && !props.grow) c.push('space-x-8')
12
+ if (props.variant === 'block') c.push('z-[1]')
13
+ if (props.align === 'center') c.push('justify-center')
14
+ if (props.align === 'right') c.push('justify-end')
15
+
16
+ return c
17
+ },
18
+
19
+ tracker: ({ props }: ThemeParams) => {
20
+ const c = ['absolute transition-all duration-150']
21
+
22
+ if (props.variant === 'line') c.push('h-[2px] -mt-[2px] bg-[color:var(--x-tabs-text)] dark:bg-[color:var(--x-tabs-dark-text)]')
23
+
24
+ if (props.variant === 'block') c.push('rounded-md h-full top-0 bg-[color:var(--x-tabs-bg)] dark:bg-[color:var(--x-tabs-dark-bg)]')
25
+
26
+ return c
27
+ },
28
+ },
29
+
30
+ styles: ({ props, colors, css }: ThemeParams) => {
31
+ const gray = colors.getPalette('gray')
32
+ const color = colors.getPalette(props.color)
33
+
34
+ return css.variables({
35
+ text: color[600],
36
+ bg: props.ghost ? color[50] : '#fff',
37
+ dark: {
38
+ text: color[400],
39
+ bg: props.ghost ? color[900] : gray[700],
40
+ },
41
+ })
42
+ },
43
+ }
@@ -1,127 +1,100 @@
1
1
  <script lang="ts">
2
- import { defineComponent, reactive, computed, provide, type PropType, ref, watch, onMounted, watchEffect } from 'vue'
2
+ export default { name: 'XTabGroup' }
3
+ </script>
4
+
5
+ <script setup lang="ts">
6
+ import { reactive, computed, provide, type PropType, ref, watch, onMounted, watchEffect } from 'vue'
7
+ import { useResizeObserver, useThrottleFn } from '@vueuse/core'
3
8
  import { injectTabKey } from '../../composables/keys'
4
9
  import { useCommon } from '../../composables/common'
5
- import { useCSS } from '../../composables/css'
6
10
  import { useColors } from '../../composables/colors'
7
-
8
- import { useResizeObserver, useThrottleFn } from '@vueuse/core'
11
+ import { useTheme } from '../../composables/theme'
9
12
 
10
13
  import XScroll from '../../components/scroll/Scroll.vue'
11
14
 
12
- export default defineComponent({
13
- name: 'XTabGroup',
15
+ import theme from './TabGroup.theme'
14
16
 
15
- components: {
16
- XScroll,
17
+ const props = defineProps({
18
+ ...useCommon.props(),
19
+ ...useColors.props('primary'),
20
+ modelValue: [String, Number],
21
+ variant: {
22
+ type: String as PropType<'line' | 'block'>,
23
+ default: 'line',
17
24
  },
18
-
19
- props: {
20
- ...useCommon.props(),
21
- ...useColors.props('primary'),
22
- modelValue: [String, Number],
23
- variant: {
24
- type: String as PropType<'line' | 'block'>,
25
- default: 'line',
26
- },
27
- align: {
28
- type: String as PropType<'left' | 'center' | 'right'>,
29
- default: 'left',
30
- },
31
- ghost: Boolean,
32
- grow: Boolean,
33
- exact: Boolean,
25
+ align: {
26
+ type: String as PropType<'left' | 'center' | 'right'>,
27
+ default: 'left',
34
28
  },
29
+ ghost: Boolean,
30
+ grow: Boolean,
31
+ exact: Boolean,
32
+ })
35
33
 
36
- emits: ['update:modelValue'],
37
-
38
- setup(props, { emit }) {
39
- const scrollRef = ref()
40
- const wrapperRef = ref<HTMLElement>()
41
- const trackerRef = ref<HTMLElement>()
42
- const tabsRef = ref<HTMLElement>()
43
- const tabsContentRef = ref<HTMLElement>()
44
-
45
- const active = ref()
46
-
47
- watchEffect(() => {
48
- active.value = props.modelValue
49
- })
50
-
51
- const state = reactive({
52
- active: computed(() => active.value),
53
- variant: computed(() => props.variant),
54
- ghost: computed(() => props.ghost),
55
- grow: computed(() => props.grow),
56
- exact: computed(() => props.exact),
57
- size: computed(() => props.size),
58
- })
59
-
60
- function activateTab(tab: string | number) {
61
- active.value = tab
62
- emit('update:modelValue', tab)
63
- }
64
-
65
- provide(injectTabKey, {
66
- tabsContentRef,
67
- activateTab,
68
- state,
69
- })
70
-
71
- const updateTracker = useThrottleFn((value: string | number | undefined) => {
72
- if (typeof value === 'undefined') return
73
-
74
- const tabEl = tabsRef.value?.querySelector(`[data-value="${value}"]`) as HTMLElement
75
-
76
- if (!tabEl || !trackerRef.value) return
77
-
78
- trackerRef.value.style.left = `${tabEl.offsetLeft}px`
79
- trackerRef.value.style.width = `${tabEl.offsetWidth}px`
80
-
81
- if (!tabsRef.value || !scrollRef.value) return
82
-
83
- // scrollIntoView only updates one at a time
84
- const center = tabEl.offsetLeft - (tabsRef.value.getBoundingClientRect().width - tabEl.getBoundingClientRect().width) / 2
85
-
86
- if (scrollRef.value.scrollEl) scrollRef.value.scrollEl.scrollTo({ left: center, behavior: 'smooth' })
87
- }, 100)
88
-
89
- useResizeObserver(wrapperRef, () => { updateTracker(active.value) })
90
-
91
- watch(() => active.value, (value) => {
92
- updateTracker(value)
93
- })
94
-
95
- onMounted(() => {
96
- updateTracker(active.value)
97
- })
98
-
99
- const css = useCSS('tabs')
100
- const colors = useColors()
101
- const gray = colors.getPalette('gray')
102
- const style = computed(() => {
103
- const color = colors.getPalette(props.color)
104
-
105
- return css.variables({
106
- text: color[600],
107
- bg: props.ghost ? color[50] : '#fff',
108
- dark: {
109
- text: color[400],
110
- bg: props.ghost ? color[900] : gray[700],
111
- },
112
- })
113
- })
114
-
115
- return {
116
- scrollRef,
117
- wrapperRef,
118
- trackerRef,
119
- tabsRef,
120
- tabsContentRef,
121
- style,
122
- }
123
- },
34
+ const emit = defineEmits(['update:modelValue'])
35
+
36
+ const scrollRef = ref<typeof XScroll | null>(null)
37
+ const wrapperRef = ref<HTMLElement | null>(null)
38
+ const trackerRef = ref<HTMLElement | null>(null)
39
+ const tabsRef = ref<HTMLElement | null>(null)
40
+ const tabsContentRef = ref<HTMLElement | null>(null)
41
+
42
+ const active = ref()
43
+
44
+ watchEffect(() => {
45
+ active.value = props.modelValue
124
46
  })
47
+
48
+ const state = reactive({
49
+ active: computed(() => active.value),
50
+ variant: computed(() => props.variant),
51
+ ghost: computed(() => props.ghost),
52
+ grow: computed(() => props.grow),
53
+ exact: computed(() => props.exact),
54
+ size: computed(() => props.size),
55
+ color: computed(() => props.color),
56
+ })
57
+
58
+ function activateTab(tab: string | number) {
59
+ active.value = tab
60
+ emit('update:modelValue', tab)
61
+ }
62
+
63
+ provide(injectTabKey, {
64
+ tabsContentRef,
65
+ activateTab,
66
+ state,
67
+ })
68
+
69
+ const updateTracker = useThrottleFn((value: string | number | undefined) => {
70
+ if (typeof value === 'undefined') return
71
+
72
+ const tabEl = tabsRef.value?.querySelector(`[data-value="${value}"]`) as HTMLElement
73
+
74
+ if (!tabEl || !trackerRef.value) return
75
+
76
+ trackerRef.value.style.left = `${tabEl.offsetLeft}px`
77
+ trackerRef.value.style.width = `${tabEl.offsetWidth}px`
78
+
79
+ if (!tabsRef.value || !scrollRef.value) return
80
+
81
+ // scrollIntoView only updates one at a time
82
+ const center = tabEl.offsetLeft - (tabsRef.value.getBoundingClientRect().width - tabEl.getBoundingClientRect().width) / 2
83
+
84
+ if (scrollRef.value.scrollEl) scrollRef.value.scrollEl.scrollTo({ left: center, behavior: 'smooth' })
85
+ }, 100)
86
+
87
+ useResizeObserver(wrapperRef, () => { updateTracker(active.value) })
88
+
89
+ watch(() => active.value, (value) => {
90
+ updateTracker(value)
91
+ })
92
+
93
+ onMounted(() => {
94
+ updateTracker(active.value)
95
+ })
96
+
97
+ const { styles, classes, className } = useTheme('tabs', theme, props)
125
98
  </script>
126
99
 
127
100
  <template>
@@ -129,7 +102,11 @@ export default defineComponent({
129
102
  <div
130
103
  ref="wrapperRef"
131
104
  class="relative"
132
- :style="style"
105
+ :style="styles"
106
+ :class="[
107
+ className,
108
+ classes.wrapper,
109
+ ]"
133
110
  >
134
111
  <x-scroll
135
112
  ref="scrollRef"
@@ -138,29 +115,19 @@ export default defineComponent({
138
115
  mousewheel
139
116
  :class="{
140
117
  'rounded-md': variant === 'block',
141
- 'bg-gray-50 dark:bg-gray-800 p-1': variant === 'block' && !ghost
118
+ 'bg-slate-100 dark:bg-gray-800 p-1': variant === 'block' && !ghost
142
119
  }"
143
120
  >
144
121
  <ul
145
122
  ref="tabsRef"
146
- class="flex relative min-w-full w-fit"
147
- :class="{
148
- 'border-b border-gray-200 dark:border-gray-700': variant === 'line',
149
- 'space-x-8': variant === 'line' && !grow,
150
- 'z-[1]': variant === 'block',
151
- 'justify-center': align === 'center',
152
- 'justify-end': align === 'right'
153
- }"
123
+ class="relative"
124
+ :class="classes.list"
154
125
  >
155
126
  <slot></slot>
156
127
  </ul>
157
128
  <div
158
129
  ref="trackerRef"
159
- class="absolute transition-all duration-150"
160
- :class="{
161
- 'h-[2px] -mt-[2px] bg-[color:var(--x-tabs-text)] dark:bg-[color:var(--x-dark-tabs-text)]': variant === 'line',
162
- 'rounded-md h-full top-0 bg-[color:var(--x-tabs-bg)] dark:bg-[color:var(--x-dark-tabs-bg)]': variant === 'block'
163
- }"
130
+ :class="classes.tracker"
164
131
  ></div>
165
132
  </x-scroll>
166
133
  </div>
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import Tab from '../Tab.vue'
4
+
5
+ describe('Tab', () => {
6
+ it('renders without errors', () => {
7
+ const wrapper = mount(Tab)
8
+
9
+ expect(wrapper.vm).toBeTruthy()
10
+ })
11
+ })
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import TabGroup from '../TabGroup.vue'
4
+
5
+ describe('TabGroup', () => {
6
+ it('renders without errors', () => {
7
+ const wrapper = mount(TabGroup)
8
+
9
+ expect(wrapper.vm).toBeTruthy()
10
+ })
11
+ })
@@ -0,0 +1,19 @@
1
+ import type { ThemeParams } from '../../composables/theme'
2
+
3
+ export default {
4
+ classes: {
5
+ wrapper: ({ props, data }: ThemeParams) => {
6
+ const c = ['w-full relative']
7
+
8
+ if (props.scrollable === 'block') c.push('overflow-x-scroll sm:overflow-x-auto whitespace-wrap sm:whitespace-normal block sm:table')
9
+
10
+ if (props.stickyHeader) c.push('relative')
11
+
12
+ if (props.fixed) c.push('table-fixed')
13
+
14
+ return c
15
+ },
16
+
17
+ loadingWrapper: 'absolute inset-0 flex items-center justify-center z-40 bg-gray-300 dark:bg-gray-600 rounded opacity-50',
18
+ },
19
+ }