@dolanske/vui 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +27 -96
  2. package/dist/components/Accordion/Accordion.vue.d.ts +1 -0
  3. package/dist/components/Avatar/Avatar.vue.d.ts +4 -2
  4. package/dist/components/Divider/Divider.vue.d.ts +2 -4
  5. package/dist/components/Dropdown/Dropdown.vue.d.ts +105 -0
  6. package/dist/components/Input/Dropzone.vue.d.ts +1 -0
  7. package/dist/components/Input/Input.vue.d.ts +1 -0
  8. package/dist/components/OTP/OTP.vue.d.ts +43 -0
  9. package/dist/components/OTP/OTPItem.vue.d.ts +5 -0
  10. package/dist/components/Popout/Popout.vue.d.ts +3 -3
  11. package/dist/components/Radio/Radio.vue.d.ts +1 -1
  12. package/dist/components/Radio/RadioGroup.vue.d.ts +3 -12
  13. package/dist/components/Tooltip/Tooltip.vue.d.ts +1 -1
  14. package/dist/index.d.ts +3 -1
  15. package/dist/shared/helpers.d.ts +8 -1
  16. package/dist/shared/types.d.ts +3 -0
  17. package/dist/style.css +1 -1
  18. package/dist/vui.js +4752 -4542
  19. package/package.json +1 -1
  20. package/src/App.vue +8 -26
  21. package/src/components/Accordion/Accordion.vue +17 -3
  22. package/src/components/Accordion/accordion.scss +38 -2
  23. package/src/components/Avatar/Avatar.vue +25 -4
  24. package/src/components/Avatar/avatar.scss +5 -5
  25. package/src/components/Button/Button.vue +4 -4
  26. package/src/components/Calendar/Calendar.vue +10 -8
  27. package/src/components/Card/Card.vue +2 -2
  28. package/src/components/Checkbox/Checkbox.vue +4 -1
  29. package/src/components/Checkbox/checkbox.scss +12 -6
  30. package/src/components/Divider/Divider.vue +22 -12
  31. package/src/components/Drawer/Drawer.vue +6 -8
  32. package/src/components/Drawer/drawer.scss +0 -13
  33. package/src/components/Dropdown/Dropdown.vue +13 -8
  34. package/src/components/Input/Input.vue +4 -1
  35. package/src/components/Input/Textarea.vue +11 -6
  36. package/src/components/Input/input.scss +13 -4
  37. package/src/components/OTP/OTP.vue +133 -0
  38. package/src/components/OTP/OTPItem.vue +37 -0
  39. package/src/components/OTP/otp.scss +84 -0
  40. package/src/components/Popout/Popout.vue +3 -3
  41. package/src/components/Progress/Progress.vue +19 -11
  42. package/src/components/Progress/progress.scss +1 -1
  43. package/src/components/Radio/Radio.vue +1 -1
  44. package/src/components/Radio/RadioGroup.vue +10 -5
  45. package/src/components/Sheet/Sheet.vue +16 -15
  46. package/src/components/Sheet/sheet.scss +4 -0
  47. package/src/components/Skeleton/Skeleton.vue +19 -20
  48. package/src/components/Spinner/Spinner.vue +5 -5
  49. package/src/components/Table/table.ts +2 -1
  50. package/src/components/Tooltip/Tooltip.vue +1 -1
  51. package/src/index.ts +4 -0
  52. package/src/shared/helpers.ts +22 -1
  53. package/src/shared/types.ts +6 -0
  54. package/src/style/core.scss +4 -1
  55. package/src/style/layout.scss +4 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dolanske/vui",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.2.0",
5
5
  "private": false,
6
6
  "description": "Brother in Christ there's a new UI library ",
7
7
  "author": "dolanske",
package/src/App.vue CHANGED
@@ -1,19 +1,16 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
- import Accordion from './components/Accordion/Accordion.vue'
4
- import Button from './components/Button/Button.vue'
5
- import Flex from './components/Flex/Flex.vue'
6
- import Input from './components/Input/Input.vue'
3
+ import Avatar from './components/Avatar/Avatar.vue'
4
+ import Divider from './components/Divider/Divider.vue'
7
5
  import Tab from './components/Tabs/Tab.vue'
