@dolanske/vui 0.4.0 → 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 (155) hide show
  1. package/README.md +6 -13
  2. package/dist/components/Alert/Alert.vue.d.ts +7 -1
  3. package/dist/components/Avatar/Avatar.vue.d.ts +15 -1
  4. package/dist/components/Badge/Badge.vue.d.ts +1 -1
  5. package/dist/components/Breadcrumbs/BreadcrumbItem.vue.d.ts +1 -1
  6. package/dist/components/Button/Button.vue.d.ts +5 -15
  7. package/dist/components/ButtonGroup/ButtonGroup.vue.d.ts +2 -0
  8. package/dist/components/Calendar/Calendar.vue.d.ts +1 -1
  9. package/dist/components/Checkbox/Checkbox.vue.d.ts +1 -0
  10. package/dist/components/Dropdown/Dropdown.vue.d.ts +19 -4
  11. package/dist/components/Dropdown/DropdownTitle.vue.d.ts +5 -1
  12. package/dist/components/Flex/Flex.vue.d.ts +3 -1
  13. package/dist/components/Grid/Grid.vue.d.ts +7 -2
  14. package/dist/components/Input/Dropzone.vue.d.ts +1 -1
  15. package/dist/components/Input/Input.vue.d.ts +2 -2
  16. package/dist/components/Kbd/KbdGroup.vue.d.ts +3 -11
  17. package/dist/components/Modal/Confirm.vue.d.ts +1 -1
  18. package/dist/components/Modal/Modal.vue.d.ts +1 -1
  19. package/dist/components/Pagination/Pagination.vue.d.ts +3 -0
  20. package/dist/components/Popout/Popout.vue.d.ts +8 -1
  21. package/dist/components/Progress/Progress.vue.d.ts +2 -0
  22. package/dist/components/Radio/Radio.vue.d.ts +1 -0
  23. package/dist/components/Select/Select.vue.d.ts +2 -0
  24. package/dist/components/Sheet/Sheet.vue.d.ts +3 -0
  25. package/dist/components/Switch/Switch.vue.d.ts +1 -0
  26. package/dist/components/Table/index.d.ts +6 -0
  27. package/dist/components/Table/table.d.ts +1 -1
  28. package/dist/components/Tabs/Tab.vue.d.ts +16 -3
  29. package/dist/components/Tabs/Tabs.vue.d.ts +4 -0
  30. package/dist/components/Toast/toast.d.ts +245 -0
  31. package/dist/index.d.ts +2 -7
  32. package/dist/shared/helpers.d.ts +9 -0
  33. package/dist/shared/theme.d.ts +3 -0
  34. package/dist/style.css +1 -1
  35. package/dist/vui.js +6423 -6046
  36. package/package.json +8 -4
  37. package/src/App.vue +89 -192
  38. package/src/components/Accordion/accordion.scss +2 -0
  39. package/src/components/Alert/Alert.vue +11 -5
  40. package/src/components/Alert/alert.scss +104 -23
  41. package/src/components/Avatar/Avatar.vue +4 -1
  42. package/src/components/Avatar/avatar.scss +1 -1
  43. package/src/components/Badge/Badge.vue +1 -1
  44. package/src/components/Badge/badge.scss +134 -17
  45. package/src/components/Breadcrumbs/BreadcrumbItem.vue +2 -2
  46. package/src/components/Breadcrumbs/Breadcrumbs.vue +1 -2
  47. package/src/components/Breadcrumbs/breadcrumbs.scss +2 -1
  48. package/src/components/Button/Button.vue +16 -21
  49. package/src/components/Button/button.scss +159 -56
  50. package/src/components/ButtonGroup/ButtonGroup.vue +4 -1
  51. package/src/components/ButtonGroup/button-group.scss +2 -2
  52. package/src/components/Calendar/Calendar.vue +9 -3
  53. package/src/components/Calendar/calendar.scss +29 -2
  54. package/src/components/Card/Card.vue +2 -2
  55. package/src/components/Card/card.scss +4 -4
  56. package/src/components/Checkbox/Checkbox.vue +7 -5
  57. package/src/components/Checkbox/checkbox.scss +27 -13
  58. package/src/components/CopyClipboard/CopyClipboard.vue +15 -6
  59. package/src/components/CopyClipboard/copy-clipboard.scss +10 -2
  60. package/src/components/Drawer/Drawer.vue +4 -4
  61. package/src/components/Drawer/drawer.scss +1 -0
  62. package/src/components/Dropdown/Dropdown.vue +44 -20
  63. package/src/components/Dropdown/DropdownItem.vue +5 -4
  64. package/src/components/Dropdown/DropdownTitle.vue +7 -1
  65. package/src/components/Dropdown/dropdown-item.scss +84 -0
  66. package/src/components/Dropdown/dropdown.scss +21 -86
  67. package/src/components/Flex/Flex.vue +4 -1
  68. package/src/components/Grid/Grid.vue +25 -2
  69. package/src/components/Input/Color.vue +26 -0
  70. package/src/components/Input/Counter.vue +12 -16
  71. package/src/components/Input/Dropzone.vue +1 -1
  72. package/src/components/Input/File.vue +1 -1
  73. package/src/components/Input/Input.vue +8 -6
  74. package/src/components/Input/Password.vue +1 -13
  75. package/src/components/Input/Textarea.vue +4 -2
  76. package/src/components/Input/input.scss +113 -19
  77. package/src/components/Kbd/KbdGroup.vue +2 -6
  78. package/src/components/Kbd/kbd.scss +7 -6
  79. package/src/components/Modal/Confirm.vue +1 -1
  80. package/src/components/Modal/Modal.vue +23 -15
  81. package/src/components/Modal/modal.scss +11 -6
  82. package/src/components/OTP/otp.scss +8 -7
  83. package/src/components/Pagination/Pagination.vue +6 -3
  84. package/src/components/Popout/Popout.vue +15 -5
  85. package/src/components/Popout/popout.scss +8 -1
  86. package/src/components/Progress/Progress.vue +18 -5
  87. package/src/components/Progress/progress.scss +7 -1
  88. package/src/components/Radio/Radio.vue +4 -2
  89. package/src/components/Radio/radio.scss +28 -9
  90. package/src/components/Select/Select.vue +49 -18
  91. package/src/components/Select/select.scss +35 -2
  92. package/src/components/Sheet/Sheet.vue +8 -2
  93. package/src/components/Sheet/sheet.scss +9 -0
  94. package/src/components/Sidebar/Sidebar.vue +46 -16
  95. package/src/components/Sidebar/sidebar.scss +6 -5
  96. package/src/components/Spinner/spinner.scss +2 -1
  97. package/src/components/Switch/Switch.vue +4 -3
  98. package/src/components/Switch/switch.scss +48 -7
  99. package/src/components/Table/{Header.vue → Head.vue} +5 -5
  100. package/src/components/Table/{Table.vue → Root.vue} +2 -2
  101. package/src/components/Table/SelectRow.vue +2 -1
  102. package/src/components/Table/index.ts +7 -0
  103. package/src/components/Table/table.scss +25 -5
  104. package/src/components/Table/table.ts +7 -3
  105. package/src/components/Tabs/Tab.vue +7 -9
  106. package/src/components/Tabs/Tabs.vue +9 -2
  107. package/src/components/Tabs/tabs.scss +11 -3
  108. package/src/components/Toast/Toasts.vue +5 -0
  109. package/src/components/Toast/toast.scss +6 -2
  110. package/src/components/Toast/toast.ts +7 -0
  111. package/src/components/Tooltip/Tooltip.vue +9 -9
  112. package/src/components/Tooltip/tooltip.scss +4 -0
  113. package/src/examples/ExampleAccordions.vue +58 -0
  114. package/src/examples/ExampleAlerts.vue +78 -0
  115. package/src/examples/ExampleAvatars.vue +44 -0
  116. package/src/examples/ExampleBadges.vue +48 -0
  117. package/src/examples/ExampleBreadcrumbs.vue +46 -0
  118. package/src/examples/ExampleButtons.vue +140 -0
  119. package/src/examples/ExampleCalendars.vue +40 -0
  120. package/src/examples/ExampleCards.vue +94 -0
  121. package/src/examples/ExampleCheckboxes.vue +123 -0
  122. package/src/examples/ExampleCopyClipboard.vue +47 -0
  123. package/src/examples/ExampleDividers.vue +39 -0
  124. package/src/examples/ExampleDrawers.vue +67 -0
  125. package/src/examples/ExampleDropdowns.vue +114 -0
  126. package/src/examples/ExampleFlexGrid.vue +122 -0
  127. package/src/examples/ExampleInputs.vue +234 -0
  128. package/src/examples/ExampleKBD.vue +65 -0
  129. package/src/examples/ExampleModals.vue +143 -0
  130. package/src/examples/ExamplePalette.vue +159 -0
  131. package/src/examples/ExamplePopouts.vue +41 -0
  132. package/src/examples/ExampleSheets.vue +77 -0
  133. package/src/examples/ExampleSidebars.vue +270 -0
  134. package/src/examples/ExampleSkeletons.vue +26 -0
  135. package/src/examples/ExampleSpinners.vue +78 -0
  136. package/src/examples/ExampleTables.vue +195 -0
  137. package/src/examples/ExampleTabs.vue +119 -0
  138. package/src/examples/ExampleToasts.vue +96 -0
  139. package/src/examples/ExampleTooltips.vue +70 -0
  140. package/src/examples/shared/ExampleColor.vue +28 -0
  141. package/src/index.ts +4 -11
  142. package/src/internal/Backdrop/backdrop.scss +7 -1
  143. package/src/shared/helpers.ts +43 -0
  144. package/src/shared/theme.ts +22 -0
  145. package/src/style/animation.scss +1 -0
  146. package/src/style/core.scss +34 -57
  147. package/src/style/layout.scss +102 -5
  148. package/src/style/{fonts.scss → text.scss} +39 -0
  149. package/src/style/theme.scss +195 -0
  150. package/src/style/tooltip.scss +22 -4
  151. package/src/style/typography.scss +95 -18
  152. package/dist/components/Table/Row.vue.d.ts +0 -16
  153. package/src/components/Table/Row.vue +0 -9
  154. /package/dist/components/Table/{Header.vue.d.ts → Head.vue.d.ts} +0 -0
  155. /package/dist/components/Table/{Table.vue.d.ts → Root.vue.d.ts} +0 -0
