@indielayer/ui 1.0.0-alpha.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +6 -3
  2. package/lib/index.cjs.js +1 -15
  3. package/lib/index.es.js +4453 -3651
  4. package/lib/nuxt.js +2 -1
  5. package/package.json +16 -6
  6. package/src/common/icons.ts +15 -0
  7. package/src/common/utils.ts +68 -0
  8. package/src/components/alert/Alert.theme.ts +57 -0
  9. package/src/components/alert/Alert.vue +51 -127
  10. package/src/components/alert/__tests__/Alert.spec.ts +14 -0
  11. package/src/components/avatar/Avatar.theme.ts +39 -0
  12. package/src/components/avatar/Avatar.vue +58 -96
  13. package/src/components/avatar/__tests__/Avatar.spec.ts +11 -0
  14. package/src/components/badge/Badge.theme.ts +13 -0
  15. package/src/components/badge/Badge.vue +58 -65
  16. package/src/components/badge/__tests__/Badge.spec.ts +11 -0
  17. package/src/components/breadcrumbs/Breadcrumbs.theme.ts +9 -0
  18. package/src/components/breadcrumbs/Breadcrumbs.vue +34 -24
  19. package/src/components/breadcrumbs/__tests__/Breadcrumbs.spec.ts +11 -0
  20. package/src/components/button/Button.theme.ts +234 -0
  21. package/src/components/button/Button.vue +94 -356
  22. package/src/components/button/ButtonGroup.theme.ts +5 -0
  23. package/src/components/button/ButtonGroup.vue +30 -29
  24. package/src/components/button/__tests__/ Button.spec.ts +11 -0
  25. package/src/components/button/__tests__/ ButtonGroup.spec.ts +11 -0
  26. package/src/components/card/Card.theme.ts +7 -0
  27. package/src/components/card/Card.vue +18 -11
  28. package/src/components/card/__tests__/Card.spec.ts +11 -0
  29. package/src/components/checkbox/Checkbox.theme.ts +92 -0
  30. package/src/components/checkbox/Checkbox.vue +69 -156
  31. package/src/components/checkbox/__tests__/Checkbox.spec.ts +11 -0
  32. package/src/components/collapse/Collapse.theme.ts +11 -0
  33. package/src/components/collapse/Collapse.vue +99 -118
  34. package/src/components/collapse/__tests__/Collapse.spec.ts +11 -0
  35. package/src/components/container/Container.theme.ts +7 -0
  36. package/src/components/container/Container.vue +17 -9
  37. package/src/components/container/__tests__/Container.spec.ts +11 -0
  38. package/src/components/divider/Divider.theme.ts +11 -0
  39. package/src/components/divider/Divider.vue +22 -18
  40. package/src/components/divider/__tests__/Divider.spec.ts +11 -0
  41. package/src/components/drawer/Drawer.theme.ts +9 -0
  42. package/src/components/drawer/Drawer.vue +160 -177
  43. package/src/components/drawer/__tests__/Drawer.spec.ts +11 -0
  44. package/src/components/form/Form.theme.ts +7 -0
  45. package/src/components/form/Form.vue +90 -73
  46. package/src/components/form/__tests__/Form.spec.ts +11 -0
  47. package/src/components/helpers/InputError.tsx +14 -0
  48. package/src/components/icon/Icon.theme.ts +16 -0
  49. package/src/components/icon/Icon.vue +72 -88
  50. package/src/components/icon/__tests__/Icon.spec.ts +11 -0
  51. package/src/components/image/Image.theme.ts +7 -0
  52. package/src/components/image/Image.vue +22 -23
  53. package/src/components/image/__tests__/Image.spec.ts +11 -0
  54. package/src/components/index.ts +3 -3
  55. package/src/components/input/Input.theme.ts +44 -0
  56. package/src/components/input/Input.vue +97 -130
  57. package/src/components/input/__tests__/Input.spec.ts +11 -0
  58. package/src/components/link/Link.theme.ts +26 -0
  59. package/src/components/link/Link.vue +41 -66
  60. package/src/components/link/__tests__/Link.spec.ts +11 -0
  61. package/src/components/menu/Menu.theme.ts +7 -0
  62. package/src/components/menu/Menu.vue +54 -45
  63. package/src/components/menu/MenuItem.theme.ts +107 -0
  64. package/src/components/menu/MenuItem.vue +97 -199
  65. package/src/components/menu/__tests__/Menu.spec.ts +11 -0
  66. package/src/components/menu/__tests__/MenuItem.spec.ts +11 -0
  67. package/src/components/modal/Modal.theme.ts +29 -0
  68. package/src/components/modal/Modal.vue +78 -101
  69. package/src/components/modal/__tests__/Modal.spec.ts +11 -0
  70. package/src/components/notifications/Notifications.theme.ts +11 -0
  71. package/src/components/notifications/Notifications.vue +233 -247
  72. package/src/components/notifications/__tests__/Notifications.spec.ts +11 -0
  73. package/src/components/pagination/Pagination.theme.ts +27 -0
  74. package/src/components/pagination/Pagination.vue +142 -164
  75. package/src/components/pagination/PaginationItem.theme.ts +14 -0
  76. package/src/components/pagination/PaginationItem.vue +26 -33
  77. package/src/components/pagination/__tests__/Pagination.spec.ts +11 -0
  78. package/src/components/pagination/__tests__/PaginationItem.spec.ts +11 -0
  79. package/src/components/popover/Popover.theme.ts +9 -0
  80. package/src/components/popover/Popover.vue +153 -101
  81. package/src/components/popover/PopoverContainer.theme.ts +7 -0
  82. package/src/components/popover/PopoverContainer.vue +17 -9
  83. package/src/components/popover/__tests__/Popover.spec.ts +11 -0
  84. package/src/components/popover/__tests__/PopoverContainer.spec.ts +11 -0
  85. package/src/components/progress/Progress.theme.ts +26 -0
  86. package/src/components/progress/Progress.vue +29 -53
  87. package/src/components/progress/__tests__/Progress.spec.ts +11 -0
  88. package/src/components/radio/Radio.theme.ts +121 -0
  89. package/src/components/radio/Radio.vue +81 -158
  90. package/src/components/radio/__tests__/Radio.spec.ts +11 -0
  91. package/src/components/scroll/Scroll.theme.ts +7 -0
  92. package/src/components/scroll/Scroll.vue +34 -36
  93. package/src/components/scroll/__tests__/Scroll.spec.ts +11 -0
  94. package/src/components/select/Select.theme.ts +54 -0
  95. package/src/components/select/Select.vue +219 -273
  96. package/src/components/select/__tests__/Select.spec.ts +11 -0
  97. package/src/components/skeleton/Skeleton.theme.ts +7 -0
  98. package/src/components/skeleton/Skeleton.vue +17 -9
  99. package/src/components/skeleton/__tests__/Skeleton.spec.ts +11 -0
  100. package/src/components/slider/Slider.theme.ts +30 -0
  101. package/src/components/slider/Slider.vue +135 -168
  102. package/src/components/slider/__tests__/Slider.spec.ts +11 -0
  103. package/src/components/spacer/{Spacer.vue → Spacer.tsx} +3 -6
  104. package/src/components/spacer/__tests__/Spacer.spec.ts +11 -0
  105. package/src/components/spinner/Spinner.vue +10 -34
  106. package/src/components/spinner/__tests__/Spinner.spec.ts +11 -0
  107. package/src/components/tab/Tab.theme.ts +22 -0
  108. package/src/components/tab/Tab.vue +89 -93
  109. package/src/components/tab/TabGroup.theme.ts +43 -0
  110. package/src/components/tab/TabGroup.vue +94 -127
  111. package/src/components/tab/__tests__/Tab.spec.ts +11 -0
  112. package/src/components/tab/__tests__/TabGroup.spec.ts +11 -0
  113. package/src/components/table/Table.theme.ts +19 -0
  114. package/src/components/table/Table.vue +136 -147
  115. package/src/components/table/{TableBody.vue → TableBody.tsx} +3 -8
  116. package/src/components/table/TableCell.theme.ts +27 -0
  117. package/src/components/table/TableCell.vue +30 -58
  118. package/src/components/table/TableHead.tsx +14 -0
  119. package/src/components/table/TableHeader.vue +18 -20
  120. package/src/components/table/TableRow.vue +23 -20
  121. package/src/components/table/__tests__/Table.spec.ts +11 -0
  122. package/src/components/tag/Tag.theme.ts +32 -0
  123. package/src/components/tag/Tag.vue +40 -68
  124. package/src/components/tag/__tests__/Tag.spec.ts +11 -0
  125. package/src/components/textarea/Textarea.theme.ts +62 -0
  126. package/src/components/textarea/Textarea.vue +100 -115
  127. package/src/components/textarea/__tests__/Textarea.spec.ts +11 -0
  128. package/src/components/toggle/Toggle.theme.ts +51 -0
  129. package/src/components/toggle/Toggle.vue +51 -81
  130. package/src/components/toggle/__tests__/Toggle.spec.ts +11 -0
  131. package/src/components/tooltip/Tooltip.theme.ts +51 -0
  132. package/src/components/tooltip/Tooltip.vue +9 -14
  133. package/src/components/tooltip/__tests__/Tooltip.spec.ts +11 -0
  134. package/src/composables/colors-utils.ts +68 -68
  135. package/src/composables/colors.ts +18 -6
  136. package/src/composables/common.ts +1 -0
  137. package/src/composables/css.ts +7 -2
  138. package/src/composables/index.ts +1 -1
  139. package/src/composables/inputtable.ts +1 -1
  140. package/src/composables/interactive.ts +8 -4
  141. package/src/composables/keys.ts +1 -0
  142. package/src/composables/notifications.ts +10 -0
  143. package/src/composables/theme.ts +88 -0
  144. package/src/create.ts +9 -4
  145. package/src/exports/nuxt.js +2 -1
  146. package/src/version.ts +1 -1
  147. package/volar.d.ts +1 -0
  148. package/lib/components/alert/Alert.vue.d.ts +0 -42
  149. package/lib/components/avatar/Avatar.vue.d.ts +0 -49
  150. package/lib/components/badge/Badge.vue.d.ts +0 -75
  151. package/lib/components/breadcrumbs/Breadcrumbs.vue.d.ts +0 -30
  152. package/lib/components/button/Button.vue.d.ts +0 -87
  153. package/lib/components/button/ButtonGroup.vue.d.ts +0 -49
  154. package/lib/components/card/Card.vue.d.ts +0 -17
  155. package/lib/components/checkbox/Checkbox.vue.d.ts +0 -81
  156. package/lib/components/collapse/Collapse.vue.d.ts +0 -47
  157. package/lib/components/container/Container.vue.d.ts +0 -14
  158. package/lib/components/divider/Divider.vue.d.ts +0 -10
  159. package/lib/components/drawer/Drawer.vue.d.ts +0 -73
  160. package/lib/components/form/Form.vue.d.ts +0 -46
  161. package/lib/components/icon/Icon.vue.d.ts +0 -40
  162. package/lib/components/image/Image.vue.d.ts +0 -8
  163. package/lib/components/index.d.ts +0 -45
  164. package/lib/components/input/Input.vue.d.ts +0 -117
  165. package/lib/components/link/Link.vue.d.ts +0 -36
  166. package/lib/components/menu/Menu.vue.d.ts +0 -62
  167. package/lib/components/menu/MenuItem.vue.d.ts +0 -114
  168. package/lib/components/modal/Modal.vue.d.ts +0 -34
  169. package/lib/components/notifications/Notifications.vue.d.ts +0 -104
  170. package/lib/components/pagination/Pagination.vue.d.ts +0 -58
  171. package/lib/components/pagination/PaginationItem.vue.d.ts +0 -32
  172. package/lib/components/popover/Popover.vue.d.ts +0 -64
  173. package/lib/components/popover/PopoverContainer.vue.d.ts +0 -14
  174. package/lib/components/progress/Progress.vue.d.ts +0 -42
  175. package/lib/components/radio/Radio.vue.d.ts +0 -79
  176. package/lib/components/scroll/Scroll.vue.d.ts +0 -29
  177. package/lib/components/select/Select.vue.d.ts +0 -100
  178. package/lib/components/skeleton/Skeleton.vue.d.ts +0 -14
  179. package/lib/components/slider/Slider.vue.d.ts +0 -96
  180. package/lib/components/spacer/Spacer.vue.d.ts +0 -2
  181. package/lib/components/spinner/Spinner.vue.d.ts +0 -16
  182. package/lib/components/tab/Tab.vue.d.ts +0 -52
  183. package/lib/components/tab/TabGroup.vue.d.ts +0 -61
  184. package/lib/components/table/Table.vue.d.ts +0 -82
  185. package/lib/components/table/TableBody.vue.d.ts +0 -2
  186. package/lib/components/table/TableCell.vue.d.ts +0 -33
  187. package/lib/components/table/TableHead.vue.d.ts +0 -2
  188. package/lib/components/table/TableHeader.vue.d.ts +0 -33
  189. package/lib/components/table/TableRow.vue.d.ts +0 -23
  190. package/lib/components/tag/Tag.vue.d.ts +0 -45
  191. package/lib/components/textarea/Textarea.vue.d.ts +0 -106
  192. package/lib/components/toggle/Toggle.vue.d.ts +0 -79
  193. package/lib/components/tooltip/Tooltip.vue.d.ts +0 -2
  194. package/lib/composables/colors-utils.d.ts +0 -8
  195. package/lib/composables/colors.d.ts +0 -26
  196. package/lib/composables/common.d.ts +0 -14
  197. package/lib/composables/css.d.ts +0 -5
  198. package/lib/composables/index.d.ts +0 -7
  199. package/lib/composables/inputtable.d.ts +0 -37
  200. package/lib/composables/interactive.d.ts +0 -10
  201. package/lib/composables/keys.d.ts +0 -7
  202. package/lib/composables/notification.d.ts +0 -1
  203. package/lib/create.d.ts +0 -12
  204. package/lib/index.d.ts +0 -6
  205. package/lib/install.d.ts +0 -4
  206. package/lib/style.css +0 -1
  207. package/lib/version.d.ts +0 -2
  208. package/src/components/table/TableHead.vue +0 -15
  209. package/src/composables/notification.ts +0 -10
