@indielayer/ui 1.0.0-alpha.0 → 1.0.0-alpha.5

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -72
  3. package/lib/components/avatar/Avatar.vue.d.ts +2 -2
  4. package/lib/components/badge/Badge.vue.d.ts +2 -2
  5. package/lib/components/button/Button.vue.d.ts +2 -2
  6. package/lib/components/button/ButtonGroup.vue.d.ts +2 -2
  7. package/lib/components/checkbox/Checkbox.vue.d.ts +4 -3
  8. package/lib/components/drawer/Drawer.vue.d.ts +2 -2
  9. package/lib/components/icon/Icon.vue.d.ts +7 -3
  10. package/lib/components/index.d.ts +2 -2
  11. package/lib/components/input/Input.vue.d.ts +3 -2
  12. package/lib/components/menu/Menu.vue.d.ts +2 -2
  13. package/lib/components/menu/MenuItem.vue.d.ts +3 -3
  14. package/lib/components/notifications/Notifications.vue.d.ts +2 -2
  15. package/lib/components/pagination/Pagination.vue.d.ts +3 -2
  16. package/lib/components/pagination/PaginationItem.vue.d.ts +2 -2
  17. package/lib/components/radio/Radio.vue.d.ts +2 -2
  18. package/lib/components/select/Select.vue.d.ts +3 -2
  19. package/lib/components/slider/Slider.vue.d.ts +2 -2
  20. package/lib/components/spacer/Spacer.vue.d.ts +1 -1
  21. package/lib/components/spinner/Spinner.vue.d.ts +2 -2
  22. package/lib/components/{tabs → tab}/Tab.vue.d.ts +2 -2
  23. package/lib/components/{tabs/Tabs.vue.d.ts → tab/TabGroup.vue.d.ts} +0 -0
  24. package/lib/components/table/TableBody.vue.d.ts +1 -1
  25. package/lib/components/table/TableHead.vue.d.ts +1 -1
  26. package/lib/components/tag/Tag.vue.d.ts +2 -2
  27. package/lib/components/textarea/Textarea.vue.d.ts +3 -11
  28. package/lib/components/toggle/Toggle.vue.d.ts +2 -2
  29. package/lib/composables/keys.d.ts +1 -0
  30. package/lib/create.d.ts +12 -0
  31. package/lib/index.cjs.js +2 -2
  32. package/lib/index.d.ts +2 -0
  33. package/lib/index.es.js +271 -130
  34. package/lib/install.d.ts +4 -6
  35. package/lib/nuxt.js +15 -16
  36. package/lib/nuxt.plugin.js +8 -0
  37. package/lib/style.css +1 -1
  38. package/lib/version.d.ts +1 -1
  39. package/package.json +21 -15
  40. package/src/components/alert/Alert.vue +164 -0
  41. package/src/components/avatar/Avatar.vue +137 -0
  42. package/src/components/badge/Badge.vue +107 -0
  43. package/src/components/breadcrumbs/Breadcrumbs.vue +60 -0
  44. package/src/components/button/Button.vue +433 -0
  45. package/src/components/button/ButtonGroup.vue +73 -0
  46. package/src/components/card/Card.vue +25 -0
  47. package/src/components/checkbox/Checkbox.vue +205 -0
  48. package/src/components/collapse/Collapse.vue +181 -0
  49. package/src/components/container/Container.vue +23 -0
  50. package/src/components/divider/Divider.vue +52 -0
  51. package/src/components/drawer/Drawer.vue +244 -0
  52. package/src/components/form/Form.vue +111 -0
  53. package/src/components/icon/Icon.vue +123 -0
  54. package/src/components/image/Image.vue +36 -0
  55. package/src/components/index.ts +45 -0
  56. package/src/components/input/Input.vue +199 -0
  57. package/src/components/link/Link.vue +110 -0
  58. package/src/components/menu/Menu.vue +118 -0
  59. package/src/components/menu/MenuItem.vue +277 -0
  60. package/src/components/modal/Modal.vue +175 -0
  61. package/src/components/notifications/Notifications.vue +318 -0
  62. package/src/components/pagination/Pagination.vue +181 -0
  63. package/src/components/pagination/PaginationItem.vue +58 -0
  64. package/src/components/popover/Popover.vue +194 -0
  65. package/src/components/popover/PopoverContainer.vue +23 -0
  66. package/src/components/progress/Progress.vue +86 -0
  67. package/src/components/radio/Radio.vue +220 -0
  68. package/src/components/scroll/Scroll.vue +143 -0
  69. package/src/components/select/Select.vue +408 -0
  70. package/src/components/skeleton/Skeleton.vue +23 -0
  71. package/src/components/slider/Slider.vue +240 -0
  72. package/src/components/spacer/Spacer.vue +11 -0
  73. package/src/components/spinner/Spinner.vue +45 -0
  74. package/src/components/tab/Tab.vue +100 -0
  75. package/src/components/tab/TabGroup.vue +151 -0
  76. package/src/components/table/Table.vue +172 -0
  77. package/src/components/table/TableBody.vue +13 -0
  78. package/src/components/table/TableCell.vue +78 -0
  79. package/src/components/table/TableHead.vue +15 -0
  80. package/src/components/table/TableHeader.vue +94 -0
  81. package/src/components/table/TableRow.vue +43 -0
  82. package/src/components/tag/Tag.vue +98 -0
  83. package/src/components/textarea/Textarea.vue +156 -0
  84. package/src/components/toggle/Toggle.vue +144 -0
  85. package/src/components/tooltip/Tooltip.vue +26 -0
  86. package/src/composables/colors-utils.ts +378 -0
  87. package/src/composables/colors.ts +82 -0
  88. package/src/composables/common.ts +20 -0
  89. package/src/composables/css.ts +45 -0
  90. package/src/composables/index.ts +7 -0
  91. package/src/composables/inputtable.ts +128 -0
  92. package/src/composables/interactive.ts +16 -0
  93. package/src/composables/keys.ts +8 -0
  94. package/src/composables/notification.ts +10 -0
  95. package/src/create.ts +38 -0
  96. package/src/exports/nuxt.js +32 -0
  97. package/src/exports/nuxt.plugin.js +8 -0
  98. package/src/exports/tailwind.preset.js +55 -0
  99. package/src/index.ts +8 -0
  100. package/src/install.ts +8 -0
  101. package/src/shims-vue.d.ts +6 -0
  102. package/src/version.ts +1 -0
  103. package/volar.d.ts +1 -1