@@ -10,24 +10,32 @@
10
10
  top: 0;
11
11
  border-bottom: 1px solid var(--color-border);
12
12
  height: auto;
13
+ border-bottom-right-radius: var(--border-radius-l);
14
+ border-bottom-left-radius: var(--border-radius-l);
13
15
  }
14
16
 
15
17
  &.vui-sheet-position-bottom {
16
18
  bottom: 0;
17
19
  border-top: 1px solid var(--color-border);
18
20
  height: auto;
21
+ border-top-right-radius: var(--border-radius-l);
22
+ border-top-left-radius: var(--border-radius-l);
19
23
  }
20
24
 
21
25
  &.vui-sheet-position-right {
22
26
  right: 0;
23
27
  top: 0;
24
28
  border-left: 1px solid var(--color-border);
29
+ border-top-left-radius: var(--border-radius-l);
30
+ border-bottom-left-radius: var(--border-radius-l);
25
31
  }
26
32
 
27
33
  &.vui-sheet-position-left {
28
34
  left: 0;
29
35
  top: 0;
30
36
  border-right: 1px solid var(--color-border);
37
+ border-top-right-radius: var(--border-radius-l);
38
+ border-bottom-right-radius: var(--border-radius-l);
31
39
  }
32
40
 
33
41
  &.vui-sheet-position-top,
