@meistrari/tela-build 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 (295) hide show
  1. package/README.md +75 -0
  2. package/app.config.ts +73 -0
  3. package/components/tela/animated/animated-calculating-number.vue +16 -0
  4. package/components/tela/animated/animated-number.mdx +248 -0
  5. package/components/tela/animated/animated-number.stories.ts +52 -0
  6. package/components/tela/animated/animated-number.vue +23 -0
  7. package/components/tela/animated/animated-text.vue +124 -0
  8. package/components/tela/animated/animated-value.vue +68 -0
  9. package/components/tela/avatar/avatar.mdx +117 -0
  10. package/components/tela/avatar/avatar.stories.ts +62 -0
  11. package/components/tela/avatar/avatar.vue +71 -0
  12. package/components/tela/avatar/group/avatar-group.stories.ts +78 -0
  13. package/components/tela/avatar/group/avatar-group.vue +46 -0
  14. package/components/tela/badge/badge.mdx +154 -0
  15. package/components/tela/badge/badge.stories.ts +82 -0
  16. package/components/tela/badge/badge.vue +41 -0
  17. package/components/tela/button/button.mdx +155 -0
  18. package/components/tela/button/button.stories.ts +202 -0
  19. package/components/tela/button/button.vue +107 -0
  20. package/components/tela/card.vue +30 -0
  21. package/components/tela/chart/chart-bar.vue +58 -0
  22. package/components/tela/chat/chat.mdx +268 -0
  23. package/components/tela/chat/chat.stories.ts +253 -0
  24. package/components/tela/chat/command/index.vue +41 -0
  25. package/components/tela/chat/command/mention/index.vue +138 -0
  26. package/components/tela/chat/index.vue +112 -0
  27. package/components/tela/chat/pure-text-input/chat-text-input.vue +190 -0
  28. package/components/tela/chat/text-input/chat-text-input.stories.ts +128 -0
  29. package/components/tela/chat/text-input/index.vue +217 -0
  30. package/components/tela/chat/text-message/chat-text-message.stories.ts +138 -0
  31. package/components/tela/chat/text-message/index.vue +355 -0
  32. package/components/tela/chat/types.ts +19 -0
  33. package/components/tela/checkbox/checkbox-card.vue +30 -0
  34. package/components/tela/checkbox/checkbox.mdx +164 -0
  35. package/components/tela/checkbox/checkbox.stories.ts +104 -0
  36. package/components/tela/checkbox/checkbox.vue +43 -0
  37. package/components/tela/collapsible/Collapsible.vue +15 -0
  38. package/components/tela/collapsible/CollapsibleContent.vue +59 -0
  39. package/components/tela/collapsible/CollapsibleTrigger.vue +12 -0
  40. package/components/tela/collapsible/collapsible.mdx +157 -0
  41. package/components/tela/collapsible-section/collapsible-section.mdx +180 -0
  42. package/components/tela/collapsible-section/collapsible-section.stories.ts +53 -0
  43. package/components/tela/collapsible-section/collapsible-section.vue +51 -0
  44. package/components/tela/collapsible-section-with-actions.vue +98 -0
  45. package/components/tela/combobox/combobox-anchor.vue +24 -0
  46. package/components/tela/combobox/combobox-empty.vue +19 -0
  47. package/components/tela/combobox/combobox-group.vue +24 -0
  48. package/components/tela/combobox/combobox-indicator.vue +22 -0
  49. package/components/tela/combobox/combobox-input.vue +31 -0
  50. package/components/tela/combobox/combobox-item.vue +28 -0
  51. package/components/tela/combobox/combobox-label.vue +24 -0
  52. package/components/tela/combobox/combobox-list.vue +90 -0
  53. package/components/tela/combobox/combobox-module-selector.vue +366 -0
  54. package/components/tela/combobox/combobox-root.vue +15 -0
  55. package/components/tela/combobox/combobox-trigger.vue +12 -0
  56. package/components/tela/combobox/combobox.mdx +285 -0
  57. package/components/tela/combobox/combobox.stories.ts +232 -0
  58. package/components/tela/combobox/combobox.vue +497 -0
  59. package/components/tela/command/command-dialog.vue +22 -0
  60. package/components/tela/command/command-empty.vue +25 -0
  61. package/components/tela/command/command-group.vue +46 -0
  62. package/components/tela/command/command-input.vue +38 -0
  63. package/components/tela/command/command-item.vue +78 -0
  64. package/components/tela/command/command-list.vue +78 -0
  65. package/components/tela/command/command-separator.vue +23 -0
  66. package/components/tela/command/command-shortcut.vue +13 -0
  67. package/components/tela/command/command.vue +88 -0
  68. package/components/tela/command/dialog-base.vue +15 -0
  69. package/components/tela/command/dialog-content.vue +50 -0
  70. package/components/tela/command/utils.ts +15 -0
  71. package/components/tela/complex-table/complex-table-cell.stories.ts +145 -0
  72. package/components/tela/complex-table/complex-table-cell.vue +45 -0
  73. package/components/tela/complex-table/complex-table-header-cell.stories.ts +103 -0
  74. package/components/tela/complex-table/complex-table-header-cell.vue +48 -0
  75. package/components/tela/complex-table/complex-table-header.stories.ts +89 -0
  76. package/components/tela/complex-table/complex-table-header.vue +70 -0
  77. package/components/tela/complex-table/complex-table-row.vue +199 -0
  78. package/components/tela/complex-table/complex-table-virtualized.vue +326 -0
  79. package/components/tela/complex-table/complex-table.stories.ts +358 -0
  80. package/components/tela/complex-table/complex-table.vue +237 -0
  81. package/components/tela/complex-table/composables/table-common.ts +93 -0
  82. package/components/tela/complex-table/composables/table-selection.ts +87 -0
  83. package/components/tela/complex-table/composables/virtual-scroll.ts +252 -0
  84. package/components/tela/complex-table/styles/table-shared.css +170 -0
  85. package/components/tela/complex-table/types.ts +63 -0
  86. package/components/tela/complex-table/utils.ts +35 -0
  87. package/components/tela/confirm-button/confirm-button.vue +137 -0
  88. package/components/tela/confirmation-modal/confirmation-modal.vue +72 -0
  89. package/components/tela/copy-button.vue +86 -0
  90. package/components/tela/date-range-picker.vue +221 -0
  91. package/components/tela/dialog/dialog.mdx +170 -0
  92. package/components/tela/dialog/dialog.vue +182 -0
  93. package/components/tela/disabled-area.vue +16 -0
  94. package/components/tela/disclaimer/disclaimer.mdx +238 -0
  95. package/components/tela/disclaimer/disclaimer.stories.ts +196 -0
  96. package/components/tela/disclaimer/disclaimer.vue +125 -0
  97. package/components/tela/dropdown-menu/DropdownMenu.vue +121 -0
  98. package/components/tela/dropdown-menu/DropdownMenuCheckboxItem.vue +40 -0
  99. package/components/tela/dropdown-menu/DropdownMenuContent.vue +75 -0
  100. package/components/tela/dropdown-menu/DropdownMenuGroup.vue +12 -0
  101. package/components/tela/dropdown-menu/DropdownMenuItem.vue +137 -0
  102. package/components/tela/dropdown-menu/DropdownMenuLabel.vue +26 -0
  103. package/components/tela/dropdown-menu/DropdownMenuRadioGroup.vue +18 -0
  104. package/components/tela/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  105. package/components/tela/dropdown-menu/DropdownMenuRoot.vue +15 -0
  106. package/components/tela/dropdown-menu/DropdownMenuSeparator.vue +21 -0
  107. package/components/tela/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  108. package/components/tela/dropdown-menu/DropdownMenuSub.vue +18 -0
  109. package/components/tela/dropdown-menu/DropdownMenuSubContent.vue +30 -0
  110. package/components/tela/dropdown-menu/DropdownMenuSubTrigger.vue +35 -0
  111. package/components/tela/dropdown-menu/DropdownMenuTrigger.vue +14 -0
  112. package/components/tela/dropdown-menu/dropdown-menu.mdx +265 -0
  113. package/components/tela/dropdown-menu/dropdown-menu.stories.ts +156 -0
  114. package/components/tela/expandable-input.vue +96 -0
  115. package/components/tela/file-drop.vue +37 -0
  116. package/components/tela/file-upload/file-upload.mdx +189 -0
  117. package/components/tela/file-upload/file-upload.stories.ts +48 -0
  118. package/components/tela/file-upload/file-upload.vue +205 -0
  119. package/components/tela/filters/checkbox-filter.stories.ts +218 -0
  120. package/components/tela/filters/checkbox-filter.vue +165 -0
  121. package/components/tela/filters/date-filter.stories.ts +258 -0
  122. package/components/tela/filters/date-filter.vue +200 -0
  123. package/components/tela/filters/user-filter.stories.ts +344 -0
  124. package/components/tela/filters/user-filter.vue +271 -0
  125. package/components/tela/hover-card/hover-card.mdx +221 -0
  126. package/components/tela/hover-card/hover-card.stories.ts +87 -0
  127. package/components/tela/hover-card/hover-card.vue +61 -0
  128. package/components/tela/icon/custom.vue +319 -0
  129. package/components/tela/icon/spinner.vue +12 -0
  130. package/components/tela/icon-button/icon-button.vue +114 -0
  131. package/components/tela/icon.vue +37 -0
  132. package/components/tela/initials.vue +28 -0
  133. package/components/tela/inline-input.vue +77 -0
  134. package/components/tela/input/input.mdx +182 -0
  135. package/components/tela/input/input.stories.ts +153 -0
  136. package/components/tela/input/tela-input.vue +240 -0
  137. package/components/tela/kbd/kbd-return.vue +6 -0
  138. package/components/tela/kbd/kbd.mdx +238 -0
  139. package/components/tela/kbd/kbd.vue +18 -0
  140. package/components/tela/label/label.mdx +121 -0
  141. package/components/tela/label/label.stories.ts +37 -0
  142. package/components/tela/label/label.vue +25 -0
  143. package/components/tela/link-decoration/link-decoration.vue +19 -0
  144. package/components/tela/live-label.vue +32 -0
  145. package/components/tela/long-press-button.vue +98 -0
  146. package/components/tela/menubar/menubar-content.vue +77 -0
  147. package/components/tela/menubar/menubar-item.vue +32 -0
  148. package/components/tela/menubar/menubar-label.vue +14 -0
  149. package/components/tela/menubar/menubar-menu.vue +12 -0
  150. package/components/tela/menubar/menubar-root.vue +30 -0
  151. package/components/tela/menubar/menubar-separator.vue +17 -0
  152. package/components/tela/menubar/menubar-shortcut.vue +14 -0
  153. package/components/tela/menubar/menubar-sub-content.vue +36 -0
  154. package/components/tela/menubar/menubar-sub-trigger.vue +28 -0
  155. package/components/tela/menubar/menubar-sub.vue +20 -0
  156. package/components/tela/menubar/menubar-trigger.vue +27 -0
  157. package/components/tela/menubar/menubar.vue +298 -0
  158. package/components/tela/modal/modal.mdx +145 -0
  159. package/components/tela/modal/modal.vue +242 -0
  160. package/components/tela/multiple-select/multiple-select.mdx +274 -0
  161. package/components/tela/multiple-select/multiple-select.stories.ts +325 -0
  162. package/components/tela/multiple-select/multiple-select.vue +666 -0
  163. package/components/tela/pane.vue +110 -0
  164. package/components/tela/popover/popover-content.vue +48 -0
  165. package/components/tela/popover/popover-trigger.vue +12 -0
  166. package/components/tela/popover/popover.mdx +239 -0
  167. package/components/tela/popover/popover.stories.ts +150 -0
  168. package/components/tela/popover/popover.vue +15 -0
  169. package/components/tela/popover-list/popover-list-nested.vue +104 -0
  170. package/components/tela/popover-list/popover-list.stories.ts +330 -0
  171. package/components/tela/popover-list/popover-list.vue +191 -0
  172. package/components/tela/radio-button.vue +66 -0
  173. package/components/tela/radio-group/radio-group-item.vue +40 -0
  174. package/components/tela/radio-group/radio-group-root.vue +26 -0
  175. package/components/tela/radio-group/radio-group.mdx +78 -0
  176. package/components/tela/radio-group/radio-group.stories.ts +106 -0
  177. package/components/tela/radio-group/radio-group.vue +23 -0
  178. package/components/tela/range-calendar.stories.ts +110 -0
  179. package/components/tela/range-calendar.vue +109 -0
  180. package/components/tela/scroll-area/scroll-area.mdx +183 -0
  181. package/components/tela/scroll-area/scroll-area.vue +30 -0
  182. package/components/tela/scroll-area/scroll-bar.vue +31 -0
  183. package/components/tela/segment-toggle.stories.ts +114 -0
  184. package/components/tela/segment-toggle.vue +66 -0
  185. package/components/tela/select-menu/select-menu-content.vue +106 -0
  186. package/components/tela/select-menu/select-menu-down-button.vue +20 -0
  187. package/components/tela/select-menu/select-menu-group.vue +16 -0
  188. package/components/tela/select-menu/select-menu-item.vue +40 -0
  189. package/components/tela/select-menu/select-menu-root.vue +15 -0
  190. package/components/tela/select-menu/select-menu-trigger.vue +34 -0
  191. package/components/tela/select-menu/select-menu-up-button.vue +20 -0
  192. package/components/tela/select-menu/select-menu-value.vue +12 -0
  193. package/components/tela/select-menu/select-menu.mdx +221 -0
  194. package/components/tela/select-menu/select-menu.stories.ts +91 -0
  195. package/components/tela/select-menu/select-menu.vue +165 -0
  196. package/components/tela/selector/selector.vue +47 -0
  197. package/components/tela/sheet/sheet-close.vue +12 -0
  198. package/components/tela/sheet/sheet-content.vue +57 -0
  199. package/components/tela/sheet/sheet-description.vue +23 -0
  200. package/components/tela/sheet/sheet-footer.vue +18 -0
  201. package/components/tela/sheet/sheet-header.vue +15 -0
  202. package/components/tela/sheet/sheet-root.vue +18 -0
  203. package/components/tela/sheet/sheet-title.vue +23 -0
  204. package/components/tela/sheet/sheet-trigger.vue +12 -0
  205. package/components/tela/sheet/sheet.client.vue +150 -0
  206. package/components/tela/sheet/sheet.mdx +176 -0
  207. package/components/tela/sheet/sheet.stories.ts +201 -0
  208. package/components/tela/sheet/variants.ts +22 -0
  209. package/components/tela/side-sheet/side-sheet.mdx +131 -0
  210. package/components/tela/side-sheet/side-sheet.stories.ts +134 -0
  211. package/components/tela/side-sheet/side-sheet.vue +106 -0
  212. package/components/tela/skeleton/skeleton.mdx +165 -0
  213. package/components/tela/skeleton/skeleton.stories.ts +35 -0
  214. package/components/tela/skeleton/skeleton.vue +45 -0
  215. package/components/tela/skeleton-icon.vue +24 -0
  216. package/components/tela/span.vue +24 -0
  217. package/components/tela/star-button.vue +70 -0
  218. package/components/tela/status/status-lean.vue +30 -0
  219. package/components/tela/status/status.mdx +187 -0
  220. package/components/tela/status/status.stories.ts +160 -0
  221. package/components/tela/status/status.vue +420 -0
  222. package/components/tela/status-bar/status-bar.mdx +178 -0
  223. package/components/tela/status-bar/status-bar.stories.ts +64 -0
  224. package/components/tela/status-bar/status-bar.vue +56 -0
  225. package/components/tela/status-bar/types.ts +5 -0
  226. package/components/tela/switch/switch.mdx +118 -0
  227. package/components/tela/switch/switch.stories.ts +80 -0
  228. package/components/tela/switch/switch.vue +56 -0
  229. package/components/tela/table/table-body.vue +13 -0
  230. package/components/tela/table/table-caption.vue +13 -0
  231. package/components/tela/table/table-cell.vue +20 -0
  232. package/components/tela/table/table-empty.vue +37 -0
  233. package/components/tela/table/table-footer.vue +13 -0
  234. package/components/tela/table/table-head.vue +13 -0
  235. package/components/tela/table/table-header.vue +13 -0
  236. package/components/tela/table/table-row.vue +13 -0
  237. package/components/tela/table/table.mdx +230 -0
  238. package/components/tela/table/table.stories.ts +384 -0
  239. package/components/tela/table/table.vue +15 -0
  240. package/components/tela/tabs/tabs-content.vue +20 -0
  241. package/components/tela/tabs/tabs-indicator.vue +22 -0
  242. package/components/tela/tabs/tabs-list.vue +23 -0
  243. package/components/tela/tabs/tabs-root.vue +15 -0
  244. package/components/tela/tabs/tabs-trigger.vue +27 -0
  245. package/components/tela/tabs/tabs.mdx +138 -0
  246. package/components/tela/tabs/tabs.stories.ts +72 -0
  247. package/components/tela/tabs/tabs.vue +61 -0
  248. package/components/tela/tags/tags-select.mdx +318 -0
  249. package/components/tela/tags/tags-select.stories.ts +47 -0
  250. package/components/tela/tags/tags-select.vue +637 -0
  251. package/components/tela/tags/tags.mdx +151 -0
  252. package/components/tela/tags/tags.stories.ts +118 -0
  253. package/components/tela/tags/tags.vue +112 -0
  254. package/components/tela/textarea/textarea.mdx +102 -0
  255. package/components/tela/textarea/textarea.stories.ts +50 -0
  256. package/components/tela/textarea/textarea.vue +34 -0
  257. package/components/tela/toggle-group.vue +91 -0
  258. package/components/tela/tooltip/tooltip-content.vue +45 -0
  259. package/components/tela/tooltip/tooltip-provider.vue +12 -0
  260. package/components/tela/tooltip/tooltip-root.vue +15 -0
  261. package/components/tela/tooltip/tooltip-trigger.vue +12 -0
  262. package/components/tela/tooltip/tooltip.mdx +196 -0
  263. package/components/tela/tooltip/tooltip.stories.ts +200 -0
  264. package/components/tela/tooltip/tooltip.vue +91 -0
  265. package/components/tela/tooltip-group/tooltip-group-trigger.vue +92 -0
  266. package/components/tela/tooltip-group/tooltip-group.mdx +236 -0
  267. package/components/tela/tooltip-group/tooltip-group.stories.ts +465 -0
  268. package/components/tela/tooltip-group/tooltip-group.vue +35 -0
  269. package/components/tela/transparent-input.vue +151 -0
  270. package/components/tela/variable-icon.vue +28 -0
  271. package/components/tela/variable-input.vue +77 -0
  272. package/components/tela/wide-button/wide-button.vue +40 -0
  273. package/components.json +18 -0
  274. package/composables/status-toast.ts +67 -0
  275. package/css/reset.css +386 -0
  276. package/css/text.css +22 -0
  277. package/lib/doc-generator.ts +903 -0
  278. package/lib/extractors/volar-extract.ts +186 -0
  279. package/lib/type-resolver.ts +402 -0
  280. package/lib/utils.ts +6 -0
  281. package/modules/tela-build-docs/index.ts +139 -0
  282. package/nuxt.config.ts +80 -0
  283. package/package.json +84 -0
  284. package/plugins/test-id.ts +7 -0
  285. package/tsconfig.json +7 -0
  286. package/types/custom-icon.ts +1 -0
  287. package/types/index.ts +2 -0
  288. package/types/status.ts +1 -0
  289. package/unocss.config.ts +89 -0
  290. package/utils/component-utils.ts +30 -0
  291. package/utils/design-tokens.ts +431 -0
  292. package/utils/fold.ts +8 -0
  293. package/utils/select-menu.ts +10 -0
  294. package/utils/status.ts +1 -0
  295. package/utils/without-keys.ts +34 -0