@@ -0,0 +1,118 @@
1
+ <script lang="ts">
2
+ import { defineComponent, type PropType } from 'vue'
3
+ import { useCommon } from '../../composables/common'
4
+ import { useColors } from '../../composables/colors'
5
+
6
+ import XMenuItem from './MenuItem.vue'
7
+ import XCollapse from '../../components/collapse/Collapse.vue'
8
+ import XDivider from '../../components/divider/Divider.vue'
9
+
10
+ export default defineComponent({
11
+ name: 'XMenu',
12
+
13
+ components: {
14
+ XDivider,
15
+ XCollapse,
16
+ XMenuItem,
17
+ },
18
+
19
+ props: {
20
+ ...useCommon.props(),
21
+ ...useColors.props('primary'),
22
+ items: Array as PropType<Array<any>>,
23
+ collapsible: {
24
+ type: Boolean,
25
+ default: true,
26
+ },
27
+ collapseIcon: String,
28
+ expanded: Boolean,
29
+ disabled: Boolean,
30
+ rounded: Boolean,
31
+ filled: Boolean,
32
+ },
33
+
34
+ emits: ['expand'],
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <div v-if="items">
40
+ <template v-for="(item, index) in items" :key="index">
41
+ <template v-if="item.items">
42
+ <x-collapse
43
+ v-if="item.collapsible !== false"
44
+ :icon="item.collapseIcon || collapseIcon"
45
+ :expanded="item.expanded || expanded"
46
+ :disabled="disabled || item.disabled"
47
+ class="x-menu-inner"
48
+ @expand="$emit('expand')"
49
+ >
50
+ <template #default="{ }">
51
+ <x-menu-item
52
+ :item="item"
53
+ :color="item.color || color"
54
+ :size="item.size || size"
55
+ :rounded="rounded"
56
+ :filled="filled"
57
+ :disabled="disabled || item.disabled"
58
+ class="pr-10 font-medium"
59
+ />
60
+ </template>
61
+ <template #content="{ expand }">
62
+ <x-menu
63
+ class="border-l ml-4 border-gray-100 dark:border-gray-700 mt-2 mb-1"
64
+ :class="{ 'pl-1': filled }"
65
+ :items="item.items"
66
+ :color="item.color || color"
67
+ :size="item.size || size"
68
+ :collapsible="collapsible"
69
+ :collapse-icon="item.collapseIcon || collapseIcon"
70
+ :expanded="item.expanded || expanded"
71
+ :disabled="disabled || item.disabled"
72
+ :rounded="rounded"
73
+ :filled="filled"
74
+ @expand="expand(false)"
75
+ />
76
+ </template>
77
+ </x-collapse>
78
+ <template v-else>
79
+ <x-menu-item
80
+ :item="item"
81
+ :rounded="rounded"
82
+ :color="item.color || color"
83
+ :size="item.size || size"
84
+ :disabled="disabled || item.disabled"
85
+ class="font-medium"
86
+ inactive
87
+ />
88
+ <x-menu
89
+ class="x-menu-inner ml-4 border-l border-gray-100 dark:border-gray-700"
90
+ :class="{ 'pl-1': filled }"
91
+ :items="item.items"
92
+ :color="item.color || color"
93
+ :size="item.size || size"
94
+ :collapsible="collapsible"
95
+ :collapse-icon="item.collapseIcon || collapseIcon"
96
+ :expanded="item.expanded || expanded"
97
+ :disabled="disabled || item.disabled"
98
+ :rounded="rounded"
99
+ :filled="filled"
100
+ @expand="$emit('expand')"
101
+ />
102
+ </template>
103
+ </template>
104
+ <component
105
+ :is="item.divider ? 'x-divider' : 'x-menu-item'"
106
+ v-else
107
+ :color="item.color || color"
108
+ :size="item.size || size"
109
+ :item="item"
110
+ :disabled="disabled || item.disabled"
111
+ :filled="filled"
112
+ :rounded="rounded"
113
+ :class="{ 'my-2': item.divider }"
114
+ @active="$emit('expand')"
115
+ />
116
+ </template>
117
+ </div>
118
+ </template>
@@ -0,0 +1,277 @@
1
+ <script lang="ts">
2
+ import { defineComponent, ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
3
+ import { useCSS } from '../../composables/css'
4
+ import { useColors } from '../../composables/colors'
5
+ import { useCommon } from '../../composables/common'
6
+
7
+ import XSpinner from '../../components/spinner/Spinner.vue'
8
+ import XLink from '../../components/link/Link.vue'
9
+
10
+ export default defineComponent({
11
+ name: 'XMenuItem',
12
+
13
+ components: {
14
+ XSpinner,
15
+ XLink,
16
+ },
17
+
18
+ props: {
19
+ ...useCommon.props(),
20
+ ...useColors.props('primary'),
21
+ item: {
22
+ type: Object,
23
+ default: () => {},
24
+ },
25
+ active: Boolean,
26
+ onClick: Function,
27
+ inactive: Boolean,
28
+ value: [Number,String],
29
+ to: String,
30
+ exact: Boolean,
31
+ href: String,
32
+ target: String,
33
+ label: String,
34
+ icon: String,
35
+ iconRight: String,
36
+ loading: Boolean,
37
+ rounded: Boolean,
38
+ filled: Boolean,
39
+ selected: Boolean,
40
+ disabled: Boolean,
41
+ },
42
+
43
+ emits: ['active', 'click'],
44
+
45
+ setup(props, { emit }) {
46
+ const elRef = ref()
47
+ const isActive = ref(false)
48
+
49
+ const filled = computed(() => props.filled || props.item?.filled)
50
+ const cItem = computed(() => ({
51
+ ...props,
52
+ ...props.item,
53
+ }))
54
+
55
+ const htmlTag = cItem.value.to || cItem.value.href ? 'x-link' : 'div'
56
+ const isSupported = window && 'MutationObserver' in window
57
+ const classObserver = isSupported ? new MutationObserver(check) : null
58
+
59
+ onMounted(() => {
60
+ if (!elRef.value) return
61
+
62
+ check()
63
+
64
+ if (isSupported && htmlTag === 'x-link') classObserver?.observe(elRef.value.$el, {
65
+ attributes: true,
66
+ attributeFilter: ['class'],
67
+ })
68
+ })
69
+
70
+ onBeforeUnmount(() => {
71
+ if (classObserver) classObserver.disconnect()
72
+ })
73
+
74
+ function onItemClick(e: Event) {
75
+ cItem.value.onClick && cItem.value.onClick(e)
76
+ emit('click', e)
77
+ }
78
+
79
+ function check() {
80
+ if (elRef.value && elRef.value.$el && (cItem.value.href || cItem.value.to)) {
81
+ const active = elRef.value.$el.classList.contains(cItem.value.exact ? 'router-link-exact-active' : 'router-link-active')
82
+
83
+ isActive.value = active
84
+ } else {
85
+ isActive.value = cItem.value.active
86
+ }
87
+ }
88
+
89
+ watch(() => isActive.value, (val) => {
90
+ if (val) emit('active')
91
+ })
92
+
93
+ watch(() => cItem.value.active, (val) => {
94
+ isActive.value = val
95
+ })
96
+
97
+ const css = useCSS()
98
+ const colors = useColors()
99
+ const cssVariables = computed(() => {
100
+ const color = colors.getPalette(cItem.value.color || 'gray')
101
+ const gray = colors.getPalette('gray')
102
+
103
+ if (cItem.value.disabled) return css.get('text', gray[300])
104
+
105
+ if (filled.value) {
106
+ if (isActive.value) {
107
+ return css.variables({
108
+ bg: props.selected ? color[100] : color[50],
109
+ text: color[500],
110
+ hover: {
111
+ bg: props.selected ? color[100] : color[50],
112
+ text: color[500],
113
+ },
114
+ dark: {
115
+ bg: props.selected ? color[800] : color[700],
116
+ text: color[100],
117
+ hover: {
118
+ bg: props.selected ? color[800] : color[700],
119
+ text: color[100],
120
+ },
121
+ },
122
+ })
123
+ }
124
+
125
+ return css.variables({
126
+ bg: props.selected ? gray[50] : 'transparent',
127
+ text: gray[800],
128
+ hover: {
129
+ bg: gray[50],
130
+ text: gray[900],
131
+ },
132
+ dark: {
133
+ bg: props.selected ? gray[800] : 'transparent',
134
+ text: gray[200],
135
+ hover: {
136
+ bg: gray[800],
137
+ text: gray[100],
138
+ },
139
+ },
140
+ })
141
+ }
142
+
143
+ if (isActive.value) {
144
+ return css.variables({
145
+ text: color[500],
146
+ hover: {
147
+ text: color[500],
148
+ border: color[500],
149
+ },
150
+ dark: {
151
+ text: color[500],
152
+ hover: {
153
+ text: color[500],
154
+ border: color[500],
155
+ },
156
+ },
157
+ })
158
+ }
159
+
160
+ return css.variables({
161
+ text: gray[800],
162
+ hover: {
163
+ text: gray[900],
164
+ border: gray[300],
165
+ },
166
+ dark: {
167
+ text: gray[300],
168
+ hover: {
169
+ text: gray[200],
170
+ border: gray[800],
171
+ },
172
+ },
173
+ })
174
+ })
175
+
176
+ return {
177
+ elRef,
178
+ cItem,
179
+ htmlTag,
180
+ isActive,
181
+ cssVariables,
182
+ onItemClick,
183
+ }
184
+ },
185
+ })
186
+ </script>
187
+
188
+ <template>
189
+ <component
190
+ :is="htmlTag"
191
+ ref="elRef"
192
+ :to="cItem.to"
193
+ :href="cItem.href"
194
+ :target="cItem.target"
195
+ :color="cItem.color"
196
+ class="relative flex items-center whitespace-nowrap px-3 mt-1"
197
+ :style="cssVariables"
198
+ :class="[
199
+ $style['menu-item'],
200
+ [isActive ? $style['menu-item--active'] : ''],
201
+ {
202
+ 'font-medium': isActive,
203
+ 'flex items-center': $slots.prefix || $slots.suffix,
204
+ 'cursor-pointer': !cItem.disabled && !inactive,
205
+
206
+ // size
207
+ 'py-1 text-xs': cItem.size === 'xs',
208
+ 'py-2 text-sm': cItem.size === 'sm',
209
+ 'py-1.5': !cItem.size || !['xs', 'sm', 'lg', 'xl'].includes(cItem.size),
210
+ 'py-3': cItem.size === 'lg',
211
+ 'py-4 text-lg': cItem.size === 'xl',
212
+
213
+ 'rounded my-[1px]': rounded
214
+ },
215
+ ]"
216
+ :title="cItem.label"
217
+ :alt="cItem.label"
218
+ @click="onItemClick"
219
+ >
220
+ <span v-if="$slots.prefix" class="mr-2 shrink-0">
221
+ <slot name="prefix"></slot>
222
+ </span>
223
+ <x-icon v-else-if="cItem.icon" :size="cItem.size" :icon="cItem.icon" class="mr-2 shrink-0"/>
224
+
225
+ <span class="flex-1 truncate">
226
+ <slot>{{ cItem.label }}</slot>
227
+ </span>
228
+
229
+ <span class="ml-1 shrink-0">
230
+ <x-spinner v-if="cItem.loading" :size="cItem.size" />
231
+ <template v-else>
232
+ <span v-if="$slots.suffix">
233
+ <slot name="suffix"></slot>
234
+ </span>
235
+ <x-icon v-else-if="cItem.iconRight" :size="cItem.size" :icon="cItem.iconRight"/>
236
+ </template>
237
+ </span>
238
+ </component>
239
+ </template>
240
+
241
+ <style lang="postcss" module scoped>
242
+ .menu-item {
243
+ color: var(--x-text);
244
+ background-color: var(--x-bg);
245
+
246
+ &:before {
247
+ content: '';
248
+ position: absolute;
249
+ left: -1px;
250
+ height: 100%;
251
+ width: 1px;
252
+ background-color: transparent;
253
+ }
254
+
255
+ &:hover {
256
+ color: var(--x-text-hover, var(--x-text));
257
+ background-color: var(--x-bg-hover, var(--x-bg));
258
+ }
259
+
260
+ :global(.dark) & {
261
+ color: var(--x-dark-text);
262
+ background: var(--x-dark-bg);
263
+ &:hover {
264
+ color: var(--x-dark-text-hover, var(--x-dark-text));
265
+ background-color: var(--x-dark-bg-hover, var(--x-dark-bg));
266
+ }
267
+ }
268
+ }
269
+
270
+ :global(.x-menu-inner) {
271
+ .menu-item {
272
+ &:hover:before, &--active:before {
273
+ background-color: var(--x-border-hover);
274
+ }
275
+ }
276
+ }
277
+ </style>
@@ -0,0 +1,175 @@
1
+ <script lang="ts">
2
+ import { computed, defineComponent, ref, watch, type PropType } from 'vue'
3
+
4
+ import { onClickOutside, useEventListener } from '@vueuse/core'
5
+
6
+ import XScroll from '../../components/scroll/Scroll.vue'
7
+
8
+ export default defineComponent({
9
+ name: 'XModal',
10
+
11
+ components: {
12
+ XScroll,
13
+ },
14
+
15
+ props: {
16
+ size: {
17
+ type: String as PropType<'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'>,
18
+ default: 'md',
19
+ },
20
+ modelValue: Boolean,
21
+ showClose: Boolean,
22
+ backdrop: Boolean,
23
+ },
24
+
25
+ emits: ['update:modelValue'],
26
+
27
+ expose: ['open', 'close'],
28
+
29
+ setup(props, { emit }) {
30
+ const value = ref(props.modelValue)
31
+ const visible = ref(false)
32
+ const modalRef = ref<HTMLElement | null>(null)
33
+
34
+ const classes = computed(() => {
35
+ if (props.size === 'full') return 'w-full'
36
+ else if (props.size === 'xs') return 'sm:max-w-xs w-full'
37
+ else if (props.size === 'sm') return 'sm:max-w-sm w-full'
38
+ else if (props.size === 'lg') return 'sm:max-w-xl w-full'
39
+ else if (props.size === 'xl') return 'sm:max-w-3xl w-full'
40
+
41
+ return 'sm:max-w-lg w-full'
42
+ })
43
+
44
+ let stopClickOutside: undefined | (()=> void) = undefined
45
+
46
+ watch(value, (val) => {
47
+ if (stopClickOutside) {
48
+ stopClickOutside()
49
+ stopClickOutside = undefined
50
+ }
51
+
52
+ if (val) {
53
+ setTimeout(() => {
54
+ stopClickOutside = onClickOutside(modalRef, close)
55
+ })
56
+ }
57
+ })
58
+
59
+ watch(() => props.modelValue, (val) => {
60
+ if (val) {
61
+ value.value = val
62
+
63
+ setTimeout(() => {
64
+ visible.value = val
65
+ })
66
+ } else {
67
+ visible.value = val
68
+
69
+ setTimeout(() => {
70
+ value.value = val
71
+ }, 150)
72
+ }
73
+ })
74
+
75
+ useEventListener(document, 'keydown', onKeyDown)
76
+
77
+ function onKeyDown(event: KeyboardEvent) {
78
+ if (event.key === 'Escape' && value.value) close()
79
+ }
80
+
81
+ function close() {
82
+ visible.value = false
83
+
84
+ setTimeout(() => {
85
+ value.value = false
86
+ emit('update:modelValue', false)
87
+ }, 150)
88
+ }
89
+
90
+ function open() {
91
+ value.value = true
92
+ emit('update:modelValue', true)
93
+
94
+ setTimeout(() => {
95
+ visible.value = true
96
+ })
97
+ }
98
+
99
+ const closeIcon = '<path d="M6 18L18 6M6 6l12 12" />'
100
+
101
+ return {
102
+ closeIcon,
103
+ modalRef,
104
+ classes,
105
+ visible,
106
+ value,
107
+ close,
108
+ open,
109
+ }
110
+ },
111
+ })
112
+ </script>
113
+
114
+ <template>
115
+ <Teleport to="body">
116
+ <div
117
+ v-if="value"
118
+ class="fixed z-40 inset-0 overflow-y-auto transition-all"
119
+ :class="[
120
+ visible ? 'visible' : 'invisible ease-in duration-100'
121
+ ]"
122
+ >
123
+ <div
124
+ v-if="backdrop"
125
+ class="fixed inset-0 bg-gray-500 dark:bg-black transition-opacity"
126
+ :class="[
127
+ visible ? 'ease-out duration-200 opacity-30 dark:opacity-70' : 'ease-in duration-100 opacity-0',
128
+ ]"
129
+ ></div>
130
+
131
+ <div class="flex items-end sm:items-center justify-center p-4 sm:p-6 h-screen">
132
+ <div
133
+ ref="modalRef"
134
+ class="relative flex flex-col z-10 bg-white dark:bg-gray-900 rounded-md shadow-lg transform transition-all overflow-hidden max-h-full"
135
+ :class="[
136
+ classes,
137
+ visible ?
138
+ 'ease-out duration-200 opacity-100 translate-y-0 sm:scale-100'
139
+ : 'ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95',
140
+ ]"
141
+ role="dialog"
142
+ aria-modal="true"
143
+ aria-labelledby="modal-headline"
144
+ >
145
+ <div
146
+ v-if="showClose"
147
+ class="absolute p-1 top-4 right-4 rounded-full bg-opacity-10 hover:bg-opacity-30 cursor-pointer"
148
+ :class="[
149
+ $slots.image ? 'bg-gray-900 text-white' : 'bg-gray-500 text-gray-800 dark:text-gray-300'
150
+ ]"
151
+ @click="close"
152
+ >
153
+ <x-icon :icon="closeIcon"/>
154
+ </div>
155
+ <slot name="image"></slot>
156
+ <div v-if="$slots.header" class="text-lg font-semibold px-6 py-4 border-b">
157
+ <slot name="header"></slot>
158
+ </div>
159
+ <x-scroll
160
+ v-if="$slots.default"
161
+ :scrollbar="false"
162
+ vertical
163
+ >
164
+ <div class="px-6 py-4">
165
+ <slot></slot>
166
+ </div>
167
+ </x-scroll>
168
+ <div v-if="$slots.actions" class="bg-slate-50 dark:bg-gray-800 p-4">
169
+ <slot name="actions"></slot>
170
+ </div>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </Teleport>
175
+ </template>