8
6
  import Tabs from './components/Tabs/Tabs.vue'
9
7
 
10
8
  const tab = ref('components')
11
- const value = ref('')
12
9
  </script>
13
10
 
14
11
  <template>
15
12
  <main vaul-drawer-wrapper>
16
- <Tabs v-model="tab" expand variant="filled">
13
+ <Tabs v-model="tab" expand>
17
14
  <Tab id="home" label="Home" icon="ph:house" />
18
15
  <Tab id="components" label="Components" />
19
16
  <Tab id="typography" label="Typography" />
@@ -22,28 +19,13 @@ const value = ref('')
22
19
  <div v-if="tab === 'home'">
23
20
  home
24
21
  </div>
25
- <div v-if="tab === 'components'">
26
- <Flex>
27
- <Button variant="success">
28
- Hello
29
- </Button>
30
- <Button variant="success" plain>
31
- Hello
32
- </Button>
33
- <Button variant="success" active>
34
- Hello
35
- </Button>
36
-
37
- {{ value }}
38
22
 
39
- <Button variant="success" disabled>
40
- Hello
41
- </Button>
42
- </Flex>
23
+ <div v-if="tab === 'components'">
24
+ <Divider size="65px" :margin="32">
25
+ <Avatar />
26
+ </Divider>
43
27
 
44
- <Accordion label="Hi">
45
- <Input v-model="value" />
46
- </Accordion>
28
+ <br>
47
29
  </div>
48
30
  <div v-else-if="tab === 'typography'" class="typeset" :style="{ maxWidth: '688px', margin: 'auto' }">
49
31
  <h1>The Joke Tax Chronicles</h1>
@@ -1,11 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import { Icon } from '@iconify/vue'
3
+ import { useResizeObserver } from '@vueuse/core'
3
4
  import { ref, useTemplateRef, watch, watchEffect } from 'vue'
4
5
  import './accordion.scss'
5
6
 
6
7
  export interface AccordionProps {
7
8
  open?: boolean
8
9
  label?: string
10
+ card?: boolean
9
11
  }
10
12
 
11
13
  const props = defineProps<AccordionProps>()
@@ -55,10 +57,16 @@ defineExpose({
55
57
  toggle,
56
58
  isOpen,
57
59
  })
60
+
61
+ useResizeObserver(contentRef, ([entry]) => {
62
+ if (isOpen.value && contentMaxHeight.value !== entry.contentRect.height) {
63
+ contentMaxHeight.value = entry.contentRect.height || 0
64
+ }
65
+ })
58
66
  </script>
59
67
 
60
68
  <template>
61
- <div class="vui-accordion" :class="{ open: isOpen }">
69
+ <div class="vui-accordion" :class="{ 'open': isOpen, 'is-card': !!props.card }">
62
70
  <!-- Completely custom header which needs to be styled and implemented by the developer -->
63
71
  <slot v-if="$slots.trigger" name="trigger" :open :close :toggle :is-open />
64
72
  <button v-else class="vui-accordion-header" @click="isOpen = !isOpen">
