@dolanske/vui 0.5.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 (152) hide show
  1. package/README.md +5 -4
  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/Grid/Grid.vue.d.ts +4 -1
  13. package/dist/components/Input/Dropzone.vue.d.ts +1 -1
  14. package/dist/components/Input/Input.vue.d.ts +2 -2
  15. package/dist/components/Kbd/KbdGroup.vue.d.ts +3 -11
  16. package/dist/components/Modal/Confirm.vue.d.ts +1 -1
  17. package/dist/components/Modal/Modal.vue.d.ts +1 -1
  18. package/dist/components/Pagination/Pagination.vue.d.ts +3 -0
  19. package/dist/components/Popout/Popout.vue.d.ts +8 -1
  20. package/dist/components/Progress/Progress.vue.d.ts +2 -0
  21. package/dist/components/Radio/Radio.vue.d.ts +1 -0
  22. package/dist/components/Select/Select.vue.d.ts +2 -0
  23. package/dist/components/Sheet/Sheet.vue.d.ts +3 -0
  24. package/dist/components/Switch/Switch.vue.d.ts +1 -0
  25. package/dist/components/Table/index.d.ts +6 -0
  26. package/dist/components/Table/table.d.ts +1 -1
  27. package/dist/components/Tabs/Tab.vue.d.ts +16 -3
  28. package/dist/components/Toast/toast.d.ts +245 -0
  29. package/dist/index.d.ts +2 -7
  30. package/dist/shared/helpers.d.ts +9 -0
  31. package/dist/shared/theme.d.ts +3 -0
  32. package/dist/style.css +1 -1
  33. package/dist/vui.js +6418 -6049
  34. package/package.json +7 -3
  35. package/src/App.vue +90 -171
  36. package/src/components/Accordion/accordion.scss +1 -0
  37. package/src/components/Alert/Alert.vue +11 -5
  38. package/src/components/Alert/alert.scss +104 -23
  39. package/src/components/Avatar/Avatar.vue +4 -1
  40. package/src/components/Avatar/avatar.scss +1 -1
  41. package/src/components/Badge/Badge.vue +1 -1
  42. package/src/components/Badge/badge.scss +134 -17
  43. package/src/components/Breadcrumbs/BreadcrumbItem.vue +2 -2
  44. package/src/components/Breadcrumbs/Breadcrumbs.vue +1 -2
  45. package/src/components/Breadcrumbs/breadcrumbs.scss +2 -1
  46. package/src/components/Button/Button.vue +15 -20
  47. package/src/components/Button/button.scss +156 -55
  48. package/src/components/ButtonGroup/ButtonGroup.vue +4 -1
  49. package/src/components/ButtonGroup/button-group.scss +2 -2
  50. package/src/components/Calendar/Calendar.vue +4 -1
  51. package/src/components/Calendar/calendar.scss +25 -2
  52. package/src/components/Card/Card.vue +2 -2
  53. package/src/components/Card/card.scss +4 -4
  54. package/src/components/Checkbox/Checkbox.vue +4 -1
  55. package/src/components/Checkbox/checkbox.scss +17 -12
  56. package/src/components/CopyClipboard/CopyClipboard.vue +15 -6
  57. package/src/components/CopyClipboard/copy-clipboard.scss +10 -2
  58. package/src/components/Drawer/Drawer.vue +4 -4
  59. package/src/components/Drawer/drawer.scss +1 -0
  60. package/src/components/Dropdown/Dropdown.vue +44 -20
  61. package/src/components/Dropdown/DropdownItem.vue +4 -4
  62. package/src/components/Dropdown/DropdownTitle.vue +7 -1
  63. package/src/components/Dropdown/dropdown-item.scss +9 -2
  64. package/src/components/Dropdown/dropdown.scss +21 -7
  65. package/src/components/Grid/Grid.vue +21 -1
  66. package/src/components/Input/Color.vue +26 -0
  67. package/src/components/Input/Counter.vue +12 -16
  68. package/src/components/Input/Dropzone.vue +1 -1
  69. package/src/components/Input/File.vue +1 -1
  70. package/src/components/Input/Input.vue +8 -6
  71. package/src/components/Input/Password.vue +1 -13
  72. package/src/components/Input/Textarea.vue +4 -2
  73. package/src/components/Input/input.scss +110 -16
  74. package/src/components/Kbd/KbdGroup.vue +2 -6
  75. package/src/components/Kbd/kbd.scss +6 -5
  76. package/src/components/Modal/Confirm.vue +1 -1
  77. package/src/components/Modal/Modal.vue +23 -15
  78. package/src/components/Modal/modal.scss +11 -6
  79. package/src/components/OTP/otp.scss +8 -7
  80. package/src/components/Pagination/Pagination.vue +6 -3
  81. package/src/components/Popout/Popout.vue +15 -5
  82. package/src/components/Popout/popout.scss +8 -1
  83. package/src/components/Progress/Progress.vue +18 -5
  84. package/src/components/Progress/progress.scss +7 -1
  85. package/src/components/Radio/Radio.vue +4 -2
  86. package/src/components/Radio/radio.scss +18 -8
  87. package/src/components/Select/Select.vue +49 -18
  88. package/src/components/Select/select.scss +35 -2
  89. package/src/components/Sheet/Sheet.vue +8 -2
  90. package/src/components/Sheet/sheet.scss +9 -0
  91. package/src/components/Sidebar/Sidebar.vue +24 -11
  92. package/src/components/Sidebar/sidebar.scss +6 -5
  93. package/src/components/Spinner/spinner.scss +2 -1
  94. package/src/components/Switch/Switch.vue +4 -3
  95. package/src/components/Switch/switch.scss +39 -6
  96. package/src/components/Table/{Header.vue → Head.vue} +5 -5
  97. package/src/components/Table/{Table.vue → Root.vue} +2 -2
  98. package/src/components/Table/SelectRow.vue +2 -1
  99. package/src/components/Table/index.ts +7 -0
  100. package/src/components/Table/table.scss +25 -5
  101. package/src/components/Table/table.ts +7 -3
  102. package/src/components/Tabs/Tab.vue +7 -9
  103. package/src/components/Tabs/Tabs.vue +2 -2
  104. package/src/components/Tabs/tabs.scss +10 -3
  105. package/src/components/Toast/Toasts.vue +5 -0
  106. package/src/components/Toast/toast.scss +6 -2
  107. package/src/components/Toast/toast.ts +7 -0
  108. package/src/components/Tooltip/Tooltip.vue +9 -9
  109. package/src/components/Tooltip/tooltip.scss +4 -0
  110. package/src/examples/ExampleAccordions.vue +58 -0
  111. package/src/examples/ExampleAlerts.vue +78 -0
  112. package/src/examples/ExampleAvatars.vue +44 -0
  113. package/src/examples/ExampleBadges.vue +48 -0
  114. package/src/examples/ExampleBreadcrumbs.vue +46 -0
  115. package/src/examples/ExampleButtons.vue +140 -0
  116. package/src/examples/ExampleCalendars.vue +40 -0
  117. package/src/examples/ExampleCards.vue +94 -0
  118. package/src/examples/ExampleCheckboxes.vue +123 -0
  119. package/src/examples/ExampleCopyClipboard.vue +47 -0
  120. package/src/examples/ExampleDividers.vue +39 -0
  121. package/src/examples/ExampleDrawers.vue +67 -0
  122. package/src/examples/ExampleDropdowns.vue +114 -0
  123. package/src/examples/ExampleFlexGrid.vue +122 -0
  124. package/src/examples/ExampleInputs.vue +234 -0
  125. package/src/examples/ExampleKBD.vue +65 -0
  126. package/src/examples/ExampleModals.vue +143 -0
  127. package/src/examples/ExamplePalette.vue +159 -0
  128. package/src/examples/ExamplePopouts.vue +41 -0
  129. package/src/examples/ExampleSheets.vue +77 -0
  130. package/src/examples/ExampleSidebars.vue +270 -0
  131. package/src/examples/ExampleSkeletons.vue +26 -0
  132. package/src/examples/ExampleSpinners.vue +78 -0
  133. package/src/examples/ExampleTables.vue +195 -0
  134. package/src/examples/ExampleTabs.vue +119 -0
  135. package/src/examples/ExampleToasts.vue +96 -0
  136. package/src/examples/ExampleTooltips.vue +70 -0
  137. package/src/examples/shared/ExampleColor.vue +28 -0
  138. package/src/index.ts +4 -11
  139. package/src/internal/Backdrop/backdrop.scss +7 -1
  140. package/src/shared/helpers.ts +43 -0
  141. package/src/shared/theme.ts +22 -0
  142. package/src/style/animation.scss +1 -0
  143. package/src/style/core.scss +30 -55
  144. package/src/style/layout.scss +74 -9
  145. package/src/style/text.scss +18 -0
  146. package/src/style/theme.scss +195 -0
  147. package/src/style/tooltip.scss +22 -4
  148. package/src/style/typography.scss +95 -18
  149. package/dist/components/Table/Row.vue.d.ts +0 -16
  150. package/src/components/Table/Row.vue +0 -9
  151. /package/dist/components/Table/{Header.vue.d.ts → Head.vue.d.ts} +0 -0
  152. /package/dist/components/Table/{Table.vue.d.ts → Root.vue.d.ts} +0 -0
