@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,78 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
3
+ import { useCurrentElement } from '@vueuse/core'
4
+ import { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'
5
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
6
+ import type { HTMLAttributes } from 'vue'
7
+ import { useCommand, useCommandGroup } from './utils'
8
+
9
+ const props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()
10
+ const emits = defineEmits<ListboxItemEmits>()
11
+
12
+ const delegatedProps = computed(() => {
13
+ const { class: _, ...delegated } = props
14
+
15
+ return delegated
16
+ })
17
+
18
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
19
+
20
+ const id = useId()
21
+ const { filterState, allItems, allGroups } = useCommand()
22
+ const groupContext = useCommandGroup()
23
+
24
+ const isRender = computed(() => {
25
+ if (!filterState.search) {
26
+ return true
27
+ }
28
+ else {
29
+ const filteredCurrentItem = filterState.filtered.items.get(id)
30
+ // If the filtered items is undefined means not in the all times map yet
31
+ // Do the first render to add into the map
32
+ if (filteredCurrentItem === undefined) {
33
+ return true
34
+ }
35
+
36
+ // Check with filter
37
+ return filteredCurrentItem > 0
38
+ }
39
+ })
40
+
41
+ const itemRef = ref()
42
+ const currentElement = useCurrentElement(itemRef)
43
+ onMounted(() => {
44
+ if (!(currentElement.value instanceof HTMLElement))
45
+ return
46
+
47
+ // textValue to perform filter
48
+ allItems.value.set(id, currentElement.value.textContent ?? props.value?.toString() ?? '')
49
+
50
+ const groupId = groupContext?.id
51
+ if (groupId) {
52
+ if (!allGroups.value.has(groupId)) {
53
+ allGroups.value.set(groupId, new Set([id]))
54
+ }
55
+ else {
56
+ allGroups.value.get(groupId)?.add(id)
57
+ }
58
+ }
59
+ })
60
+ onUnmounted(() => {
61
+ allItems.value.delete(id)
62
+ })
63
+ </script>
64
+
65
+ <template>
66
+ <ListboxItem
67
+ v-if="isRender"
68
+ v-bind="forwarded"
69
+ :id="id"
70
+ ref="itemRef"
71
+ :class="cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)"
72
+ @select="() => {
73
+ filterState.search = ''
74
+ }"
75
+ >
76
+ <slot />
77
+ </ListboxItem>
78
+ </template>
@@ -0,0 +1,78 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
3
+ import { useCurrentElement } from '@vueuse/core'
4
+ import { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'
5
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
6
+ import type { HTMLAttributes } from 'vue'
7
+ import { useCommand, useCommandGroup } from './utils'
8
+
9
+ const props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()
10
+ const emits = defineEmits<ListboxItemEmits>()
11
+
12
+ const delegatedProps = computed(() => {
13
+ const { class: _, ...delegated } = props
14
+
15
+ return delegated
16
+ })
17
+
18
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
19
+
20
+ const id = useId()
21
+ const { filterState, allItems, allGroups } = useCommand()
22
+ const groupContext = useCommandGroup()
23
+
24
+ const isRender = computed(() => {
25
+ if (!filterState.search) {
26
+ return true
27
+ }
28
+ else {
29
+ const filteredCurrentItem = filterState.filtered.items.get(id)
30
+ // If the filtered items is undefined means not in the all times map yet
31
+ // Do the first render to add into the map
32
+ if (filteredCurrentItem === undefined) {
33
+ return true
34
+ }
35
+
36
+ // Check with filter
37
+ return filteredCurrentItem > 0
38
+ }
39
+ })
40
+
41
+ const itemRef = ref()
42
+ const currentElement = useCurrentElement(itemRef)
43
+ onMounted(() => {
44
+ if (!(currentElement.value instanceof HTMLElement))
45
+ return
46
+
47
+ // textValue to perform filter
48
+ allItems.value.set(id, currentElement.value.textContent ?? props.value?.toString() ?? '')
49
+
50
+ const groupId = groupContext?.id
51
+ if (groupId) {
52
+ if (!allGroups.value.has(groupId)) {
53
+ allGroups.value.set(groupId, new Set([id]))
54
+ }
55
+ else {
56
+ allGroups.value.get(groupId)?.add(id)
57
+ }
58
+ }
59
+ })
60
+ onUnmounted(() => {
61
+ allItems.value.delete(id)
62
+ })
63
+ </script>
64
+
65
+ <template>
66
+ <ListboxItem
67
+ v-if="isRender"
68
+ v-bind="forwarded"
69
+ :id="id"
70
+ ref="itemRef"
71
+ :class="cn('relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)"
72
+ @select="() => {
73
+ filterState.search = ''
74
+ }"
75
+ >
76
+ <slot />
77
+ </ListboxItem>
78
+ </template>
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import type { SeparatorProps } from 'reka-ui'
3
+ import { Separator } from 'reka-ui'
4
+ import { computed } from 'vue'
5
+ import type { HTMLAttributes } from 'vue'
6
+
7
+ const props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()
8
+
9
+ const delegatedProps = computed(() => {
10
+ const { class: _, ...delegated } = props
11
+
12
+ return delegated
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <Separator
18
+ v-bind="delegatedProps"
19
+ :class="cn('-mx-1 h-px bg-border', props.class)"
20
+ >
21
+ <slot />
22
+ </Separator>
23
+ </template>
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ class?: HTMLAttributes['class']
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <span :class="cn('ml-auto text-xs tracking-widest text-muted-foreground', props.class)">
11
+ <slot />
12
+ </span>
13
+ </template>
@@ -0,0 +1,88 @@
1
+ <script setup lang="ts">
2
+ import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
3
+ import { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'
4
+ import { computed, reactive, ref, watch } from 'vue'
5
+ import type { HTMLAttributes } from 'vue'
6
+ import { provideCommandContext } from './utils'
7
+
8
+ const props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {
9
+ modelValue: '',
10
+ })
11
+
12
+ const emits = defineEmits<ListboxRootEmits>()
13
+
14
+ const delegatedProps = computed(() => {
15
+ const { class: _, ...delegated } = props
16
+
17
+ return delegated
18
+ })
19
+
20
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
21
+
22
+ const allItems = ref<Map<string, string>>(new Map())
23
+ const allGroups = ref<Map<string, Set<string>>>(new Map())
24
+
25
+ const { contains } = useFilter({ sensitivity: 'base' })
26
+ const filterState = reactive({
27
+ search: '',
28
+ filtered: {
29
+ /** The count of all visible items. */
30
+ count: 0,
31
+ /** Map from visible item id to its search score. */
32
+ items: new Map() as Map<string, number>,
33
+ /** Set of groups with at least one visible item. */
34
+ groups: new Set() as Set<string>,
35
+ },
36
+ })
37
+
38
+ function filterItems() {
39
+ if (!filterState.search) {
40
+ filterState.filtered.count = allItems.value.size
41
+ // Do nothing, each item will know to show itself because search is empty
42
+ return
43
+ }
44
+
45
+ // Reset the groups
46
+ filterState.filtered.groups = new Set()
47
+ let itemCount = 0
48
+
49
+ // Check which items should be included
50
+ for (const [id, value] of allItems.value) {
51
+ const score = contains(value, filterState.search)
52
+ filterState.filtered.items.set(id, score ? 1 : 0)
53
+ if (score)
54
+ itemCount++
55
+ }
56
+
57
+ // Check which groups have at least 1 item shown
58
+ for (const [groupId, group] of allGroups.value) {
59
+ for (const itemId of group) {
60
+ if (filterState.filtered.items.get(itemId)! > 0) {
61
+ filterState.filtered.groups.add(groupId)
62
+ break
63
+ }
64
+ }
65
+ }
66
+
67
+ filterState.filtered.count = itemCount
68
+ }
69
+
70
+ watch(() => filterState.search, () => {
71
+ filterItems()
72
+ })
73
+
74
+ provideCommandContext({
75
+ allItems,
76
+ allGroups,
77
+ filterState,
78
+ })
79
+ </script>
80
+
81
+ <template>
82
+ <ListboxRoot
83
+ v-bind="forwarded"
84
+ :class="cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', props.class)"
85
+ >
86
+ <slot />
87
+ </ListboxRoot>
88
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import { DialogRoot, useForwardPropsEmits } from 'reka-ui'
3
+ import type { DialogRootEmits, DialogRootProps } from 'reka-ui'
4
+
5
+ const props = defineProps<DialogRootProps>()
6
+ const emits = defineEmits<DialogRootEmits>()
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits)
9
+ </script>
10
+
11
+ <template>
12
+ <DialogRoot v-bind="forwarded">
13
+ <slot />
14
+ </DialogRoot>
15
+ </template>
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import { X } from 'lucide-vue-next'
3
+ import {
4
+ DialogClose,
5
+ DialogContent,
6
+
7
+ DialogOverlay,
8
+ DialogPortal,
9
+ useForwardPropsEmits,
10
+ } from 'reka-ui'
11
+ import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
12
+ import { computed } from 'vue'
13
+ import type { HTMLAttributes } from 'vue'
14
+
15
+ const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
16
+ const emits = defineEmits<DialogContentEmits>()
17
+
18
+ const delegatedProps = computed(() => {
19
+ const { class: _, ...delegated } = props
20
+
21
+ return delegated
22
+ })
23
+
24
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
25
+ </script>
26
+
27
+ <template>
28
+ <DialogPortal>
29
+ <DialogOverlay
30
+ class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
31
+ />
32
+ <DialogContent
33
+ v-bind="forwarded"
34
+ :class="
35
+ cn(
36
+ 'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border-[1px] bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
37
+ props.class,
38
+ )"
39
+ >
40
+ <slot />
41
+
42
+ <DialogClose
43
+ class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
44
+ >
45
+ <X class="w-4 h-4" />
46
+ <span class="sr-only">Close</span>
47
+ </DialogClose>
48
+ </DialogContent>
49
+ </DialogPortal>
50
+ </template>
@@ -0,0 +1,15 @@
1
+ import type { Ref } from 'vue'
2
+ import { createContext } from 'reka-ui'
3
+
4
+ export const [useCommand, provideCommandContext] = createContext<{
5
+ allItems: Ref<Map<string, string>>
6
+ allGroups: Ref<Map<string, Set<string>>>
7
+ filterState: {
8
+ search: string
9
+ filtered: { count: number, items: Map<string, number>, groups: Set<string> }
10
+ }
11
+ }>('Command')
12
+
13
+ export const [useCommandGroup, provideCommandGroupContext] = createContext<{
14
+ id?: string
15
+ }>('CommandGroup')
@@ -0,0 +1,145 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import TelaComplexTableCell from './complex-table-cell.vue'
3
+
4
+ const meta = {
5
+ title: 'Components/Tela/ComplexTableCell',
6
+ component: TelaComplexTableCell,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: 'A table cell component for use within ComplexTable. Renders cell content based on column and row data. Supports custom cell rendering, text content, and styling.',
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ column: {
18
+ control: 'object',
19
+ description: 'Column definition object with `title` and `key` properties.',
20
+ },
21
+ row: {
22
+ control: 'object',
23
+ description: 'Row data object containing the cell value in the `data` property.',
24
+ },
25
+ },
26
+ decorators: [
27
+ story => ({
28
+ components: { story },
29
+ template: `
30
+ <div style="width: 200px; border: 1px solid #E1E3E4;">
31
+ <story />
32
+ </div>
33
+ `,
34
+ }),
35
+ ],
36
+ } satisfies Meta<typeof TelaComplexTableCell>
37
+
38
+ export default meta
39
+ type Story = StoryObj<typeof meta>
40
+
41
+ export const TextContent: Story = {
42
+ args: {
43
+ column: {
44
+ title: 'Name',
45
+ isDefault: false,
46
+ },
47
+ row: {
48
+ id: '1',
49
+ name: 'John Doe',
50
+ index: 1,
51
+ status: 'success',
52
+ data: {
53
+ Name: 'John Doe',
54
+ },
55
+ },
56
+ },
57
+ }
58
+
59
+ export const LongTextContent: Story = {
60
+ args: {
61
+ column: {
62
+ title: 'Description',
63
+ isDefault: false,
64
+ },
65
+ row: {
66
+ id: '1',
67
+ name: 'John Doe',
68
+ index: 1,
69
+ status: 'success',
70
+ data: {
71
+ Description: 'This is a very long text content that should be truncated with ellipsis because it exceeds the maximum number of lines allowed in the cell component and needs to be handled gracefully.',
72
+ },
73
+ },
74
+ },
75
+ }
76
+
77
+ export const ArrayContent: Story = {
78
+ args: {
79
+ column: {
80
+ title: 'Tags',
81
+ isDefault: false,
82
+ },
83
+ row: {
84
+ id: '1',
85
+ name: 'John Doe',
86
+ index: 1,
87
+ status: 'success',
88
+ data: {
89
+ Tags: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5'],
90
+ },
91
+ },
92
+ },
93
+ }
94
+
95
+ export const EmptyContent: Story = {
96
+ args: {
97
+ column: {
98
+ title: 'Empty',
99
+ isDefault: true,
100
+ },
101
+ row: {
102
+ id: '1',
103
+ name: 'John Doe',
104
+ index: 1,
105
+ status: 'success',
106
+ data: {
107
+ Empty: '',
108
+ },
109
+ },
110
+ },
111
+ }
112
+
113
+ export const UndefinedContent: Story = {
114
+ args: {
115
+ column: {
116
+ title: 'Missing',
117
+ isDefault: true,
118
+ },
119
+ row: {
120
+ id: '1',
121
+ name: 'John Doe',
122
+ index: 1,
123
+ status: 'success',
124
+ data: {},
125
+ },
126
+ },
127
+ }
128
+
129
+ export const NumberContent: Story = {
130
+ args: {
131
+ column: {
132
+ title: 'Amount',
133
+ isDefault: false,
134
+ },
135
+ row: {
136
+ id: '1',
137
+ name: 'John Doe',
138
+ index: 1,
139
+ status: 'success',
140
+ data: {
141
+ Amount: 42,
142
+ },
143
+ },
144
+ },
145
+ }
@@ -0,0 +1,45 @@
1
+ <script lang="ts" setup>
2
+ import { hasEmptyOrNull } from 'tela-shared/src/helpers/empty-or-null'
3
+ import type { Column, Row } from './types'
4
+ import { hasError } from './utils'
5
+ import { useI18n } from 'vue-i18n'
6
+
7
+ defineOptions({
8
+ name: 'TelaComplexTableCell',
9
+ })
10
+ const props = defineProps<{
11
+ column: Column
12
+ row: Row
13
+ }>()
14
+
15
+ const { t } = useI18n()
16
+
17
+ const content = computed(() => {
18
+ const data = props.row.data ?? {}
19
+ return data[props.column.key || props.column.title]
20
+ })
21
+
22
+ const icon = computed(() => props.row.icons?.find(icon => icon?.key === props.column.key))
23
+ </script>
24
+
25
+ <template>
26
+ <div inline-grid h-full justify-start flex flex-row items-center px-12px py-10px gap-6px w-full>
27
+ <div v-if="icon">
28
+ <TelaIcon :name="icon.name" :size="icon.size" :style="icon.style" />
29
+ </div>
30
+ <div v-if="hasEmptyOrNull(content) && !hasError(row)" w-full flex justify-start :class="row.style">
31
+ <span body-14-regular italic text-gray-300 opacity-24>
32
+
33
+ </span>
34
+ </div>
35
+ <div v-else overflow-hidden flex body-14-regular :text="row.color ? row.color : 'gray-800'" justify-start self-center :class="row.style">
36
+ <p v-if="!Array.isArray(content)" line-clamp-2 w-full text-start>
37
+ {{ content }}
38
+ </p>
39
+ <p v-else line-clamp-2 flex items-center gap-4px text-nowrap>
40
+ <span>{{ content.length }} {{ t('common.items') }} </span>
41
+ <TelaIcon name="i-ph-sort-ascending" size="md" mr-2px shrink-0 />
42
+ </p>
43
+ </div>
44
+ </div>
45
+ </template>
@@ -0,0 +1,103 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import TelaComplexTableHeaderCell from './complex-table-header-cell.vue'
3
+
4
+ const meta = {
5
+ title: 'Components/Tela/ComplexTableHeaderCell',
6
+ component: TelaComplexTableHeaderCell,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ layout: 'centered',
10
+ docs: {
11
+ description: {
12
+ component: 'A header cell component for ComplexTable headers. Displays column titles, sorting indicators, and selection checkboxes. Supports different cell types and custom styling.',
13
+ },
14
+ },
15
+ },
16
+ argTypes: {
17
+ type: {
18
+ control: 'select',
19
+ options: ['default', 'checkbox'],
20
+ description: 'Type of header cell. "default" displays column title, "checkbox" displays selection checkbox.',
21
+ },
22
+ column: {
23
+ control: 'object',
24
+ description: 'Column definition object with `title`, `key`, and optionally `color` properties.',
25
+ },
26
+ tabSize: {
27
+ control: 'select',
28
+ options: ['sm', 'md', 'lg'],
29
+ description: 'Size variant for the header cell.',
30
+ },
31
+ },
32
+ } satisfies Meta<typeof TelaComplexTableHeaderCell>
33
+
34
+ export default meta
35
+ type Story = StoryObj<typeof meta>
36
+
37
+ // Basic header cell with title
38
+ export const Default: Story = {
39
+ args: {
40
+ type: 'default',
41
+ column: {
42
+ title: 'Column Title',
43
+ color: 'red',
44
+ },
45
+ tabSize: 'sm',
46
+ },
47
+ }
48
+
49
+ // Header cell with icon
50
+ export const WithIcon: Story = {
51
+ args: {
52
+ type: 'default',
53
+ column: {
54
+ title: 'Column with Icon',
55
+ color: '#71757B',
56
+ icon: {
57
+ name: 'i-ph-check',
58
+ size: '16px',
59
+ },
60
+ },
61
+ },
62
+ }
63
+
64
+ // Default column style
65
+ export const DefaultColumn: Story = {
66
+ args: {
67
+ type: 'default',
68
+ column: {
69
+ title: 'Default Column',
70
+ isDefault: true,
71
+ },
72
+ },
73
+ }
74
+
75
+ // Checkbox header cell
76
+ export const Checkbox: Story = {
77
+ args: {
78
+ type: 'checkbox',
79
+ rows: [1, 2, 3],
80
+ selectedRows: [1, 2],
81
+ },
82
+ }
83
+
84
+ // Checkbox header cell - all selected
85
+ export const CheckboxAllSelected: Story = {
86
+ args: {
87
+ type: 'checkbox',
88
+ rows: [1, 2, 3],
89
+ selectedRows: [1, 2, 3],
90
+ },
91
+ }
92
+
93
+ // With md tab size
94
+ export const WithMdTabSize: Story = {
95
+ args: {
96
+ type: 'default',
97
+ column: {
98
+ title: 'Default Column',
99
+ isDefault: true,
100
+ },
101
+ tabSize: 'md',
102
+ },
103
+ }