@@ -1,98 +1,70 @@
1
1
  <script lang="ts">
2
- import { computed, defineComponent } from 'vue'
3
- import { useCSS } from '../../composables/css'
2
+ export default { name: 'XTag' }
3
+ </script>
4
+
5
+ <script setup lang="ts">
6
+ import { computed } from 'vue'
4
7
  import { useColors } from '../../composables/colors'
5
8
  import { useCommon } from '../../composables/common'
9
+ import { useTheme } from '../../composables/theme'
10
+ import { closeIcon } from '../../common/icons'
6
11
 
7
- export default defineComponent({
8
- name: 'XTag',
9
-
10
- props: {
11
- ...useCommon.props(),
12
- ...useColors.props('gray'),
13
- tag: {
14
- type: String,
15
- default: 'span',
16
- },
17
- rounded: Boolean,
18
- removable: Boolean,
19
- outlined: Boolean,
20
- },
21
-
22
- emits: ['remove'],
12
+ import XIcon from '../icon/Icon.vue'
23
13
 
24
- setup(props) {
25
- const css = useCSS()
26
- const colors = useColors()
27
- const styles = computed(() => {
28
- const color = colors.getPalette(props.color)
14
+ import theme from './Tag.theme'
29
15
 
30
- return css.variables({
31
- bg: color[100],
32
- text: color[800],
33
- border: color[800],
34
- dark: {
35
- text: props.outlined ? color[200] : color[800],
36
- },
37
- })
38
- })
16
+ const props = defineProps({
17
+ ...useCommon.props(),
18
+ ...useColors.props('gray'),
19
+ tag: {
20
+ type: String,
21
+ default: 'span',
22
+ },
23
+ rounded: Boolean,
24
+ removable: Boolean,
25
+ outlined: Boolean,
26
+ })
39
27
 
40
- const sizeClasses = computed(() => {
41
- if (props.size === 'xs') return 'px-2 py-1 text-xs'
42
- else if (props.size === 'sm') return 'px-2 py-1 text-sm'
43
- else if (props.size === 'lg') return 'px-4 py-3 text-lg'
44
- else if (props.size === 'xl') return 'px-6 py-6 text-xl'
28
+ defineEmits(['remove'])
45
29
 
46
- return 'px-3 py-2'
47
- })
30
+ const closeIconSize = computed(() => {
31
+ if (props.size === 'xs') return 'xs'
32
+ else if (props.size === 'sm') return 'sm'
33
+ else if (props.size === 'lg') return 'md'
34
+ else if (props.size === 'xl') return 'lg'
48
35
 
49
- return {
50
- styles,
51
- sizeClasses,
52
- }
53
- },
36
+ return 'sm'
54
37
  })
38
+
39
+ const { styles, classes, className } = useTheme('tag', theme, props)
55
40
  </script>
56
41
 
57
42
  <template>
58
43
  <component
59
44
  :is="tag"
60
- class="inline-flex items-center leading-none whitespace-nowrap
61
- text-[color:var(--x-text)]
62
- dark:text-[color:var(--x-dark-text)]
63
- border-[color:var(--x-border)
64
- "
45
+ class="text-[color:var(--x-tag-text)] dark:text-[color:var(--x-tag-dark-text)] border-[color:var(--x-tag-border)"
65
46
  :style="styles"
66
47
  :class="
67
48
  [
68
- sizeClasses,
69
- outlined ? 'border' : 'bg-[color:var(--x-bg)]',
49
+ className,
50
+ classes.wrapper,
51
+ outlined ? 'border' : 'bg-[color:var(--x-tag-bg)]',
70
52
  rounded ? 'rounded-full' : 'rounded'
71
53
  ]"
72
54
  >
73
55
  <span
74
56
  v-if="removable"
75
- class="flex items-center"
57
+ class="max-w-full truncate"
76
58
  >
77
59
  <slot></slot>
78
- <svg
79
- width="24"
80
- height="24"
81
- viewBox="0 0 24 24"
82
- stroke="currentColor"
83
- stroke-linejoin="round"
84
- stroke-linecap="round"
85
- fill="none"
86
- role="presentation"
87
- class="stroke-2 w-4 h-4 ml-1 cursor-pointer hover:text-gray-700 transition-colors duration-150 ease-in-out flex-shrink-0"
60
+ <x-icon
61
+ :size="closeIconSize"
62
+ :icon="closeIcon"
63
+ class="ml-1 cursor-pointer hover:text-gray-700 transition-colors duration-150"
88
64
  @click="(e) => $emit('remove', e)"
89
- >
90
- <path d="M6 18L18 6M6 6l12 12" />
91
- </svg>
65
+ />
92
66
  </span>
93
67
 
94
- <template v-else>
95
- <slot></slot>
96
- </template>
68
+ <slot v-else></slot>
97
69
  </component>
98
70
  </template>
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import Tag from '../Tag.vue'
4
+
5
+ describe('Tag', () => {
6
+ it('renders without errors', () => {
7
+ const wrapper = mount(Tag)
8
+
9
+ expect(wrapper.vm).toBeTruthy()
10
+ })
11
+ })
@@ -0,0 +1,62 @@
1
+ import type { ThemeParams } from '../../composables/theme'
2
+
3
+ export default {
4
+ classes: {
5
+ wrapper: 'inline-block align-bottom text-left',
6
+ // wrapper: ({ props, data }: ThemeParams) => {
7
+ // let c = 'inline-flex items-center leading-none whitespace-nowrap'
8
+
9
+ // if (props.size === 'xs') c += ' px-2 py-1 text-xs'
10
+ // else if (props.size === 'sm') c += ' px-2 py-1 text-sm'
11
+ // else if (props.size === 'lg') c += ' px-4 py-3 text-lg'
12
+ // else if (props.size === 'xl') c += ' px-6 py-6 text-xl'
13
+ // else c += ' px-3 py-2'
14
+
15
+ // return c
16
+ // },
17
+
18
+ // loadingWrapper: 'absolute inset-0 flex items-center justify-center z-40 bg-gray-300 dark:bg-gray-600 rounded opacity-50',
19
+
20
+ label: ({ props }: ThemeParams) => {
21
+ const classes = 'font-medium text-gray-800 dark:text-gray-200 mb-1'
22
+
23
+ if (props.size === 'xs') return classes + ' text-xs'
24
+ else if (props.size === 'sm') return classes + ' text-sm'
25
+ else if (props.size === 'lg') return classes + ' text-lg'
26
+ else if (props.size === 'xl') return classes + ' text-xl'
27
+
28
+ return classes //+ ' text-sm'
29
+ },
30
+
31
+ input: ({ props, data }: ThemeParams) => {
32
+ const classes = ['resize-none appearance-none block w-full placeholder-gray-400 dark:placeholder-gray-500 outline-transparent outline outline-2 outline-offset-[-1px] transition duration-150 ease-in-out border-gray-300 dark:border-gray-700 border shadow-sm rounded-md']
33
+
34
+ if (!data.errorInternal && !props.disabled) classes.push('hover:border-gray-400 dark:hover:border-gray-500')
35
+
36
+ if (props.size === 'xs') classes.push('px-2 py-1 text-xs')
37
+ else if (props.size === 'sm') classes.push('px-2 py-2 text-sm')
38
+ else if (props.size === 'lg') classes.push('px-4 py-3 text-lg')
39
+ else if (props.size === 'xl') classes.push('px-5 py-4 text-xl')
40
+ else classes.push('px-3 py-2')
41
+
42
+ classes.push(props.disabled
43
+ ? 'bg-gray-100 dark:bg-gray-900 text-gray-500 cursor-not-allowed'
44
+ : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200')
45
+
46
+ return classes
47
+ },
48
+ },
49
+
50
+ styles: ({ colors, props, css }: ThemeParams) => {
51
+ const color = colors.getPalette(props.color)
52
+
53
+ return css.variables({
54
+ bg: color[100],
55
+ text: color[800],
56
+ border: color[800],
57
+ dark: {
58
+ text: props.outlined ? color[200] : color[800],
59
+ },
60
+ })
61
+ },
62
+ }
@@ -1,141 +1,127 @@
1
1
  <script lang="ts">
2
- import { defineComponent, ref, watch, onMounted, onBeforeUnmount } from 'vue'
2
+ export default { name: 'XTextarea' }
3
+ </script>
4
+
5
+ <script setup lang="ts">
6
+ import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
7
+ import { useResizeObserver } from '@vueuse/core'
3
8
  import { useCSS } from '../../composables/css'
9
+ import { useTheme } from '../../composables/theme'
4
10
  import { useCommon } from '../../composables/common'
5
11
  import { useColors } from '../../composables/colors'
6
12
  import { useInputtable } from '../../composables/inputtable'
7
13
  import { useInteractive } from '../../composables/interactive'
8
14
 
9
- export default defineComponent({
10
- name: 'XTextarea',
15
+ import XInputError from '../helpers/InputError'
11
16
 
12
- validators: {
13
- ...useCommon.validators(),
14
- },
17
+ import theme from './Textarea.theme'
15
18
 
16
- props: {
17
- ...useCommon.props(),
18
- ...useInteractive.props(),
19
- ...useInputtable.props(),
20
- helper: String,
21
- label: String,
22
- dir: {
23
- type: String,
24
- default: 'ltr',
25
- },
26
- rows: Number,
27
- max: Number,
28
- maxlength: Number,
29
- min: Number,
30
- minlength: Number,
31
- placeholder: String,
32
- adjustToText: {
33
- type: Boolean,
34
- default: true,
35
- },
36
- preventEnter: Boolean,
37
- inputClass: String,
38
- block: Boolean,
19
+ const props = defineProps({
20
+ ...useCommon.props(),
21
+ ...useInteractive.props(),
22
+ ...useInputtable.props(),
23
+ helper: String,
24
+ label: String,
25
+ dir: {
26
+ type: String,
27
+ default: 'ltr',
39
28
  },
40
-
41
- emits: useInputtable.emits(),
42
-
43
- setup(props, { emit }) {
44
- const elRef = ref<HTMLTextAreaElement>()
45
- let observer: ResizeObserver | null = null
46
-
47
- onMounted(() => {
48
- if (elRef.value) {
49
- observer = new ResizeObserver(resize)
50
- observer.observe(elRef.value)
51
- window.addEventListener('resize', resize)
52
- }
53
- })
54
-
55
- onBeforeUnmount(() => {
56
- if (observer) observer.disconnect()
57
- window.removeEventListener('resize', resize)
58
- })
59
-
60
- watch([() => props.modelValue, () => props.size], () => {
61
- setTimeout(resize)
62
- })
63
-
64
- const css = useCSS('textarea')
65
- const colors = useColors()
66
- const color = colors.getPalette('primary')
67
- const style = css.get('border', color[500])
68
-
69
- function onInput() {
70
- resize()
71
- }
72
-
73
- function onEnter(e: KeyboardEvent) {
74
- if (props.preventEnter) e.preventDefault()
75
- e.stopPropagation()
76
-
77
- return
78
- }
79
-
80
- function resize() {
81
- if (props.adjustToText && elRef.value) {
82
- elRef.value.style.height = '1px'
83
- elRef.value.style.height = (2 + elRef.value.scrollHeight) + 'px'
84
- }
85
- }
86
-
87
- const interactive = useInteractive(elRef)
88
-
89
- return {
90
- ...interactive,
91
- ...useInputtable(props, { focus: interactive.focus, emit }),
92
- elRef,
93
- style,
94
- onInput,
95
- onEnter,
96
- }
29
+ rows: [Number, String],
30
+ max: [Number, String],
31
+ maxlength: [Number, String],
32
+ min: [Number, String],
33
+ minlength: [Number, String],
34
+ placeholder: String,
35
+ adjustToText: {
36
+ type: Boolean,
37
+ default: true,
97
38
  },
39
+ preventEnter: Boolean,
40
+ block: Boolean,
41
+ })
42
+
43
+ const emit = defineEmits(useInputtable.emits())
44
+
45
+ const elRef = ref<HTMLTextAreaElement | null>(null)
46
+
47
+ useResizeObserver(elRef, resize)
48
+
49
+ onMounted(() => {
50
+ window.addEventListener('resize', resize)
51
+ })
52
+
53
+ onBeforeUnmount(() => {
54
+ window.removeEventListener('resize', resize)
98
55
  })
56
+
57
+ watch([() => props.modelValue, () => props.size], () => {
58
+ setTimeout(resize)
59
+ })
60
+
61
+ const css = useCSS('textarea')
62
+ const colors = useColors()
63
+ const color = colors.getPalette('primary')
64
+ const style = css.get('border', color[400])
65
+
66
+ function onInput() {
67
+ resize()
68
+ }
69
+
70
+ function onEnter(e: KeyboardEvent) {
71
+ if (props.preventEnter) e.preventDefault()
72
+ e.stopPropagation()
73
+
74
+ return
75
+ }
76
+
77
+ function resize() {
78
+ if (props.adjustToText && elRef.value) {
79
+ elRef.value.style.height = '1px'
80
+ elRef.value.style.height = (2 + elRef.value.scrollHeight) + 'px'
81
+ }
82
+ }
83
+
84
+ const { focus, blur } = useInteractive(elRef)
85
+
86
+ const {
87
+ errorInternal,
88
+ isInsideForm,
89
+ inputListeners,
90
+ reset,
91
+ validate,
92
+ setError,
93
+ } = useInputtable(props, { focus, emit })
94
+
95
+ const { styles, classes, className } = useTheme('textarea', theme, props, { errorInternal })
96
+
97
+ defineExpose({ focus, blur, reset, validate, setError })
99
98
  </script>
100
99
 
101
100
  <template>
102
101
  <label
103
- class="inline-block relative align-bottom text-left"
104
- :class="{ 'mb-3': isInsideForm, 'w-full': block }"
102
+ :style="styles"
103
+ class="relative"
104
+ :class="[
105
+ className,
106
+ classes.wrapper,
107
+ { 'mb-3': isInsideForm, 'w-full': block }
108
+ ]"
105
109
  >
106
110
  <p
107
111
  v-if="label"
108
- class="font-medium text-gray-800 dark:text-gray-200 mb-1"
109
- :class="{
110
- 'text-xs': size === 'xs',
111
- 'text-sm': size === 'sm',
112
- 'text-lg': size === 'lg',
113
- 'text-xl': size === 'xl',
114
- }"
112
+ :class="classes.label"
115
113
  v-text="label"
116
114
  ></p>
117
115
 
118
116
  <textarea
119
117
  ref="elRef"
120
- class="appearance-none block w-full placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none transition-colors duration-150 ease-in-out border-gray-300 dark:border-gray-700 resize-none overflow-hidden border shadow-sm rounded-md
121
- focus:border-[color:var(--x-textarea-border)]
122
- "
118
+ class=""
123
119
  :style="style"
124
120
  :class="[
125
- disabled ? 'bg-gray-100 dark:bg-gray-700 text-gray-500 cursor-not-allowed' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200',
126
- {
127
- // size
128
- 'px-2 py-1 text-xs': size === 'xs',
129
- 'px-2 py-2 text-sm': size === 'sm',
130
- 'px-3 py-2': !size || !['auto', 'xs', 'sm', 'lg', 'xl'].includes(size),
131
- 'px-4 py-3 text-lg': size === 'lg',
132
- 'px-5 py-4 text-xl': size === 'xl',
133
- },
134
- {
135
- // error
136
- 'border-red-500 focus:border-red-500 dark:focus:border-red-500': errorInternal,
137
- },
138
- inputClass,
121
+ classes.input,
122
+ errorInternal
123
+ ? 'border-red-500 dark:border-red-400 focus:outline-red-500'
124
+ : 'focus:outline-[color:var(--x-textarea-border)]',
139
125
  ]"
140
126
  :disabled="disabled"
141
127
  :max="max"
@@ -147,13 +133,12 @@ export default defineComponent({
147
133
  :name="name"
148
134
  :placeholder="placeholder"
149
135
  :readonly="readonly"
150
- :value="modelValue?.toString()"
136
+ :value="modelValue ? String(modelValue) : ''"
151
137
  v-on="inputListeners"
152
138
  @keydown.enter="onEnter"
153
139
  @input="onInput"
154
140
  ></textarea>
155
141
 
156
- <p v-if="errorInternal" class="text-sm text-red-500 mt-1" v-text="errorInternal"></p>
157
- <p v-else-if="helper" class="text-sm text-gray-500 mt-1" v-text="helper"></p>
142
+ <x-input-error :error="errorInternal" :helper="helper"/>
158
143
  </label>
159
144
  </template>
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { mount } from '@vue/test-utils'
3
+ import Textarea from '../Textarea.vue'
4
+
5
+ describe('Textarea', () => {
6
+ it('renders without errors', () => {
7
+ const wrapper = mount(Textarea)
8
+
9
+ expect(wrapper.vm).toBeTruthy()
10
+ })
11
+ })
@@ -0,0 +1,51 @@
1
+ import type { ThemeParams } from '../../composables/theme'
2
+
3
+ export default {
4
+ classes: {
5
+ wrapper: '',
6
+
7
+ label: ({ props }: ThemeParams) => {
8
+ const c = 'font-medium text-gray-800 dark:text-gray-200'
9
+
10
+ if (props.size === 'xs') return c + ' text-xs'
11
+ else if (props.size === 'sm') return c + ' text-sm'
12
+ else if (props.size === 'lg') return c + ' text-lg'
13
+ else if (props.size === 'xl') return c + ' text-xl'
14
+
15
+ return c + ' text-sm'
16
+ },
17
+
18
+ buttonWrapper: ({ props }: ThemeParams) => {
19
+ let c = 'relative shrink-0'
20
+
21
+ if (props.size === 'sm' || props.size === 'xs') c += ' w-6'
22
+ else if (props.size === 'lg') c += ' w-10'
23
+ else if (props.size === 'xl') c += ' w-12'
24
+ else c += ' w-8'
25
+
26
+ return c
27
+ },
28
+
29
+ button: ({ props }: ThemeParams) => {
30
+ let c = 'rounded-full shadow transform transition duration-150 shrink-0'
31
+
32
+ if (props.size === 'sm' || props.size === 'xs') c += ' h-3 w-3'
33
+ else if (props.size === 'lg') c += ' h-5 w-5'
34
+ else if (props.size === 'xl') c += ' h-6 w-6'
35
+ else c += ' h-4 w-4'
36
+
37
+ return c
38
+ },
39
+ },
40
+
41
+ styles: ({ colors, props, css }: ThemeParams) => {
42
+ const color = colors.getPalette(props.color)
43
+
44
+ return css.variables({
45
+ bg: color[500],
46
+ dark: {
47
+ bg: color[600],
48
+ },
49
+ })
50
+ },
51
+ }