@@ -68,8 +76,14 @@ defineExpose({
68
76
  <Icon icon="ph:caret-down" />
69
77
  </button>
70
78
 
71
- <div ref="content" class="vui-accordion-content" :style="{ 'max-height': isOpen ? `${contentMaxHeight}px` : '0px' }">
72
- <slot />
79
+ <div
80
+ class="vui-accordion-content"
81
+ :aria-hidden="!isOpen"
82
+ :style="{ 'max-height': isOpen ? `${contentMaxHeight}px` : '0px' }"
83
+ >
84
+ <div ref="content" class="vui-accordtion-content-inner">
85
+ <slot />
86
+ </div>
73
87
  </div>
74
88
  </div>
75
89
  </template>
@@ -4,12 +4,49 @@
4
4
  border-bottom: 1px solid var(--color-border);
5
5
  padding-bottom: 0;
6
6
 
7
+ &.is-card {
8
+ border: 1px solid var(--color-border);
9
+ border-radius: var(--border-radius-m);
10
+
11
+ &.open {
12
+ padding-bottom: 0;
13
+
14
+ .vui-accordion-header {
15
+ border-block-width: 1px;
16
+ border-bottom-left-radius: 0;
17
+ border-bottom-right-radius: 0;
18
+ }
19
+ }
20
+
21
+ .vui-accordion-header {
22
+ padding-inline: var(--space-m);
23
+ border-bottom: 0px solid var(--color-border);
24
+ text-decoration: inherit;
25
+ border-radius: var(--border-radius-m);
26
+
27
+ &:hover {
28
+ text-decoration: inherit;
29
+ text-underline-offset: inherit;
30
+
31
+ background-color: var(--color-button-gray);
32
+ }
33
+ }
34
+
35
+ .vui-accordtion-content-inner {
36
+ padding: var(--space-m);
37
+ }
38
+ }
39
+
7
40
  &.open {
8
41
  padding-bottom: var(--space-m);
9
42
 
10
43
  .vui-accordion-header svg {
11
44
  transform: rotate(180deg);
12
45
  }
46
+
47
+ .vui-accordion-content {
48
+ visibility: visible;
49
+ }
13
50
  }
14
51
 
15
52
  .vui-accordion-header {
@@ -31,8 +68,6 @@
31
68
  svg {
32
69
  transition: var(--transition);
33
70
  }
34
-
35
- // padding-bottom: var(--w);
36
71
  }
37
72
 
38
73
  .vui-accordion-content {
@@ -40,5 +75,6 @@
40
75
  width: 100%;
41
76
  max-height: 0;
42
77
  overflow: hidden;
78
+ visibility: hidden;
43
79
  }
44
80
  }
@@ -1,29 +1,50 @@
1
1
  <script setup lang="ts">
2
2
  import type { Sizes } from '../../shared/types'
3
3
  import { Icon } from '@iconify/vue'
4
- import { ref } from 'vue'
4
+ import { useCssVar } from '@vueuse/core'
5
+ import { ref, useTemplateRef, watch } from 'vue'
6
+ import { Size } from '../../shared/types'
5
7
  import './avatar.scss'
6
8
 
7
9
  interface Props {
8
- size?: Sizes
10
+ size?: Sizes | number
9
11
  url?: string
10
12
  fallback?: string
11
13
  icon?: string
12
14
  }
13
15
 
14
16
  const {
15
- size = 'm',
17
+ size = Size.m,
16
18
  url,
17
19
  fallback,
18
20
  } = defineProps<Props>()
19
21
 
20
22
  const showFallback = ref(false)
23
+
24
+ // For some reason CSS variable assignemnt in scoped <style> is broken, so we
25
+ // have to go this way instead.
26
+ const avatarRef = useTemplateRef('avatar')
27
+ const avatarSize = useCssVar('--avatar-size', avatarRef)
28
+ watch(() => size, (val) => {
29
+ avatarSize.value = (() => {
30
+ if (typeof val == 'number') {
31
+ return `${val}px`
32
+ }
33
+ switch (size) {
34
+ case Size.s: return '28px'
35
+ case Size.l: return '48px'
36
+ case Size.m:
37
+ default: return '36px'
38
+ }
39
+ })()
40
+ })
21
41
  </script>
22
42
 
23
43
  <template>
24
44
  <div
45
+ ref="avatar"
25
46
  class="vui-avatar"
26
- :class="[`vui-avatar-size-${size}`]"
47
+ :class="[`vui-avatar-size-${typeof size === 'number' ? 'm' : size}`]"
27
48
  >
28
49
  <img v-if="url && !showFallback" :src="url" @error="showFallback = true">
29
50
  <strong v-else>
@@ -1,8 +1,8 @@
1
1
  .vui-avatar {
2
- --button-size: 36px;
2
+ --avatar-size: 36px;
3
3
 
4
4
  &.vui-avatar-size-s {
5
- --button-size: 28px;
5
+ // --avatar-size: 28px;
6
6
 
7
7
  strong {
8
8
  font-size: var(--font-size-xs);
@@ -10,15 +10,15 @@
10
10
  }
11
11
 
12
12
  &.vui-avatar-size-l {
13
- --button-size: 48px;
13
+ // --avatar-size: 48px;
14
14
 
15
15
  strong {
16
16
  font-size: var(--font-size-m);
17
17
  }
18
18
  }
19
19
 
20
- width: var(--button-size);
21
- height: var(--button-size);
20
+ width: var(--avatar-size);
21
+ height: var(--avatar-size);
22
22
  border-radius: 100%;
23
23
  display: flex;
24
24
  align-items: center;
@@ -43,7 +43,7 @@ const {
43
43
  dashed,
44
44
  } = defineProps<Props>()
45
45
 
46
- const actualHeight = computed(() => {
46
+ const h = computed(() => {
47
47
  switch (size) {
48
48
  case Size.s: return '24px'
49
49
  case Size.l: return '40px'
@@ -52,7 +52,7 @@ const actualHeight = computed(() => {
52
52
  }
53
53
  })
54
54
 
55
- const actualPadding = computed(() => {
55
+ const p = computed(() => {
56
56
  switch (size) {
57
57
  case Size.s: return '5px'
58
58
  case Size.l: return '16px'
@@ -84,7 +84,7 @@ const actualPadding = computed(() => {
84
84
 
85
85
  <style scoped>
86
86
  .vui-button {
87
- --button-height: v-bind(actualHeight);
88
- --button-padding: v-bind(actualPadding);
87
+ --button-height: v-bind(h);
88
+ --button-padding: v-bind(p);
89
89
  }
90
90
  </style>
@@ -14,6 +14,8 @@ const props = withDefaults(defineProps<VueDatePickerProps & {
14
14
  format: 'dd/MM/yyyy HH:mm',
15
15
  expand: false,
16
16
  })
17
+
18
+ const ICON_SIZE = 18
17
19
  </script>
18
20
 
19
21
  <template>
@@ -26,28 +28,28 @@ const props = withDefaults(defineProps<VueDatePickerProps & {
26
28
  >
27
29
  <!-- Icon slots -->
28
30
  <template #input-icon>
29
- <Icon :width="18" :height="18" icon="ph:calendar-blank" />
31
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:calendar-blank" />
30
32
  </template>
31
33
  <template #calendar-icon>
32
- <Icon :width="18" :height="18" icon="ph:calendar-blank" />
34
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:calendar-blank" />
33
35
  </template>
34
36
  <template #clear-icon>
35
- <Icon :width="18" :height="18" icon="ph:x" />
37
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:x" />
36
38
  </template>
37
39
  <template #clock-icon>
38
- <Icon :width="18" :height="18" icon="ph:clock" />
40
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:clock" />
39
41
  </template>
40
42
  <template #arrow-left>
41
- <Icon :width="18" :height="18" icon="ph:caret-left" />
43
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:caret-left" />
42
44
  </template>
43
45
  <template #arrow-right>
44
- <Icon :width="18" :height="18" icon="ph:caret-right" />
46
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:caret-right" />
45
47
  </template>
46
48
  <template #arrow-up>
47
- <Icon :width="18" :height="18" icon="ph:caret-up" />
49
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:caret-up" />
48
50
  </template>
49
51
  <template #arrow-down>
50
- <Icon :width="18" :height="18" icon="ph:caret-down" />
52
+ <Icon :width="ICON_SIZE" :height="ICON_SIZE" icon="ph:caret-down" />
51
53
  </template>
52
54
 
53
55
  <!-- Content slots -->
@@ -33,13 +33,13 @@ const {
33
33
  <slot name="header-end" />
34
34
  </div>
35
35
 
36
- <Divider v-if="(separators || headerSeparator) && ($slots.header || $slots['header-end'])" :size="1" />
36
+ <Divider v-if="(separators || headerSeparator) && ($slots.header || $slots['header-end'])" :space="1" />
37
37
 
38
38
  <div v-if="$slots.default" class="vui-card-content">
39
39
  <slot />
40
40
  </div>
41
41
 
42
- <Divider v-if="(separators || footerSeparator) && $slots.footer" :size="1" />
42
+ <Divider v-if="(separators || footerSeparator) && $slots.footer" :space="1" />
43
43
 
44
44
  <div v-if="$slots.footer" class="vui-card-footer">
45
45
  <slot name="footer" />
@@ -34,7 +34,10 @@ const id = useId()
34
34
  type="checkbox"
35
35
  :disabled
36
36
  :checked="checkedProp"
37
- @change="emit('change', ($event.target as HTMLInputElement).checked)"
37
+ @change="(e) => {
38
+ if (disabled) return
39
+ emit('change', (e.target as HTMLInputElement).checked)
40
+ }"
38
41
  >
39
42
  <label :for="id">
40
43
  <span class="vui-checkbox-icon">
@@ -9,19 +9,24 @@
9
9
 
10
10
  &.disabled {
11
11
  cursor: not-allowed;
12
- pointer-events: none;
13
12
 
14
- .vui-checkbox-icon svg path {
15
- color: var(--color-text-lighter);
13
+ .vui-checkbox-icon {
14
+ pointer-events: none;
15
+ svg path {
16
+ color: var(--color-text-lighter);
17
+ }
16
18
  }
17
19
 
18
- input + label p {
19
- color: var(--color-text-lighter);
20
+ input + label {
21
+ cursor: not-allowed;
22
+
23
+ p {
24
+ color: var(--color-text-lighter);
25
+ }
20
26
  }
21
27
  }
22
28
 
23
29
  .vui-checkbox-icon {
24
- cursor: pointer;
25
30
  width: var(--checkbox-size);
26
31
  height: var(--checkbox-size);
27
32
 
@@ -52,6 +57,7 @@
52
57
  align-items: center;
53
58
  min-height: var(--checkbox-size);
54
59
  font-size: var(--font-size-ms);
60
+ align-self: flex-start;
55
61
  // line-height: var(--checkbox-size);
56
62
  }
57
63
  }
@@ -1,13 +1,13 @@
1
1
  <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { formatUnitValue } from '../../shared/helpers'
2
4
  import './divider.scss'
3
5
 
4
6
  interface Props {
5
7
  thickness?: number
6
- size?: number
8
+ size?: number | string
7
9
  vertical?: boolean
8
- width?: number
9
- height?: number
10
- margin?: string
10
+ margin?: string | number
11
11
  }
12
12
 
13
13
  const {
@@ -16,19 +16,29 @@ const {
16
16
  vertical,
17
17
  margin = '0',
18
18
  } = defineProps<Props>()
19
+
20
+ const h = computed(() => formatUnitValue(size))
21
+ const w = computed(() => vertical ? h.value : 'initial')
22
+ const bW = computed(() => `${thickness}px`)
23
+ const m = computed(() => formatUnitValue(margin))
19
24
  </script>
20
25
 
21
26
  <template>
22
- <div
23
- class="vui-divider" :class="{ vertical }" :style="{
24
- ...(vertical && { width: `${size}px` }),
25
- height: `${size}px`,
26
- borderWidth: `${thickness}px`,
27
- margin,
28
- }"
29
- >
27
+ <div class="vui-divider" :class="{ vertical }">
30
28
  <div v-if="$slots.default" class="vui-divider-slot">
31
29
  <slot />
32
30
  </div>
33
31
  </div>
34
32
  </template>
33
+
34
+ <style lang="scss" scoped>
35
+ .vui-divider {
36
+ margin: v-bind(m);
37
+ width: v-bind(w);
38
+ height: v-bind(h);
39
+
40
+ &:before {
41
+ border-width: v-bind(bW);
42
+ }
43
+ }
44
+ </style>
@@ -40,15 +40,17 @@ const {
40
40
  portalProps,
41
41
  handle = true,
42
42
  } = defineProps<Props>()
43
+
43
44
  const open = defineModel<boolean>()
44
45
 
45
- const containerMaxWidth = computed(() => {
46
+ const mW = computed(() => {
46
47
  if (typeof containerSize === 'string') {
47
48
  if (containerClass === 'full') {
48
49
  return '100%'
49
50
  }
50
51
  else {
51
- return `var(--container-${containerSize})`
52
+ return getComputedStyle(document.documentElement)
53
+ .getPropertyValue(`--container-${containerSize}`)
52
54
  }
53
55
  }
54
56
  else {
@@ -69,12 +71,8 @@ const id = useId()
69
71
  >
70
72
  <DrawerPortal v-bind="portalProps">
71
73
  <DrawerOverlay class="vui-drawer-overlay" />
72
- <DrawerContent class="vui-drawer-content" :class="{ 'hide-handlk': handle === false }" :aria-describedby="id">
73
- <div
74
- class="vui-drawer-container container" :class="containerClass" :style="{
75
- maxWidth: containerMaxWidth,
76
- }"
77
- >
74
+ <DrawerContent class="vui-drawer-content" :class="{ 'hide-handle': handle === false }" :aria-describedby="id">
75
+ <div :key="mW" class="vui-drawer-container container" :class="containerClass" :style="{ 'max-width': mW }">
78
76
  <DrawerTitle class="visually-hidden" :name="id">
79
77
  {{ title }}
80
78
  </DrawerTitle>
@@ -33,17 +33,4 @@
33
33
  background-color: var(--color-border-strong);
34
34
  transition: var(--transition-quick);
35
35
  }
36
-
37
- // .vui-drawer-container {
38
- // width: 100%;
39
- // max-width: 756px;
40
- // margin-inline: auto;
41
- // }
42
- }
43
-
44
- .vui-drawer-overlay {
45
- // opacity: 0.4;
46
- // position: fixed;
47
- // inset: 0;
48
- // background-color: var(--color-bg-lowered);
49
36
  }
@@ -1,12 +1,13 @@
1
1
  <script setup lang='ts'>
2
- import type { Placement } from '@floating-ui/vue'
3
2
  import type { MaybeElement } from '@vueuse/core'
3
+ import type { Placement } from '../../shared/types'
4
4
  import { onClickOutside } from '@vueuse/core'
5
5
  import { computed, ref, useTemplateRef } from 'vue'
6
+ import { formatUnitValue } from '../../shared/helpers'
6
7
  import Popout from '../Popout/Popout.vue'
7
8
  import './dropdown.scss'
8
9
 
9
- interface Props {
10
+ export interface Props {
10
11
  /**
11
12
  * Tooltip placement related to the anchor
12
13
  */
@@ -24,7 +25,7 @@ interface Props {
24
25
  const {
25
26
  placement = 'bottom-start',
26
27
  expand,
27
- minWidth,
28
+ minWidth = 156,
28
29
  } = defineProps<Props>()
29
30
 
30
31
  const anchorRef = useTemplateRef<HTMLDivElement>('anchor')
@@ -63,6 +64,9 @@ defineExpose({
63
64
  toggle,
64
65
  isOpen: showMenu,
65
66
  })
67
+
68
+ const mW = computed(() => formatUnitValue(minWidth))
69
+ const w = computed(() => expand ? `${anchorWidth.value}px` : 'initial')
66
70
  </script>
67
71
 
68
72
  <template>
@@ -77,17 +81,18 @@ defineExpose({
77
81
  :anchor="anchorRef"
78
82
  class="vui-dropdown"
79
83
  :placement
80
- :style="{
81
- minWidth: `${minWidth ?? 156}px`,
82
- ...(expand && { width: `${anchorWidth}px` }),
83
- }"
84
84
  >
85
85
  <slot :open :close :toggle :is-open="showMenu" />
86
86
  </Popout>
87
87
  </Transition>
88
88
  </template>
89
89
 
90
- <style scoped>
90
+ <style scoped lang="scss">
91
+ .vui-dropdown {
92
+ min-width: v-bind(mW);
93
+ width: v-bind(w);
94
+ }
95
+
91
96
  .dropdown-enter-active,
92
97
  .dropdown-leave-active {
93
98
  transition: 0.1s opacity ease-in-out;
@@ -23,6 +23,7 @@ export interface InputProps {
23
23
  multiple?: boolean
24
24
  min?: number
25
25
  max?: number
26
+ disabled?: boolean
26
27
  }
27
28
 
28
29
  const {
@@ -40,6 +41,7 @@ const {
40
41
  min,
41
42
  max,
42
43
  errors = [] as string[],
44
+ disabled,
43
45
  } = defineProps<InputProps>()
44
46
 
45
47
  const model = defineModel<string | number>({
@@ -76,7 +78,7 @@ const renderLimit = computed(() => {
76
78
  </script>
77
79
 
78
80
  <template>
79
- <div class="vui-input-container" :class="{ expand, required, readonly, 'has-errors': errors.length > 0 }">
81
+ <div class="vui-input-container" :class="{ expand, disabled, required, readonly, 'has-errors': errors.length > 0 }">
80
82
  <slot name="before" />
81
83
  <div class="vui-input">
82
84
  <label v-if="label" for="id">{{ label }}</label>
@@ -100,6 +102,7 @@ const renderLimit = computed(() => {
100
102
  :accept
101
103
  :multiple
102
104
  :min
105
+ :disabled
103
106
  >
104
107
  <slot name="end" />
105
108
  </Flex>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { InputProps } from './Input.vue'
3
- import { useId } from 'vue'
3
+ import { computed, useId } from 'vue'
4
4
  import '../Input/input.scss'
5
5
 
6
6
  type Props = Omit<InputProps, 'type'> & {
@@ -35,6 +35,9 @@ const model = defineModel<string>({
35
35
  },
36
36
  })
37
37
  const id = useId()
38
+
39
+ const r = computed(() => resize === true ? 'both' : (resize || 'initial'))
40
+ const fS = computed(() => autoResize ? 'content' : 'auto')
38
41
  </script>
39
42
 
40
43
  <template>
@@ -53,11 +56,6 @@ const id = useId()
53
56
  :placeholder
54
57
  :required
55
58
  :max="limit"
56
- :style="{
57
- 'resize': resize === true ? 'both' : (resize || 'initial'),
58
- // @ts-expect-error This is only supported in chrome for now
59
- 'field-sizing': autoResize ? 'content' : 'auto',
60
- }"
61
59
  />
62
60
  </div>
63
61
  <p v-if="limit" class="vui-input-limit">
@@ -71,3 +69,10 @@ const id = useId()
71
69
  <slot name="after" />
72
70
  </div>
73
71
  </template>
72
+
73
+ <style scoped lang="scss">
74
+ .vui-input-container .vui-input textarea {
75
+ resize: v-bind(r);
76
+ field-sizing: v-bind(fS);
77
+ }
78
+ </style>
@@ -17,6 +17,11 @@
17
17
 
18
18
  width: 224px;
19
19
 
20
+ &.disabled input,
21
+ &.disabled textarea {
22
+ cursor: not-allowed;
23
+ }
24
+
20
25
  &.expand {
21
26
  width: 100%;
22
27
  }
@@ -26,10 +31,14 @@
26
31
  color: var(--input-color-text-red);
27
32
  }
28
33
 
29
- &.readonly .vui-input input {
30
- pointer-events: none;
31
- color: var(--input-color-text-light);
32
- border-color: var(--input-color-border-weak);
34
+ &.readonly .vui-input {
35
+ input,
36
+ textarea,
37
+ .vui-input-style {
38
+ pointer-events: none;
39
+ color: var(--input-color-text-light);
40
+ border-color: var(--input-color-border-weak);
41
+ }
33
42
  }
34
43
 
35
44
  &.has-errors {