@@ -36,6 +44,7 @@
36
44
  width: 100%;
37
45
  }
38
46
 
47
+ .vui-sheet-footer,
39
48
  .vui-sheet-header,
40
49
  .vui-sheet-content {
41
50
  width: 100%;
@@ -1,6 +1,7 @@
1
1
  <script setup lang='ts'>
2
- import { useCssVar, useMouse } from '@vueuse/core'
3
- import { computed, useSlots, useTemplateRef, watch } from 'vue'
2
+ import { useCssVar, useMouseInElement, useTimeoutFn, watchThrottled } from '@vueuse/core'
3
+ import { computed, onMounted, useSlots, useTemplateRef } from 'vue'
4
+ import { isNil } from '../../shared/helpers'
4
5
  import './sidebar.scss'
5
6
 
6
7
  const props = withDefaults(defineProps<Props>(), {
@@ -26,18 +27,21 @@ interface Props {
26
27
  }
27
28
 
28
29
  const sidebar = useTemplateRef('sidebar')
29
- const open = defineModel<boolean>()
30
+ const open = defineModel<boolean>({
31
+ default: true,
32
+ })
30
33
  const slots = useSlots()
31
34
  const offset = useCssVar('--vui-sidebar-float-offset', sidebar, {
32
35
  initialValue: '8px',
33
36
  })
34
37
 
35
38
  const width = computed(() => {
36
- if (props.mini)
37
- return `65px`
39
+ if (props.mini) {
40
+ return props.floaty ? '73px' : `65px`
41
+ }
38
42
  if (!props.floaty)
39
43
  return `${props.width}px`
40
- return `calc(${props.width}px - ${offset.value})`
44
+ return `calc(${props.width}px + ${offset.value})`
41
45
  })
42
46
 
43
47
  const slotProps = computed(() => ({
@@ -45,28 +49,54 @@ const slotProps = computed(() => ({
45
49
  floaty: props.floaty,
46
50
  width: props.width,
47
51
  open,
52
+ close: () => open.value = false,
48
53
  }))
49
54
 
50
- const { x } = useMouse()
55
+ // Sidebar `appear` implementation
56
+ const { start, stop, isPending } = useTimeoutFn(() => {
57
+ if (props.appear) {
58
+ open.value = true
59
+ }
60
+ }, 250)
61
+
62
+ const APPEAR_OFFSET = 32
63
+
64
+ const wrap = useTemplateRef('wrap')
65
+ const { elementX } = useMouseInElement(wrap)
66
+
67
+ onMounted(() => {
68
+ if (props.appear && open.value) {
69
+ open.value = false
70
+ }
71
+ })
51
72
 
52
- let appearActive = true
53
- watch(x, (pos) => {
54
- if (!props.appear)
73
+ watchThrottled(elementX, (pos) => {
74
+ if (!props.appear || (pos <= APPEAR_OFFSET && pos >= 0 && isPending.value))
55
75
  return
56
76
 
57
- if (pos < 20 && !open.value) {
58
- open.value = true
59
- appearActive = true
77
+ if (pos <= APPEAR_OFFSET && pos >= 0 && !open.value && !isPending.value) {
78
+ start()
60
79
  }
61
- else if (appearActive && pos > props.width) {
80
+ else if (isPending.value) {
81
+ stop()
82
+ }
83
+
84
+ const openWidth = props.mini
85
+ ? 65
86
+ : props.floaty
87
+ ? props.width
88
+ : props.width - (isNil(offset.value) ? 0 : Number(offset.value?.replace('px', '')))
89
+
90
+ if ((pos > APPEAR_OFFSET + openWidth || pos < 0) && open.value) {
62
91
  open.value = false
63
- appearActive = false
64
92
  }
93
+ }, {
94
+ throttle: 100,
65
95
  })
66
96
  </script>
67
97
 
68
98
  <template>
69
- <div class="vui-sidebar-outer" :style="{ width }" :class="{ open }">
99
+ <div ref="wrap" class="vui-sidebar-outer" :style="{ width }" :class="{ open }">
70
100
  <aside ref="sidebar" class="vui-sidebar" :class="{ open, floaty: props.floaty, mini: props.mini }" :style="{ width: `${props.mini ? 65 : props.width}px` }">
71
101
  <div v-if="slots.header" class="vui-sidebar-header">
72
102
  <slot name="header" v-bind="slotProps" />
@@ -2,12 +2,12 @@
2
2
  .vui-sidebar-layout {
3
3
  display: flex;
4
4
  flex-wrap: nowrap;
5
- gap: 32px;
5
+ gap: 0;
6
+ height: 100vh;
6
7
  position: relative;
7
8
 
8
9
  main {
9
10
  flex: 1;
10
- padding: 2rem;
11
11
  }
12
12
 
13
13
  .vui-sidebar-outer {
@@ -22,11 +22,11 @@
22
22
  .vui-sidebar {
23
23
  --vui-sidebar-float-offset: 8px;
24
24
  display: flex;
25
+ height: 100%;
25
26
  flex-direction: column;
26
27
  gap: var(--space-sm);
27
- height: 100vh;
28
28
  width: 224px;
29
- position: fixed;
29
+ position: absolute;
30
30
  top: 0;
31
31
  z-index: 50;
32
32
  background-color: var(--color-bg);
@@ -47,7 +47,7 @@
47
47
  top: var(--vui-sidebar-float-offset);
48
48
  left: var(--vui-sidebar-float-offset);
49
49
  bottom: var(--vui-sidebar-float-offset);
50
- height: calc(100vh - calc(var(--vui-sidebar-float-offset) * 2));
50
+ height: calc(100% - calc(var(--vui-sidebar-float-offset) * 2));
51
51
  border-radius: var(--border-radius-m);
52
52
  border: 1px solid var(--color-border);
53
53
  transform: translateX(calc(-100% - calc(var(--vui-sidebar-float-offset) * 2)));
@@ -76,6 +76,7 @@
76
76
  position: absolute;
77
77
  inset: 0;
78
78
  overflow-y: auto;
79
+ overflow-x: hidden;
79
80
  }
80
81
  }
81
82
 
@@ -1,5 +1,6 @@
1
1
  .vui-spinner {
2
- --spinner-color: var(--color-text);
2
+ --spinner-color: var(--color-border-accent);
3
+
3
4
  aspect-ratio: 1;
4
5
  border-radius: 50%;
5
6
  border: 3px solid var(--spinner-color);
@@ -5,17 +5,18 @@ import './switch.scss'
5
5
  interface Props {
6
6
  label?: string
7
7
  disabled?: boolean
8
+ accent?: boolean
8
9
  }
9
10
 
10
- const { label, disabled } = defineProps<Props>()
11
+ const { label, disabled, accent } = defineProps<Props>()
11
12
  const slots = defineSlots()
12
13
  const checked = defineModel<boolean>()
13
14
  const id = useId()
14
15
  </script>
15
16
 
16
17
  <template>
17
- <div class="vui-switch" :class="{ disabled, checked }">
18
- <input :id v-model="checked" type="checkbox">
18
+ <div class="vui-switch" :class="{ disabled, checked, accent }">
19
+ <input :id v-model="checked" type="checkbox" :disabled>
19
20
  <label :for="id">
20
21
  <div class="vui-switch-icon">
21
22
  <span class="vui-switch-indicator" />
@@ -1,9 +1,27 @@
1
1
  .vui-switch {
2
2
  --switch-size: 24px;
3
3
 
4
- &.checked .vui-switch-icon .vui-switch-indicator {
5
- left: calc(100% - 24px);
6
- background-color: var(--color-text);
4
+ &.checked {
5
+ .vui-switch-icon .vui-switch-indicator {
6
+ left: calc(100% - 24px);
7
+ background-color: var(--color-text);
8
+ }
9
+
10
+ &.accent .vui-switch-icon .vui-switch-indicator {
11
+ background-color: var(--color-accent);
12
+ }
13
+ }
14
+
15
+ &.disabled {
16
+ .vui-switch-icon {
17
+ opacity: 0.5;
18
+ cursor: not-allowed;
19
+ }
20
+
21
+ input + label .vui-switch-content {
22
+ opacity: 0.5;
23
+ cursor: not-allowed;
24
+ }
7
25
  }
8
26
 
9
27
  .vui-switch-icon {
@@ -12,7 +30,7 @@
12
30
  border-radius: 22px;
13
31
  background-color: var(--color-bg-raised);
14
32
  position: relative;
15
- cursor: pointer;
33
+ cursor: default;
16
34
 
17
35
  .vui-switch-indicator {
18
36
  display: block;
@@ -22,13 +40,22 @@
22
40
  width: 20px;
23
41
  height: 20px;
24
42
  border-radius: 100%;
25
- background-color: var(--color-bg);
43
+ background-color: var(--color-text-lighter);
26
44
  transition: var(--transition);
27
45
  }
28
46
  }
29
47
 
30
48
  input {
31
- display: none;
49
+ width: 1px;
50
+ height: 1px;
51
+ position: absolute;
52
+ overflow: hidden;
53
+ outline: none !important;
54
+ opacity: 0;
55
+
56
+ &:focus-visible + label .vui-switch-icon {
57
+ outline: 2px solid var(--color-text);
58
+ }
32
59
 
33
60
  & + label {
34
61
  display: grid;
@@ -44,9 +71,23 @@
44
71
  &:is(p) {
45
72
  height: var(--switch-size);
46
73
  line-height: var(--switch-size);
47
- font-size: var(--font-size-ms);
74
+ font-size: var(--font-size-m);
48
75
  }
49
76
  }
50
77
  }
51
78
  }
52
79
  }
80
+
81
+ :root.light {
82
+ .vui-switch .vui-switch-icon .vui-switch-indicator {
83
+ background-color: var(--color-bg-lowered);
84
+ }
85
+
86
+ .vui-switch.checked.accent .vui-switch-icon .vui-switch-indicator {
87
+ background-color: var(--color-accent);
88
+ }
89
+
90
+ .vui-switch.checked .vui-switch-icon .vui-switch-indicator {
91
+ background-color: var(--color-text);
92
+ }
93
+ }
@@ -40,18 +40,18 @@ const sortStateBind = computed(() => {
40
40
 
41
41
  <template>
42
42
  <th>
43
- <div v-if="props.header" class="vui-table-th-content">
43
+ <div v-if="props.header || $slots.default" class="vui-table-th-content">
44
44
  <slot>
45
- {{ props.header.label }}
45
+ {{ props.header?.label }}
46
46
  </slot>
47
47
  <Button
48
- v-if="props.sort"
48
+ v-if="props.sort && props.header"
49
49
  class="vui-table-sort-button"
50
50
  v-bind="sortStateBind"
51
- :class="{ active: !!props.header.sortKey }"
52
51
  size="s"
53
- plain
52
+ :plain="!!!props.header.sortKey"
54
53
  square
54
+ variant="gray"
55
55
  @click="props.header.sortToggle"
56
56
  />
57
57
  </div>
@@ -50,7 +50,7 @@ const selecting = inject(TableSelectionProvideSymbol) as TableSelectionProvide
50
50
  }"
51
51
  >
52
52
  <table>
53
- <thead>
53
+ <thead v-if="$slots.header">
54
54
  <tr>
55
55
  <slot name="header" />
56
56
  </tr>
@@ -59,7 +59,7 @@ const selecting = inject(TableSelectionProvideSymbol) as TableSelectionProvide
59
59
  <slot name="body" />
60
60
  </tbody>
61
61
  </table>
62
- <div class="vui-table-pagination-wrap">
62
+ <div v-if="$slots.pagination" class="vui-table-pagination-wrap">
63
63
  <slot name="pagination" />
64
64
  </div>
65
65
  </div>
@@ -1,6 +1,7 @@
1
1
  <script setup lang='ts'>
2
2
  import type { BaseRow, TableSelectionProvide } from './table'
3
3
  import { computed, inject } from 'vue'
4
+ import { isObjectInSet } from '../../shared/helpers'
4
5
  import Button from '../Button/Button.vue'
5
6
  import { TableSelectionProvideSymbol } from './table'
6
7
 
@@ -14,7 +15,7 @@ const {
14
15
  selectRow,
15
16
  selectedRows,
16
17
  } = inject(TableSelectionProvideSymbol) as TableSelectionProvide
17
- const isSelected = computed(() => selectedRows.value.has(props.row))
18
+ const isSelected = computed(() => isObjectInSet(selectedRows.value, props.row))
18
19
  </script>
19
20
 
20
21
  <template>
@@ -0,0 +1,7 @@
1
+ import Cell from './Cell.vue'
2
+ import Head from './Head.vue'
3
+ import Root from './Root.vue'
4
+ import SelectAll from './SelectAll.vue'
5
+ import SelectRow from './SelectRow.vue'
6
+
7
+ export { Cell, Head, Root, SelectAll, SelectRow }
@@ -47,16 +47,28 @@
47
47
  tr {
48
48
  border: none;
49
49
 
50
+ &:first-child td {
51
+ border-top: 0 !important;
52
+ }
53
+
50
54
  &:has(.vui-table-interactive-cell.selected) {
51
55
  td {
52
56
  background-color: var(--color-bg-raised);
53
57
  }
54
58
  }
59
+
60
+ &:last-child td {
61
+ border-bottom: 0;
62
+ }
63
+ }
64
+
65
+ th {
66
+ border-top: 0 !important;
55
67
  }
56
68
 
57
69
  th,
58
70
  td {
59
- font-size: var(--font-size-ms);
71
+ font-size: var(--font-size-m);
60
72
  border: none;
61
73
  border-left: none !important;
62
74
  transition: var(--transition-fast);
@@ -72,6 +84,7 @@
72
84
  height: auto;
73
85
  padding-inline: var(--space-xs);
74
86
  padding-block: 0;
87
+ vertical-align: middle;
75
88
 
76
89
  &.selected .vui-button.icon .vui-button-slot svg path {
77
90
  color: var(--color-text) !important;
@@ -107,24 +120,25 @@
107
120
 
108
121
  th {
109
122
  .vui-table-th-content {
110
- color: var(--color-text-light);
123
+ color: var(--color-text);
111
124
  font-size: var(--font-size-xs);
112
125
  text-transform: uppercase;
113
- font-weight: 500;
126
+ font-weight: var(--font-weight-semibold);
114
127
  display: flex;
115
128
  justify-content: flex-start;
116
129
  align-items: center;
117
130
  gap: var(--space-xs);
118
131
 
119
132
  .vui-table-sort-button:not(.active) svg path {
120
- color: var(--color-text-lighter);
133
+ color: var(--color-text-light);
121
134
  }
122
135
  }
123
136
  }
124
137
  }
125
138
 
126
139
  .vui-table-pagination-wrap {
127
- padding: var(--space-s) var(--space-m);
140
+ padding: var(--space-xs) var(--space-m);
141
+ border-top: 1px solid var(--color-border);
128
142
 
129
143
  p {
130
144
  font-size: var(--font-size-s);
@@ -132,3 +146,9 @@
132
146
  }
133
147
  }
134
148
  }
149
+
150
+ :root.light {
151
+ .vui-table-container table tr:has(.vui-table-interactive-cell.selected) td {
152
+ background-color: var(--color-bg-medium);
153
+ }
154
+ }
@@ -38,7 +38,7 @@ interface TableOptionsInput {
38
38
  }
39
39
 
40
40
  // eslint-disable-next-line ts/explicit-function-return-type
41
- export function defineTable<const Dataset extends Array<BaseRow>>(
41
+ export function defineTable<const Dataset extends any[]>(
42
42
  computedDataset: MaybeRefOrGetter<Dataset>,
43
43
  tableOptions?: TableOptionsInput,
44
44
  ) {
@@ -139,7 +139,7 @@ export function defineTable<const Dataset extends Array<BaseRow>>(
139
139
  })
140
140
 
141
141
  const headers = computed(() => Object
142
- .keys($data.value[0])
142
+ .keys($data.value[0] || {})
143
143
  .map((key) => {
144
144
  return {
145
145
  label: key,
@@ -212,7 +212,11 @@ export function defineTable<const Dataset extends Array<BaseRow>>(
212
212
  selectedRows.value = new Set()
213
213
  }
214
214
  else {
215
- selectedRows.value = new Set($data.value.map(row => row))
215
+ const data = new Set<BaseRow>()
216
+ for (const item of $data.value) {
217
+ data.add(item)
218
+ }
219
+ selectedRows.value = new Set(data)
216
220
  }
217
221
  }
218
222
 
@@ -1,27 +1,25 @@
1
1
  <script setup lang="ts">
2
2
  import { Icon } from '@iconify/vue'
3
- import { computed } from 'vue'
4
3
 
5
4
  export interface TabProps {
6
5
  disabled?: boolean
7
- id?: string
8
- label: string
6
+ label?: string
9
7
  icon?: string
10
8
  }
11
-
12
9
  const props = defineProps<TabProps>()
13
- const id = computed(() => props.id ?? props.label)
14
10
  </script>
15
11
 
16
12
  <template>
17
13
  <button
18
14
  class="vui-tab"
19
- :data-tab-id="id"
15
+ :data-tab-id="label"
20
16
  :class="{ disabled: props.disabled }"
21
17
  role="tab"
22
- :name="id"
18
+ :name="label"
23
19
  >
24
- <Icon v-if="props.icon" :icon="props.icon" />
25
- {{ props.label }}
20
+ <slot>
21
+ <Icon v-if="props.icon" :icon="props.icon" />
22
+ {{ props.label }}
23
+ </slot>
26
24
  </button>
27
25
  </template>
@@ -18,6 +18,8 @@ const {
18
18
 
19
19
  const slots = defineSlots<{
20
20
  default: () => Array<VNode & { props: TabProps }>
21
+ start: unknown
22
+ end: unknown
21
23
  }>()
22
24
 
23
25
  const active = defineModel()
@@ -67,13 +69,18 @@ onMounted(() => {
67
69
  : `vui-tabs-variant-${variant}`,
68
70
  ]"
69
71
  >
72
+ <slot name="start" />
70
73
  <Component
71
74
  :is="vnode"
72
75
  v-for="vnode of slots.default()"
73
76
  :key="vnode.props.id"
74
- :class="{ active: vnode.props.id === active }"
75
- @click="active = vnode.props.id"
77
+ :class="{ active: vnode.props.label === active }"
78
+ @click="active = vnode.props.label"
76
79
  />
80
+ <template v-if="slots.end">
81
+ <div v-if="!!!expand" class="flex-1" />
82
+ <slot name="end" />
83
+ </template>
77
84
 
78
85
  <Transition name="fade" appear>
79
86
  <div ref="underline" class="vui-tab-underline" />
@@ -2,6 +2,7 @@
2
2
  display: flex;
3
3
  width: 100%;
4
4
  gap: 4px;
5
+ align-items: center;
5
6
  border-bottom: 1px solid var(--color-border);
6
7
  position: relative;
7
8
 
@@ -49,9 +50,10 @@
49
50
  align-items: center;
50
51
  justify-content: center;
51
52
  padding: 0 10px;
52
- font-size: var(--font-size-ms);
53
+ font-size: var(--font-size-m);
53
54
  position: relative;
54
- color: var(--color-text-light);
55
+ color: var(--color-text-lighter);
56
+ font-weight: var(--font-weight-medium);
55
57
  transition: var(--transition);
56
58
  cursor: default;
57
59
  gap: var(--space-xs);
@@ -72,8 +74,14 @@
72
74
  .vui-tab-underline {
73
75
  transition: var(--transition);
74
76
  display: block;
75
- border-bottom: 1px solid var(--color-text);
77
+ border-bottom: 2px solid var(--color-text);
76
78
  position: absolute;
77
79
  bottom: 0;
78
80
  }
79
81
  }
82
+
83
+ :root.light {
84
+ .vui-tabs.vui-tabs-variant-filled {
85
+ background-color: var(--color-bg-medium);
86
+ }
87
+ }
@@ -14,6 +14,11 @@ import './toast.scss'
14
14
  <p v-if="toast.description">
15
15
  {{ toast.description }}
16
16
  </p>
17
+ <Component
18
+ :is="toast.body"
19
+ v-if="toast.body"
20
+ v-bind="{ data: toast.bodyProps, toastId }"
21
+ />
17
22
  </div>
18
23
  <Button v-if="toast.action" @click="toast.action.handler(toast.id)">
19
24
  {{ toast.action.label }}
@@ -14,8 +14,8 @@
14
14
  display: flex;
15
15
  border: 1px solid var(--color-border);
16
16
  border-radius: var(--border-radius-m);
17
- padding: var(--space-m) var(--space-s);
18
- background-color: var(--color-bg);
17
+ padding: var(--space-m);
18
+ background-color: var(--color-bg-lowered);
19
19
  width: 100%;
20
20
  align-items: center;
21
21
  gap: var(--space-m);
@@ -29,6 +29,10 @@
29
29
  margin-bottom: var(--space-xs);
30
30
  display: block;
31
31
  font-size: var(--font-size-m);
32
+
33
+ &:only-child {
34
+ margin: 0;
35
+ }
32
36
  }
33
37
 
34
38
  p {
@@ -1,3 +1,4 @@
1
+ import type { Component } from 'vue'
1
2
  import { ref } from 'vue'
2
3
 
3
4
  interface ToastAction {
@@ -10,6 +11,8 @@ interface ToastOptions {
10
11
  timeout?: number
11
12
  action?: ToastAction
12
13
  description?: string
14
+ body?: Component
15
+ bodyProps?: object
13
16
  }
14
17
 
15
18
  interface Toast {
@@ -20,6 +23,8 @@ interface Toast {
20
23
  createdAt: number
21
24
  expiresAt: number
22
25
  description?: string
26
+ body?: Component
27
+ bodyProps?: object
23
28
  }
24
29
 
25
30
  // Store in a ref so the toast component can import it
@@ -44,6 +49,8 @@ export function pushToast(title: string, options?: ToastOptions): Toast {
44
49
  action: parsedOptions.action,
45
50
  createdAt: Date.now(),
46
51
  expiresAt: Date.now() + parsedOptions.timeout,
52
+ body: parsedOptions.body,
53
+ bodyProps: parsedOptions.bodyProps ?? {},
47
54
  }
48
55
 
49
56
  toasts.value.set(id, newToast)