@@ -0,0 +1,114 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import { ref, watch } from 'vue'
3
+
4
+ import SegmentToggle from './segment-toggle.vue'
5
+
6
+ const meta: Meta<typeof SegmentToggle> = {
7
+ title: 'Core/SegmentToggle',
8
+ component: SegmentToggle,
9
+ tags: ['autodocs'],
10
+ parameters: {
11
+ layout: 'centered',
12
+ docs: {
13
+ description: {
14
+ component: 'A segment toggle component that displays multiple options as connected segments. Only one option can be selected at a time. Supports v-model binding, different sizes, and disabled states. Useful for mutually exclusive option selection with a modern segmented control interface.',
15
+ },
16
+ },
17
+ },
18
+ argTypes: {
19
+ modelValue: {
20
+ control: 'text',
21
+ description: 'The currently selected option value (v-model).',
22
+ },
23
+ options: {
24
+ control: 'object',
25
+ description: 'Array of toggle options. Each option should have a `value` and `label` property.',
26
+ },
27
+ size: {
28
+ control: 'select',
29
+ options: ['small', 'medium'],
30
+ description: 'Size of the segment toggle. Controls height and padding.',
31
+ },
32
+ disabled: {
33
+ control: 'boolean',
34
+ description: 'Disable the entire segment toggle, preventing user interaction.',
35
+ },
36
+ class: {
37
+ control: 'text',
38
+ description: 'Custom CSS classes to apply to the segment toggle container.',
39
+ },
40
+ },
41
+ args: {
42
+ options: [
43
+ { label: 'Left', value: 'left' },
44
+ { label: 'Center', value: 'center' },
45
+ { label: 'Right', value: 'right' },
46
+ ],
47
+ modelValue: 'left',
48
+ size: 'medium',
49
+ disabled: false,
50
+ },
51
+ render: (args) => {
52
+ return {
53
+ components: { SegmentToggle },
54
+ setup() {
55
+ const value = ref<string>(args.modelValue || '')
56
+
57
+ watch(
58
+ () => args.modelValue,
59
+ (val) => {
60
+ value.value = val || ''
61
+ },
62
+ )
63
+
64
+ return { args, value }
65
+ },
66
+ template: `
67
+ <div style="padding: 20px; display: flex; flex-direction: column; align-items: center; gap: 16px;">
68
+ <SegmentToggle
69
+ v-model="value"
70
+ :options="args.options"
71
+ :size="args.size"
72
+ :disabled="args.disabled"
73
+ :class="args.class"
74
+ />
75
+ <div style="font-family: monospace; font-size: 12px;">Selected: {{ value }}</div>
76
+ </div>
77
+ `,
78
+ }
79
+ },
80
+ }
81
+
82
+ export default meta
83
+
84
+ type Story = StoryObj<typeof meta>
85
+
86
+ export const Default: Story = {}
87
+
88
+ export const Small: Story = {
89
+ args: {
90
+ size: 'small',
91
+ },
92
+ }
93
+
94
+ export const Disabled: Story = {
95
+ args: {
96
+ disabled: true,
97
+ },
98
+ }
99
+
100
+ export const TwoOptions: Story = {
101
+ args: {
102
+ options: [
103
+ { label: 'On', value: 'on' },
104
+ { label: 'Off', value: 'off' },
105
+ ],
106
+ modelValue: 'on',
107
+ },
108
+ }
109
+
110
+ export const PreselectedMiddle: Story = {
111
+ args: {
112
+ modelValue: 'center',
113
+ },
114
+ }
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ interface Option {
3
+ label: string
4
+ value: string
5
+ }
6
+
7
+ const props = withDefaults(defineProps<{
8
+ modelValue: string
9
+ options: Option[]
10
+ class?: string
11
+ buttonsClass?: string
12
+ size?: 'small' | 'medium'
13
+ disabled?: boolean
14
+ }>(), {
15
+ size: 'medium',
16
+ })
17
+
18
+ const emit = defineEmits<{
19
+ (e: 'update:modelValue', value: string): void
20
+ }>()
21
+
22
+ const uniqueId = `segment-toggle-${Math.random().toString(36)}`
23
+
24
+ function selectTab(value: string) {
25
+ emit('update:modelValue', value)
26
+ }
27
+ </script>
28
+
29
+ <template>
30
+ <div
31
+ rounded-full flex items-center gap-2px select-none p-2px min-w-68px bg-gray-100
32
+ :class="[
33
+ props.size === 'small' ? 'min-h-24px' : 'min-h-28px',
34
+ props.disabled && 'opacity-50 pointer-events-none cursor-not-allowed',
35
+ props.class,
36
+ ]"
37
+ >
38
+ <button
39
+ v-for="option in options"
40
+ :key="option.value"
41
+ type="button"
42
+ relative body-12-semibold rounded-full transition-all duration-200 flex items-center justify-center
43
+ :class="[
44
+ props.size === 'small' ? 'h-24px px-12px min-w-50px' : 'h-28px px-24px min-w-115px',
45
+ props.buttonsClass,
46
+ ]"
47
+ :disabled="props.disabled"
48
+ @click="selectTab(option.value)"
49
+ >
50
+ <span relative z-10 :class="modelValue === option.value ? 'text-gray-900' : 'text-gray-700'">{{ option.label }}</span>
51
+ <AnimatePresence mode="wait" :initial="false">
52
+ <Motion
53
+ v-if="modelValue === option.value"
54
+ aria-hidden="true"
55
+ :layout-id="`${uniqueId}-active-tab`"
56
+ absolute inset-0 bg-white shadow-tab rounded-inherit size-full
57
+ class="z-0"
58
+ :initial="{ opacity: 0 }"
59
+ :animate="{ opacity: 1 }"
60
+ :exit="{ opacity: 0 }"
61
+ :transition="{ duration: 0.3, type: 'spring', bounce: 0 }"
62
+ />
63
+ </AnimatePresence>
64
+ </button>
65
+ </div>
66
+ </template>
@@ -0,0 +1,106 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ SelectContent,
4
+ SelectViewport,
5
+ useForwardPropsEmits,
6
+ SelectPortal,
7
+
8
+ } from 'reka-ui'
9
+ import type { SelectContentEmits, SelectContentProps } from 'reka-ui'
10
+ import type { HTMLAttributes } from 'vue'
11
+ import { reactiveOmit } from '@vueuse/core'
12
+
13
+ import SelectMenuDownButton from './select-menu-down-button.vue'
14
+ import SelectMenuUpButton from './select-menu-up-button.vue'
15
+
16
+ defineOptions({
17
+ inheritAttrs: false,
18
+ })
19
+
20
+ const props = withDefaults(
21
+ defineProps<SelectContentProps & { class?: HTMLAttributes['class'], enablePortal?: boolean }>(),
22
+ {
23
+ position: 'popper',
24
+ enablePortal: false,
25
+ },
26
+ )
27
+ const emits = defineEmits<SelectContentEmits>()
28
+
29
+ const delegatedProps = reactiveOmit(props, 'class')
30
+
31
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
32
+ </script>
33
+
34
+ <template>
35
+ <SelectPortal v-if="enablePortal">
36
+ <SelectContent
37
+ v-bind="{ ...forwarded, ...$attrs }"
38
+ :class="cn(
39
+ 'SelectContent relative z-999 max-h-96 overflow-hidden rounded-[10px] border-[0.5px] border-gray-300 bg-white-1000',
40
+ props.class,
41
+ )"
42
+ :side-offset="4"
43
+ shadow="0 4px 16px 0 rgba(85, 91, 98, 0.14)"
44
+ avoid-collisions
45
+ >
46
+ <SelectMenuUpButton />
47
+ <SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--reka-select-trigger-height] w-full min-w-[--reka-select-trigger-width]')">
48
+ <slot />
49
+ </SelectViewport>
50
+ <SelectMenuDownButton />
51
+ </SelectContent>
52
+ </SelectPortal>
53
+ <SelectContent
54
+ v-else
55
+ v-bind="{ ...forwarded, ...$attrs }"
56
+ :class="cn(
57
+ 'SelectContent relative z-999 max-h-96 overflow-hidden rounded-[10px] border-[0.5px] border-gray-300 bg-white-1000',
58
+ props.class,
59
+ )"
60
+ :side-offset="4"
61
+ shadow="0 4px 16px 0 rgba(85, 91, 98, 0.14)"
62
+ avoid-collisions
63
+ >
64
+ <SelectMenuUpButton />
65
+ <SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--reka-select-trigger-height] w-full min-w-[--reka-select-trigger-width]')">
66
+ <slot />
67
+ </SelectViewport>
68
+ <SelectMenuDownButton />
69
+ </SelectContent>
70
+ </template>
71
+
72
+ <style>
73
+ .SelectContent {
74
+ transform-origin: var(--reka-select-content-transform-origin);
75
+
76
+ &[data-state="open"] {
77
+ animation: slideDownAndFade 0.12s ease-out;
78
+ }
79
+
80
+ &[data-state="closed"] {
81
+ animation: slideUpAndFade 0.12s ease-out;
82
+ }
83
+ }
84
+
85
+ @keyframes slideDownAndFade {
86
+ from {
87
+ opacity: 0;
88
+ transform: translateY(2px) scale(0.97);
89
+ }
90
+ to {
91
+ opacity: 1;
92
+ transform: scale(1);
93
+ }
94
+ }
95
+
96
+ @keyframes slideUpAndFade {
97
+ from {
98
+ opacity: 1;
99
+ transform: translateY(0) scale(1);
100
+ }
101
+ to {
102
+ opacity: 0;
103
+ transform: scale(0.97);
104
+ }
105
+ }
106
+ </style>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { reactiveOmit } from '@vueuse/core'
4
+ import { SelectScrollDownButton, useForwardProps } from 'reka-ui'
5
+ import type { SelectScrollDownButtonProps } from 'reka-ui'
6
+
7
+ const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>()
8
+
9
+ const delegatedProps = reactiveOmit(props, 'class')
10
+
11
+ const forwardedProps = useForwardProps(delegatedProps)
12
+ </script>
13
+
14
+ <template>
15
+ <SelectScrollDownButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
16
+ <slot>
17
+ <TelaIcon name="i-ph-caret-down" text="16px" color="gray-400" />
18
+ </slot>
19
+ </SelectScrollDownButton>
20
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import type { SelectGroupProps } from 'reka-ui'
3
+ import type { HTMLAttributes } from 'vue'
4
+ import { reactiveOmit } from '@vueuse/core'
5
+ import { SelectGroup } from 'reka-ui'
6
+
7
+ const props = defineProps<SelectGroupProps & { class?: HTMLAttributes['class'] }>()
8
+
9
+ const delegatedProps = reactiveOmit(props, 'class')
10
+ </script>
11
+
12
+ <template>
13
+ <SelectGroup :class="cn('w-full', props.class)" v-bind="delegatedProps">
14
+ <slot />
15
+ </SelectGroup>
16
+ </template>
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ import type { SelectItemProps } from 'reka-ui'
3
+ import type { HTMLAttributes } from 'vue'
4
+ import { reactiveOmit } from '@vueuse/core'
5
+ import {
6
+ SelectItem,
7
+ SelectItemIndicator,
8
+ SelectItemText,
9
+ useForwardProps,
10
+ } from 'reka-ui'
11
+ import { cn } from '@/lib/utils'
12
+
13
+ const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>()
14
+
15
+ const delegatedProps = reactiveOmit(props, 'class')
16
+
17
+ const forwardedProps = useForwardProps(delegatedProps)
18
+ </script>
19
+
20
+ <template>
21
+ <SelectItem
22
+ v-bind="forwardedProps"
23
+ :class="
24
+ cn(
25
+ 'relative flex w-full cursor-pointer select-none items-center justify-between gap-2 rounded-[12px] px-[12px] py-[7px] text-body-14-medium font-460 outline-none focus:bg-gray-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
26
+ props.class,
27
+ )
28
+ "
29
+ >
30
+ <SelectItemText>
31
+ <slot />
32
+ </SelectItemText>
33
+
34
+ <span class="relative flex h-3.5 w-3.5 items-center justify-center">
35
+ <SelectItemIndicator>
36
+ <TelaIcon name="i-ph-check" size="14px" color="gray-500" />
37
+ </SelectItemIndicator>
38
+ </span>
39
+ </SelectItem>
40
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import { SelectRoot, useForwardPropsEmits } from 'reka-ui'
3
+ import type { SelectRootProps, SelectRootEmits } from 'reka-ui'
4
+
5
+ const props = defineProps<SelectRootProps>()
6
+ const emits = defineEmits<SelectRootEmits>()
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits)
9
+ </script>
10
+
11
+ <template>
12
+ <SelectRoot v-bind="forwarded">
13
+ <slot />
14
+ </SelectRoot>
15
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup lang="ts">
2
+ import type { SelectTriggerProps } from 'reka-ui'
3
+ import type { HTMLAttributes } from 'vue'
4
+ import { reactiveOmit } from '@vueuse/core'
5
+ import { SelectIcon, SelectTrigger, useForwardProps } from 'reka-ui'
6
+
7
+ const props = withDefaults(
8
+ defineProps<SelectTriggerProps & { triggerIconSize?: string, class?: HTMLAttributes['class'] }>(),
9
+ {
10
+ triggerIconSize: '12px',
11
+ },
12
+ )
13
+
14
+ const delegatedProps = reactiveOmit(props, 'class')
15
+
16
+ const forwardedProps = useForwardProps(delegatedProps)
17
+ </script>
18
+
19
+ <template>
20
+ <SelectTrigger
21
+ v-bind="forwardedProps"
22
+ :class="cn(
23
+ 'group flex h-32px w-full items-center gap-[12px] justify-between rounded-[10px] border-[0.5px] border-gray-300 bg-white-1000 pl-[12px] pr-[10px] py-[7px] text-body-14-semibold font-520 select-none text-start',
24
+ 'data-[placeholder]:text-gray-900 data-[state=open]:text-gray-500 hover:bg-gray-100 data-[state=open]:bg-gray-100 focus-visible:outline-none [&>span]:truncate',
25
+ 'focus-visible:ring-[0.5px] focus-visible:ring-cyan-600 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:border-gray-200 disabled:text-gray-400',
26
+ props.class,
27
+ )"
28
+ >
29
+ <slot />
30
+ <SelectIcon as-child>
31
+ <TelaIcon name="i-ph-caret-down" :size="props.triggerIconSize" color="gray-500" class="shrink-0 transition-all ease-out duration-150 group-data-[state=open]:rotate-180" />
32
+ </SelectIcon>
33
+ </SelectTrigger>
34
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { reactiveOmit } from '@vueuse/core'
4
+ import { SelectScrollUpButton, useForwardProps } from 'reka-ui'
5
+ import type { SelectScrollUpButtonProps } from 'reka-ui'
6
+
7
+ const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>()
8
+
9
+ const delegatedProps = reactiveOmit(props, 'class')
10
+
11
+ const forwardedProps = useForwardProps(delegatedProps)
12
+ </script>
13
+
14
+ <template>
15
+ <SelectScrollUpButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
16
+ <slot>
17
+ <TelaIcon name="i-ph-caret-up" text="16px" color="gray-400" />
18
+ </slot>
19
+ </SelectScrollUpButton>
20
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { SelectValueProps } from 'reka-ui'
3
+ import { SelectValue } from 'reka-ui'
4
+
5
+ const props = defineProps<SelectValueProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <SelectValue v-bind="props">
10
+ <slot />
11
+ </SelectValue>
12
+ </template>
@@ -0,0 +1,221 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as SelectMenuStories from './select-menu.stories.ts';
3
+
4
+ <Meta of={SelectMenuStories} />
5
+
6
+ # TelaSelectMenu
7
+
8
+ A flexible select menu component built on reka-ui. Allows users to select a single option from a dropdown list. Supports icons, descriptions, tooltips, grouping, and custom styling.
9
+
10
+ ## Examples
11
+
12
+ ### Basic Usage
13
+
14
+ ```vue
15
+ <script setup>
16
+ import { ref } from 'vue'
17
+
18
+ const selected = ref('')
19
+ const options = [
20
+ { value: 'option1', label: 'Option 1' },
21
+ { value: 'option2', label: 'Option 2' },
22
+ { value: 'option3', label: 'Option 3' }
23
+ ]
24
+ </script>
25
+
26
+ <template>
27
+ <TelaSelectMenu
28
+ v-model="selected"
29
+ :options="options"
30
+ placeholder="Select an option"
31
+ />
32
+ </template>
33
+ ```
34
+
35
+ ### With Icons
36
+
37
+ ```vue
38
+ <script setup>
39
+ import { ref } from 'vue'
40
+
41
+ const selected = ref('')
42
+ const options = [
43
+ { value: 'user', label: 'User', icon: 'i-ph-user' },
44
+ { value: 'settings', label: 'Settings', icon: 'i-ph-gear' },
45
+ { value: 'notifications', label: 'Notifications', icon: 'i-ph-bell' }
46
+ ]
47
+ </script>
48
+
49
+ <template>
50
+ <TelaSelectMenu
51
+ v-model="selected"
52
+ :options="options"
53
+ />
54
+ </template>
55
+ ```
56
+
57
+ ### With Descriptions
58
+
59
+ ```vue
60
+ <TelaSelectMenu
61
+ v-model="selected"
62
+ :options="[
63
+ {
64
+ value: 'basic',
65
+ label: 'Basic Plan',
66
+ description: 'For individuals'
67
+ },
68
+ {
69
+ value: 'pro',
70
+ label: 'Pro Plan',
71
+ description: 'For small teams'
72
+ },
73
+ {
74
+ value: 'enterprise',
75
+ label: 'Enterprise',
76
+ description: 'For large organizations'
77
+ }
78
+ ]"
79
+ />
80
+ ```
81
+
82
+ ### With External Icons
83
+
84
+ ```vue
85
+ <TelaSelectMenu
86
+ v-model="framework"
87
+ :options="[
88
+ {
89
+ value: 'vue',
90
+ label: 'Vue.js',
91
+ externalIconSrc: 'https://vuejs.org/logo.svg'
92
+ },
93
+ {
94
+ value: 'react',
95
+ label: 'React',
96
+ externalIconSrc: 'https://react.dev/logo.svg'
97
+ }
98
+ ]"
99
+ />
100
+ ```
101
+
102
+ ### Custom Trigger
103
+
104
+ ```vue
105
+ <TelaSelectMenu v-model="selected" :options="options">
106
+ <template #trigger="{ currentOption }">
107
+ <button class="custom-trigger">
108
+ {{ currentOption?.label || 'Select' }}
109
+ </button>
110
+ </template>
111
+ </TelaSelectMenu>
112
+ ```
113
+
114
+ ### Custom Styling
115
+
116
+ ```vue
117
+ <TelaSelectMenu
118
+ v-model="selected"
119
+ :options="options"
120
+ trigger-class="w-300px"
121
+ content-class="max-h-400px"
122
+ item-class="py-3"
123
+ />
124
+ ```
125
+
126
+ ### With Icon Background
127
+
128
+ ```vue
129
+ <TelaSelectMenu
130
+ v-model="selected"
131
+ :options="options"
132
+ :icon-with-background="{
133
+ size: 'md',
134
+ backgroundClass: 'bg-blue-100'
135
+ }"
136
+ />
137
+ ```
138
+
139
+ ### Disabled State
140
+
141
+ ```vue
142
+ <TelaSelectMenu
143
+ v-model="selected"
144
+ :options="options"
145
+ disabled
146
+ />
147
+ ```
148
+
149
+ ## Props
150
+
151
+ <ArgTypes of={SelectMenuStories} />
152
+
153
+ ```typescript
154
+ type SelectMenuOption = {
155
+ value: string
156
+ label: string
157
+ description?: string
158
+ icon?: string | Component
159
+ externalIconSrc?: string
160
+ group?: string
161
+ tooltipContent?: Component
162
+ }
163
+
164
+ type SelectMenuProps = {
165
+ modelValue?: string
166
+ options: SelectMenuOption[]
167
+ triggerClass?: string
168
+ contentClass?: string
169
+ groupClass?: string
170
+ itemClass?: string
171
+ placeholder?: string
172
+ triggerIconSize?: string
173
+ disabled?: boolean
174
+ iconWithBackground?: {
175
+ size: 'xs' | 'sm' | 'md'
176
+ backgroundClass: string
177
+ }
178
+ enablePortal?: boolean
179
+ }
180
+ ```
181
+
182
+ ## Slots
183
+
184
+ - `trigger` - Custom trigger button (receives `currentOption` as slot prop)
185
+
186
+ ## Components
187
+
188
+ The SelectMenu system consists of these sub-components:
189
+ - `TelaSelectMenuRoot` - Root container component
190
+ - `TelaSelectMenuTrigger` - Trigger button
191
+ - `TelaSelectMenuValue` - Value display
192
+ - `TelaSelectMenuContent` - Dropdown content container
193
+ - `TelaSelectMenuGroup` - Group container for items
194
+ - `TelaSelectMenuItem` - Individual selectable item
195
+
196
+ ## Features
197
+
198
+ - **Single Selection**: Choose one option from a list
199
+ - **Icons Support**: Use icon names or external image sources
200
+ - **Descriptions**: Add helpful context to options
201
+ - **Tooltips**: Show additional information on hover
202
+ - **Grouping**: Organize options into groups
203
+ - **Custom Styling**: Granular control over all parts
204
+ - **Portal Rendering**: Control dropdown positioning
205
+ - **Keyboard Navigation**: Full keyboard support
206
+ - **Accessible**: Built on reka-ui with proper ARIA attributes
207
+
208
+ ## Events
209
+
210
+ - `update:modelValue` - Emitted when selection changes with new value
211
+ - `select` - Emitted when an option is selected with the value
212
+ - `blur` - Emitted when select loses focus
213
+ - `focus` - Emitted when select gains focus
214
+
215
+ ## Accessibility
216
+
217
+ - Built on reka-ui primitives
218
+ - Proper ARIA attributes
219
+ - Keyboard navigation (Arrow keys, Enter, Escape)
220
+ - Focus management
221
+ - Screen reader friendly