@@ -48,7 +48,7 @@ onMounted(() => {
48
48
  <input :id="inputId" type="file">
49
49
  <label :for="inputId">
50
50
  <slot :dragging>
51
- <Flex justify-center gap="s" align-baseline>
51
+ <Flex justify-center gap="xs" align-center>
52
52
  <template v-if="dragging">
53
53
  <Icon icon="ph:target" />
54
54
  Drop it
@@ -9,7 +9,7 @@ const emits = defineEmits<{ files: [FileList] }>()
9
9
  <template>
10
10
  <Input
11
11
  type="file"
12
- v-bind="{ ...props }"
12
+ v-bind="props"
13
13
  @input="emits('files', $event.target.files)"
14
14
  />
15
15
  </template>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, type InputTypeHTMLAttribute, useId, useTemplateRef, watchEffect } from 'vue'
2
+ import { computed, useId, useTemplateRef, watchEffect } from 'vue'
3
3
  import { getMaybeRefLength } from '../../shared/helpers'
4
4
  import Flex from '../Flex/Flex.vue'
5
5
  import '../../style/core.scss'
@@ -7,8 +7,10 @@ import './input.scss'
7
7
 
8
8
  // FIXME: sometimes spamming inputs when limit is set, it will _just_ let me write one more letter
9
9
 
10
+ export type InputType = 'text' | 'password' | 'color' | 'date' | 'email' | 'number' | 'range' | 'search' | 'tel' | 'time' | 'url' | 'file'
11
+
10
12
  export interface InputProps {
11
- type?: InputTypeHTMLAttribute
13
+ type?: InputType
12
14
  label?: string
13
15
  hint?: string
14
16
  limit?: number | string
@@ -63,12 +65,12 @@ const inputRef = useTemplateRef('input')
63
65
 
64
66
  watchEffect(() => {
65
67
  if (focus)
66
- inputRef.value?.focus()
68
+ inputRef.value?.focus({ preventScroll: true })
67
69
  })
68
70
 
69
71
  defineExpose({
70
72
  focus: () => {
71
- inputRef.value?.focus()
73
+ inputRef.value?.focus({ preventScroll: true })
72
74
  },
73
75
  })
74
76
 
@@ -81,11 +83,11 @@ const renderLimit = computed(() => {
81
83
  <div class="vui-input-container" :class="{ expand, disabled, required, readonly, 'has-errors': errors.length > 0 }">
82
84
  <slot name="before" />
83
85
  <div class="vui-input">
84
- <label v-if="label" for="id">{{ label }}</label>
86
+ <label v-if="label" :for="id">{{ label }}</label>
85
87
  <p v-if="hint" class="vui-input-hint">
86
88
  {{ hint }}
87
89
  </p>
88
- <Flex class="vui-input-style" :gap="3" align-center>
90
+ <Flex class="vui-input-style" :gap="5" align-center>
89
91
  <slot name="start" />
90
92
  <slot name="__internal_replace_input" :input-id="id" />
91
93
  <input
@@ -25,8 +25,7 @@ const show = ref(showPassword)
25
25
  <template #end>
26
26
  <Button
27
27
  square
28
- size="s"
29
- :data-title-top="show ? 'Hide password' : 'Show password'"
28
+ :data-title-top="show ? 'Hide' : 'Reveal'"
30
29
  @click="show = !show"
31
30
  >
32
31
  <Icon :width="18" :height="18" :icon="show ? 'ph:eye-slash' : 'ph:eye'" />
@@ -34,14 +33,3 @@ const show = ref(showPassword)
34
33
  </template>
35
34
  </Input>
36
35
  </template>
37
-
38
- <style scoped lang="scss">
39
- :deep(.vui-input-style) {
40
- padding-right: 4px !important;
41
- gap: 8px !important;
42
- }
43
-
44
- [data-title-top]:before {
45
- min-width: 104px;
46
- }
47
- </style>
@@ -20,6 +20,7 @@ const {
20
20
  resize = 'vertical',
21
21
  autoResize,
22
22
  errors = [] as string[],
23
+ disabled,
23
24
  } = defineProps<Props>()
24
25
 
25
26
  const model = defineModel<string>({
@@ -41,10 +42,10 @@ const fS = computed(() => autoResize ? 'content' : 'auto')
41
42
  </script>
42
43
 
43
44
  <template>
44
- <div class="vui-input-container" :class="{ expand, required, readonly, 'has-errors': errors.length > 0 }">
45
+ <div class="vui-input-container" :class="{ expand, required, readonly, 'has-errors': errors.length > 0, disabled }">
45
46
  <slot name="before" />
46
47
  <div class="vui-input">
47
- <label v-if="label" for="id">{{ label }}</label>
48
+ <label v-if="label" :for="id">{{ label }}</label>
48
49
  <p v-if="hint" class="vui-input-hint">
49
50
  {{ hint }}
50
51
  </p>
@@ -55,6 +56,7 @@ const fS = computed(() => autoResize ? 'content' : 'auto')
55
56
  name="id"
56
57
  :placeholder
57
58
  :required
59
+ :disabled
58
60
  :max="limit"
59
61
  :style="{
60
62
  resize: r,
@@ -17,9 +17,16 @@
17
17
 
18
18
  width: 224px;
19
19
 
20
- &.disabled input,
21
- &.disabled textarea {
22
- cursor: not-allowed;
20
+ &.disabled {
21
+ .vui-input label {
22
+ color: var(--input-color-text-lighter);
23
+ }
24
+
25
+ input,
26
+ textarea {
27
+ cursor: not-allowed;
28
+ resize: none !important;
29
+ }
23
30
  }
24
31
 
25
32
  &.expand {
@@ -28,7 +35,9 @@
28
35
 
29
36
  &.required .vui-input > label:after {
30
37
  content: '*';
38
+ padding-left: 2px;
31
39
  color: var(--input-color-text-red);
40
+ font-size: var(--font-size-l);
32
41
  }
33
42
 
34
43
  &.readonly .vui-input {
@@ -38,6 +47,7 @@
38
47
  pointer-events: none;
39
48
  color: var(--input-color-text-light);
40
49
  border-color: var(--input-color-border-weak);
50
+ resize: none !important;
41
51
  }
42
52
  }
43
53
 
@@ -45,20 +55,33 @@
45
55
  .vui-input {
46
56
  .vui-input-style,
47
57
  textarea {
48
- border-color: var(--color-text-red) !important;
58
+ outline: 1px solid var(--color-text-red) !important;
49
59
  }
50
60
  }
51
61
  }
52
62
 
63
+ &.vui-input-color {
64
+ .vui-input-style {
65
+ padding-left: 0 !important;
66
+ outline: none !important;
67
+ }
68
+ }
69
+
53
70
  .vui-input {
54
71
  label {
55
72
  display: block;
56
73
  text-align: left;
57
74
  margin-bottom: 8px;
58
- font-size: var(--font-size-ms);
75
+ font-size: var(--font-size-m);
59
76
  color: var(--input-color-text);
60
77
  }
61
78
 
79
+ svg {
80
+ min-width: 16px;
81
+ min-height: 16px;
82
+ // font-size: var(--font-size-l);
83
+ }
84
+
62
85
  .vui-input-hint {
63
86
  margin-bottom: 8px;
64
87
  margin-top: -4px;
@@ -82,22 +105,42 @@
82
105
  background: transparent;
83
106
  height: var(--input-height);
84
107
  line-height: var(--input-height);
85
- color: var(--color-text);
108
+ color: var(--color-text-lighter);
86
109
  outline: none;
87
- padding-inline: var(--input-padding);
88
- font-size: var(--font-size-ms);
110
+ font-size: var(--font-size-m);
89
111
  width: 100%;
90
- transition: var(--transition);
112
+ transition: var(--transition-fast);
113
+ padding-inline: var(--input-padding);
114
+ z-index: 1;
91
115
 
92
- &:has(input:focus-visible),
93
- &:focus-visible {
94
- outline: 2px solid var(--color-text);
116
+ &:has(input:focus),
117
+ &:focus {
118
+ // Override error outline
119
+ outline: 2px solid var(--color-text) !important;
120
+ }
121
+
122
+ .vui-button {
123
+ border: 1px solid var(--color-border);
124
+
125
+ &:first-child {
126
+ border-top-right-radius: 0;
127
+ border-bottom-right-radius: 0;
128
+ margin-left: calc(calc(var(--input-padding) + 1px) * -1);
129
+ }
130
+
131
+ &:last-child {
132
+ border-top-left-radius: 0;
133
+ border-bottom-left-radius: 0;
134
+ margin-right: calc(calc(var(--input-padding) + 1px) * -1);
135
+ }
95
136
  }
96
137
  }
97
138
 
98
139
  input,
99
140
  textarea {
141
+ color: var(--color-text);
100
142
  font-family: var(--global-font);
143
+ // padding-inline: 3px;
101
144
  }
102
145
 
103
146
  input[type='file']::file-selector-button {
@@ -114,6 +157,51 @@
114
157
  background-color: var(--color-border);
115
158
  }
116
159
 
160
+ input[type='color'] {
161
+ width: 1px;
162
+ height: 1px;
163
+ position: absolute;
164
+ overflow: hidden;
165
+ outline: none !important;
166
+ opacity: 0;
167
+
168
+ &:focus + label .vui-input-color-indicator {
169
+ outline: 2px solid var(--color-text);
170
+ }
171
+
172
+ & + label {
173
+ position: relative;
174
+ margin: 0;
175
+ padding-left: var(--input-height);
176
+
177
+ input {
178
+ padding-inline: var(--space-xs);
179
+ border-radius: var(--border-radius-s);
180
+
181
+ &:focus {
182
+ outline: 2px solid var(--color-text);
183
+ }
184
+ }
185
+
186
+ .vui-input-color-indicator {
187
+ position: absolute;
188
+ inset: 4px;
189
+ right: unset;
190
+ width: calc(var(--input-height) - 8px);
191
+ background-color: var(--color-border);
192
+ border-radius: var(--border-radius-s);
193
+ font-size: var(--font-size-l);
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: center;
197
+
198
+ &:hover {
199
+ opacity: 0.8;
200
+ }
201
+ }
202
+ }
203
+ }
204
+
117
205
  ::-moz-range-thumb,
118
206
  ::-webkit-slider-thumb {
119
207
  width: 16px;
@@ -130,7 +218,7 @@
130
218
  line-height: calc(var(--input-height) - 1px);
131
219
  background: transparent;
132
220
  outline: none;
133
- font-size: var(--font-size-ms);
221
+ font-size: var(--font-size-m);
134
222
  color: var(--color-text);
135
223
 
136
224
  &:-webkit-autofill {
@@ -172,12 +260,13 @@
172
260
 
173
261
  &.vui-dropzone {
174
262
  &.dragging .vui-input .vui-input-style {
175
- border-color: var(--color-border-accent);
263
+ border-color: var(--color-accent);
176
264
 
177
265
  &:hover {
178
266
  border-color: var(--color-border);
179
267
  }
180
268
  }
269
+
181
270
  .vui-input {
182
271
  .vui-input-style {
183
272
  height: unset;
@@ -187,11 +276,15 @@
187
276
  line-height: 1.2em;
188
277
 
189
278
  &:hover {
190
- border-color: var(--color-border-strong);
279
+ border-color: var(--color-accent);
191
280
  }
192
281
 
193
282
  input {
194
- display: none;
283
+ width: 1px;
284
+ height: 1px;
285
+ position: absolute;
286
+ outline: 0 !important;
287
+ opacity: 0 !important;
195
288
 
196
289
  & + label {
197
290
  display: flex;
@@ -199,6 +292,7 @@
199
292
  justify-content: center;
200
293
  width: 100%;
201
294
  min-height: 96px;
295
+ margin: 0;
202
296
  color: var(--color-text-light);
203
297
  }
204
298
  }
@@ -1,5 +1,5 @@
1
1
  <script setup lang='ts'>
2
- import type { VNode } from 'vue'
2
+ import type Kbd from './Kbd.vue'
3
3
  import { useMagicKeys, whenever } from '@vueuse/core'
4
4
 
5
5
  /**
@@ -12,11 +12,7 @@ const emits = defineEmits<{
12
12
  }>()
13
13
 
14
14
  const slots = defineSlots<{
15
- default: () => Array<VNode & {
16
- props: {
17
- keys: string
18
- }
19
- }>
15
+ default: () => Array<typeof Kbd>
20
16
  }>()
21
17
  const keys = useMagicKeys()
22
18
 
@@ -4,15 +4,16 @@
4
4
  justify-content: center;
5
5
  height: 24px;
6
6
  border-radius: var(--border-radius-xs);
7
- // border: 1px solid var(--color-border-strong);
8
7
  font-size: var(--font-size-s);
9
8
  padding: 0 4px;
10
- transition: var(--transition);
9
+ transition: var(--transition-fast);
11
10
  font-weight: 600;
12
- background-color: var(--color-text);
13
- color: var(--color-text-invert);
11
+ background-color: var(--color-button-gray);
12
+ color: var(--color-text-accent);
14
13
 
15
14
  &.active {
16
- background-color: var(--color-text-yellow);
15
+ transform: translateY(2px);
16
+ color: var(--color-text-invert);
17
+ background-color: var(--color-button-fill);
17
18
  }
18
19
  }
@@ -20,7 +20,7 @@ const props = withDefaults(defineProps<Props>(), {
20
20
  size: 's',
21
21
  canDismiss: true,
22
22
  showCancel: true,
23
- confirmVariant: 'default',
23
+ confirmVariant: 'gray',
24
24
  })
25
25
 
26
26
  const emits = defineEmits<{
@@ -8,7 +8,7 @@ import Card from '../Card/Card.vue'
8
8
  import './modal.scss'
9
9
 
10
10
  export interface ModalProps {
11
- size?: Sizes | 'full'
11
+ size?: Sizes | 'full' | 'screen'
12
12
  /**
13
13
  * Modal wraps a floating card. You can optinally pass in any props you'd pass
14
14
  * into the <Card /> component.
@@ -43,32 +43,40 @@ function close() {
43
43
  }
44
44
 
45
45
  const attrs = useAttrs()
46
+
47
+ function tryClose() {
48
+ if (canDismiss) {
49
+ close()
50
+ }
51
+ }
46
52
  </script>
47
53
 
48
54
  <template>
49
55
  <Teleport to="body">
50
56
  <Transition appear name="modal">
51
- <Backdrop v-if="open" @close="close">
52
- <div class="vui-modal" :class="[`vui-modal-size-${size}`, { scrollable, centered }]" v-bind="attrs">
53
- <Button
54
- v-if="canDismiss"
55
- class="vui-modal-close"
56
- plain
57
- square
58
- icon="ph:x"
59
- @click="open = false"
60
- />
57
+ <Backdrop v-if="open" :class="{ 'p-0': size === 'screen' }" @close="tryClose">
58
+ <div class="vui-modal" :class="[`vui-modal-size-${size}`, { scrollable: scrollable || size === 'screen', centered }]" v-bind="attrs" @click.self="tryClose">
61
59
  <Card v-bind="card">
62
60
  <template v-if="$slots.header" #header>
63
- <slot name="header" :close />
61
+ <slot name="header" :close="close" />
62
+ </template>
63
+ <template #header-end>
64
+ <Button
65
+ v-if="canDismiss"
66
+ class="vui-modal-close"
67
+ plain
68
+ square
69
+ icon="ph:x"
70
+ @click="open = false"
71
+ />
64
72
  </template>
65
73
  <template v-if="$slots.default" #default>
66
74
  <div>
67
- <slot name="default" :close />
75
+ <slot name="default" :close="close" />
68
76
  </div>
69
77
  </template>
70
78
  <template v-if="$slots.footer" #footer>
71
- <slot name="footer" :close />
79
+ <slot name="footer" :close="close" />
72
80
  </template>
73
81
  </Card>
74
82
  </div>
@@ -86,6 +94,6 @@ const attrs = useAttrs()
86
94
  .modal-enter-from,
87
95
  .modal-leave-to {
88
96
  opacity: 0;
89
- transform: scale(0.95);
97
+ transform: scale(1.025);
90
98
  }
91
99
  </style>
@@ -4,12 +4,6 @@
4
4
  height: 100%;
5
5
  position: relative;
6
6
 
7
- .vui-modal-close {
8
- position: absolute;
9
- top: 16px;
10
- right: 16px;
11
- }
12
-
13
7
  &.centered {
14
8
  display: flex;
15
9
  align-items: center;
@@ -27,6 +21,17 @@
27
21
  max-width: 728px;
28
22
  }
29
23
 
24
+ &.vui-modal-size-screen {
25
+ position: fixed;
26
+ inset: 0;
27
+
28
+ & > .vui-card {
29
+ border-radius: 0;
30
+ border: none;
31
+ height: 100vh;
32
+ }
33
+ }
34
+
30
35
  &.scrollable {
31
36
  & > .vui-card {
32
37
  display: flex;
@@ -10,21 +10,22 @@
10
10
  display: flex;
11
11
  align-items: center;
12
12
  justify-content: center;
13
- width: 42px;
14
- height: 42px;
13
+ width: var(--interactive-el-height);
14
+ height: var(--interactive-el-height);
15
15
  border: 1px solid var(--color-border-strong);
16
16
  color: var(--color-text);
17
17
  z-index: 1;
18
18
  font-size: var(--font-size-m);
19
19
  outline: 0 solid var(--color-text-light);
20
- transition: var(--transition);
20
+ transition: var(--transition-fast);
21
21
 
22
22
  .blinker {
23
- display: none;
23
+ display: block;
24
24
  height: 16px;
25
25
  width: 1px;
26
26
  background-color: var(--color-text);
27
- animation: blink 1.25s ease-out infinite;
27
+ animation: blink 1s ease-out infinite;
28
+ visibility: hidden;
28
29
  }
29
30
 
30
31
  @keyframes blink {
@@ -40,7 +41,7 @@
40
41
  }
41
42
 
42
43
  &.has-value {
43
- background-color: var(--color-bg-raised);
44
+ background-color: var(--color-bg-medium);
44
45
 
45
46
  .blinker {
46
47
  display: none !important;
@@ -52,7 +53,7 @@
52
53
  outline-width: 2px;
53
54
 
54
55
  .blinker {
55
- display: block;
56
+ visibility: visible;
56
57
  }
57
58
  }
58
59
 
@@ -1,4 +1,5 @@
1
1
  <script setup lang='ts'>
2
+ import type { Variants } from '../Button/Button.vue'
2
3
  import type { Pagination } from './pagination'
3
4
  import { computed } from 'vue'
4
5
  import Button from '../Button/Button.vue'
@@ -9,12 +10,14 @@ interface Props {
9
10
  pagination: Pagination
10
11
  prevNext?: boolean
11
12
  firstLast?: boolean
13
+ variant?: Variants
12
14
  }
13
15
 
14
16
  const props = withDefaults(defineProps<Props>(), {
15
17
  numbers: true,
16
18
  prevNext: true,
17
19
  firstLast: true,
20
+ variant: 'gray',
18
21
  })
19
22
 
20
23
  const emit = defineEmits<{
@@ -34,7 +37,7 @@ function setPrev() {
34
37
  </script>
35
38
 
36
39
  <template>
37
- <Flex inline class="vui-pagination" gap="s">
40
+ <Flex inline class="vui-pagination" gap="xxs">
38
41
  <slot name="start">
39
42
  <Button v-if="props.firstLast" data-title-top="First page" plain :disabled="props.pagination.startPage === props.pagination.currentPage" square icon="ph:caret-double-left" @click="emit('change', props.pagination.startPage)" />
40
43
  </slot>
@@ -44,13 +47,13 @@ function setPrev() {
44
47
  </slot>
45
48
 
46
49
  <template v-if="props.numbers">
47
- <Flex gap="s">
50
+ <Flex gap="xxs">
48
51
  <Button
49
52
  v-for="page in props.pagination.pages"
50
53
  :key="page"
51
54
  square
52
55
  :plain="props.pagination.currentPage !== page"
53
- :variant="props.pagination.currentPage === page ? 'blue' : 'default'"
56
+ variant="gray"
54
57
  @click="emit('change', page)"
55
58
  >
56
59
  {{ page }}
@@ -1,10 +1,14 @@
1
1
  <script setup lang='ts'>
2
2
  import type { Placement, PopoutMaybeElement } from '../../shared/types'
3
- import { autoPlacement, offset, shift, useFloating } from '@floating-ui/vue'
3
+ import { flip, offset, shift, useFloating } from '@floating-ui/vue'
4
+ import { onClickOutside } from '@vueuse/core'
4
5
  import { toRef, useTemplateRef } from 'vue'
5
6
  import './popout.scss'
6
7
 
7
8
  export interface Props {
9
+ /**
10
+ * Reference to the HTML element the Popout is anchored to
11
+ */
8
12
  anchor: PopoutMaybeElement<HTMLElement>
9
13
  /**
10
14
  * Override the autoPlacement option
@@ -20,19 +24,25 @@ const props = withDefaults(defineProps<Props>(), {
20
24
  offset: 8,
21
25
  })
22
26
 
27
+ const emit = defineEmits<{
28
+ clickOutside: []
29
+ }>()
23
30
  const popoutRef = useTemplateRef('popout')
24
31
  const anchorRef = toRef(props.anchor)
25
32
 
26
33
  const { floatingStyles } = useFloating(anchorRef, popoutRef, {
27
34
  placement: props.placement,
28
35
  middleware: [
29
- ...(props.placement ? [] : [autoPlacement()]),
36
+ // ...(props.placement
37
+ // ? []
38
+ // : [autoPlacement()]),
39
+ shift({ padding: 8 }),
40
+ flip(),
30
41
  offset(props.offset),
31
- shift({
32
- padding: 8,
33
- }),
34
42
  ],
35
43
  })
44
+
45
+ onClickOutside(popoutRef, () => emit('clickOutside'))
36
46
  </script>
37
47
 
38
48
  <template>
@@ -2,7 +2,14 @@
2
2
  border-radius: var(--border-radius);
3
3
  box-shadow: var(--box-shadow);
4
4
  min-width: 80px;
5
- background-color: var(--color-bg-raised);
5
+ background-color: var(--color-bg-medium);
6
6
  border-radius: var(--border-radius-m);
7
7
  z-index: 1000;
8
8
  }
9
+
10
+ :root.light {
11
+ .vui-popout {
12
+ background-color: var(--color-bg);
13
+ box-shadow: var(--box-shadow-strong);
14
+ }
15
+ }