@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,110 @@
1
+ <script setup lang="ts">
2
+ import { Pane } from 'splitpanes'
3
+
4
+ const props = defineProps<{
5
+ title?: string
6
+ subtitle?: string
7
+ size?: number
8
+ minSize?: number
9
+ icon?: string
10
+ iconUrl?: string
11
+ collapsible?: boolean
12
+ collapseThreshold?: number
13
+ collapsedSize?: number
14
+ collapsedIcon?: string
15
+ startCollapsed?: boolean
16
+ disableSplit?: boolean
17
+ }>()
18
+
19
+ const emit = defineEmits<{
20
+ 'update:collapse': [size: number]
21
+ }>()
22
+
23
+ const size = ref(props.size)
24
+ const collapsedSize = ref(props.collapsedSize ?? 7)
25
+ const sizeBeforeCollapse = ref(props.size)
26
+ const isCollapsed = ref(Boolean(props.startCollapsed))
27
+
28
+ watch(() => props.size, (newValue) => {
29
+ size.value = newValue
30
+
31
+ if (isCollapsed.value && newValue !== collapsedSize.value)
32
+ isCollapsed.value = false
33
+
34
+ if (!isCollapsed.value && newValue && newValue <= collapsedSize.value + (props.collapseThreshold ?? 0)) {
35
+ isCollapsed.value = true
36
+ emit('update:collapse', collapsedSize.value)
37
+ }
38
+ }, { immediate: true })
39
+
40
+ function toggleCollapse() {
41
+ if (isCollapsed.value) {
42
+ isCollapsed.value = false
43
+ emit('update:collapse', Math.max(sizeBeforeCollapse.value ?? 0, props.minSize ?? 0, collapsedSize.value + 8))
44
+ }
45
+ else {
46
+ isCollapsed.value = true
47
+ sizeBeforeCollapse.value = size.value
48
+ emit('update:collapse', collapsedSize.value)
49
+ }
50
+ }
51
+ </script>
52
+
53
+ <template>
54
+ <component
55
+ :is="disableSplit ? 'div' : Pane"
56
+ :size="disableSplit ? undefined : size"
57
+ :min-size="minSize"
58
+ >
59
+ <div v-if="title || $slots.actions" flex items-center w-full justify-between relative h-72px z-1>
60
+ <Transition name="fade">
61
+ <div v-if="title && !isCollapsed" flex flex-col p-24px>
62
+ <div flex>
63
+ <img v-if="iconUrl" :src="iconUrl" w-24px>
64
+ <TelaIcon v-else-if="icon" :name="icon" w-24px />
65
+ <div :m="(iconUrl || icon) ? 'l-16px' : 'l-8px'" font-semibold text="14px textcolor">
66
+ {{ title }}
67
+ </div>
68
+ </div>
69
+ <div v-if="subtitle" :m="(iconUrl || icon) ? 'l-16px' : 'l-8px'" font-regular text="13px gray-800">
70
+ {{ subtitle }}
71
+ </div>
72
+ </div>
73
+ </Transition>
74
+ <div absolute top-16px right-32px flex items-center gap-8px>
75
+ <slot name="actions" />
76
+
77
+ <TelaButton
78
+ v-if="collapsible"
79
+ transition ease-in-out
80
+ ml-12px
81
+ icon="i-ph-arrow-left"
82
+ size="sm"
83
+ color="primary"
84
+ variant="ghost"
85
+ :class="{
86
+ 'rotate-180': !isCollapsed,
87
+ }"
88
+ @click="toggleCollapse"
89
+ />
90
+ </div>
91
+ </div>
92
+
93
+ <slot v-if="!isCollapsed" />
94
+ </component>
95
+ </template>
96
+
97
+ <style scoped>
98
+ .fade-enter-active {
99
+ transition: opacity 0.6s cubic-bezier(1, 0, 0, 1);
100
+ }
101
+
102
+ .fade-leave-active {
103
+ transition: opacity 0.6s cubic-bezier(1, 0, 0, 1);
104
+ }
105
+
106
+ .fade-enter-from,
107
+ .fade-leave-to {
108
+ opacity: 0;
109
+ }
110
+ </style>
@@ -0,0 +1,48 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ PopoverContent,
4
+ PopoverPortal,
5
+ useForwardPropsEmits,
6
+ } from 'reka-ui'
7
+ import type { PopoverContentEmits, PopoverContentProps } from 'reka-ui'
8
+ import { computed } from 'vue'
9
+ import type { HTMLAttributes } from 'vue'
10
+
11
+ defineOptions({
12
+ inheritAttrs: false,
13
+ })
14
+
15
+ const props = withDefaults(
16
+ defineProps<PopoverContentProps & { class?: HTMLAttributes['class'] }>(),
17
+ {
18
+ align: 'center',
19
+ sideOffset: 4,
20
+ },
21
+ )
22
+ const emits = defineEmits<PopoverContentEmits>()
23
+
24
+ const delegatedProps = computed(() => {
25
+ const { class: _, ...delegated } = props
26
+
27
+ return delegated
28
+ })
29
+
30
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
31
+ </script>
32
+
33
+ <template>
34
+ <PopoverPortal>
35
+ <PopoverContent
36
+ v-bind="{ ...forwarded, ...$attrs }"
37
+ :class="
38
+ cn(
39
+ 'w-72 rounded-md border-[1px] bg-popover p-4 text-popover-foreground shadow-md outline-none 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
40
+ props.class,
41
+ )
42
+ "
43
+ z-700
44
+ >
45
+ <slot />
46
+ </PopoverContent>
47
+ </PopoverPortal>
48
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import { PopoverTrigger } from 'reka-ui'
3
+ import type { PopoverTriggerProps } from 'reka-ui'
4
+
5
+ const props = defineProps<PopoverTriggerProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <PopoverTrigger v-bind="props">
10
+ <slot />
11
+ </PopoverTrigger>
12
+ </template>
@@ -0,0 +1,239 @@
1
+ import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
2
+ import * as PopoverStories from './popover.stories.ts';
3
+
4
+ <Meta of={PopoverStories} />
5
+
6
+ # TelaPopover
7
+
8
+ A popover component that displays content in a floating panel. Supports positioning on all sides (top, right, bottom, left) with different alignments (start, center, end). Built with composable subcomponents for flexible usage.
9
+
10
+ ## Examples
11
+
12
+ ### With Custom Content
13
+
14
+ <Canvas of={PopoverStories.WithCustomContent} />
15
+
16
+ ### Different Positions
17
+
18
+ <Canvas of={PopoverStories.WithDifferentPositions} />
19
+
20
+ ### Different Alignments
21
+
22
+ <Canvas of={PopoverStories.WithDifferentAlignments} />
23
+
24
+ ### Basic Usage
25
+
26
+ ```vue
27
+ <script setup>
28
+ import { ref } from 'vue'
29
+
30
+ const isOpen = ref(false)
31
+ </script>
32
+
33
+ <template>
34
+ <TelaPopover v-model:open="isOpen">
35
+ <TelaPopoverTrigger>
36
+ <TelaButton>Open Popover</TelaButton>
37
+ </TelaPopoverTrigger>
38
+ <TelaPopoverContent>
39
+ <div class="p-4">
40
+ <h3>Popover Content</h3>
41
+ <p>This is the popover content</p>
42
+ </div>
43
+ </TelaPopoverContent>
44
+ </TelaPopover>
45
+ </template>
46
+ ```
47
+
48
+ ### With Custom Content Code
49
+
50
+ ```vue
51
+ <TelaPopover v-model:open="isOpen">
52
+ <TelaPopoverTrigger>
53
+ <TelaButton>Options</TelaButton>
54
+ </TelaPopoverTrigger>
55
+ <TelaPopoverContent>
56
+ <div class="flex flex-col gap-2 p-2">
57
+ <button class="p-2 hover:bg-gray-100 rounded">
58
+ Option 1
59
+ </button>
60
+ <button class="p-2 hover:bg-gray-100 rounded">
61
+ Option 2
62
+ </button>
63
+ <button class="p-2 hover:bg-gray-100 rounded">
64
+ Option 3
65
+ </button>
66
+ </div>
67
+ </TelaPopoverContent>
68
+ </TelaPopover>
69
+ ```
70
+
71
+ ### Different Positions Code
72
+
73
+ ```vue
74
+ <!-- Top -->
75
+ <TelaPopover>
76
+ <TelaPopoverTrigger>
77
+ <TelaButton>Top</TelaButton>
78
+ </TelaPopoverTrigger>
79
+ <TelaPopoverContent side="top">
80
+ Popover on top
81
+ </TelaPopoverContent>
82
+ </TelaPopover>
83
+
84
+ <!-- Right -->
85
+ <TelaPopover>
86
+ <TelaPopoverTrigger>
87
+ <TelaButton>Right</TelaButton>
88
+ </TelaPopoverTrigger>
89
+ <TelaPopoverContent side="right">
90
+ Popover on right
91
+ </TelaPopoverContent>
92
+ </TelaPopover>
93
+
94
+ <!-- Bottom (default) -->
95
+ <TelaPopover>
96
+ <TelaPopoverTrigger>
97
+ <TelaButton>Bottom</TelaButton>
98
+ </TelaPopoverTrigger>
99
+ <TelaPopoverContent side="bottom">
100
+ Popover on bottom
101
+ </TelaPopoverContent>
102
+ </TelaPopover>
103
+
104
+ <!-- Left -->
105
+ <TelaPopover>
106
+ <TelaPopoverTrigger>
107
+ <TelaButton>Left</TelaButton>
108
+ </TelaPopoverTrigger>
109
+ <TelaPopoverContent side="left">
110
+ Popover on left
111
+ </TelaPopoverContent>
112
+ </TelaPopover>
113
+ ```
114
+
115
+ ```vue
116
+ <!-- Align Start -->
117
+ <TelaPopover>
118
+ <TelaPopoverTrigger>
119
+ <TelaButton>Start</TelaButton>
120
+ </TelaPopoverTrigger>
121
+ <TelaPopoverContent align="start">
122
+ Aligned to start
123
+ </TelaPopoverContent>
124
+ </TelaPopover>
125
+
126
+ <!-- Align Center (default) -->
127
+ <TelaPopover>
128
+ <TelaPopoverTrigger>
129
+ <TelaButton>Center</TelaButton>
130
+ </TelaPopoverTrigger>
131
+ <TelaPopoverContent align="center">
132
+ Aligned to center
133
+ </TelaPopoverContent>
134
+ </TelaPopover>
135
+
136
+ <!-- Align End -->
137
+ <TelaPopover>
138
+ <TelaPopoverTrigger>
139
+ <TelaButton>End</TelaButton>
140
+ </TelaPopoverTrigger>
141
+ <TelaPopoverContent align="end">
142
+ Aligned to end
143
+ </TelaPopoverContent>
144
+ </TelaPopover>
145
+ ```
146
+
147
+ ### With Side Offset
148
+
149
+ ```vue
150
+ <TelaPopover>
151
+ <TelaPopoverTrigger>
152
+ <TelaButton>With Offset</TelaButton>
153
+ </TelaPopoverTrigger>
154
+ <TelaPopoverContent :side-offset="20">
155
+ Popover with 20px offset
156
+ </TelaPopoverContent>
157
+ </TelaPopover>
158
+ ```
159
+
160
+ ### Form in Popover
161
+
162
+ ```vue
163
+ <TelaPopover v-model:open="isOpen">
164
+ <TelaPopoverTrigger>
165
+ <TelaButton>Add Item</TelaButton>
166
+ </TelaPopoverTrigger>
167
+ <TelaPopoverContent>
168
+ <form @submit.prevent="onSubmit" class="p-4 w-300px">
169
+ <h3 class="text-lg font-medium mb-4">Add New Item</h3>
170
+ <TelaInput label="Name" v-model="name" class="mb-3" />
171
+ <TelaTextarea label="Description" v-model="description" class="mb-4" />
172
+ <div class="flex gap-2 justify-end">
173
+ <TelaButton variant="secondary" @click="isOpen = false">
174
+ Cancel
175
+ </TelaButton>
176
+ <TelaButton type="submit" variant="primary">
177
+ Add
178
+ </TelaButton>
179
+ </div>
180
+ </form>
181
+ </TelaPopoverContent>
182
+ </TelaPopover>
183
+ ```
184
+
185
+ ## Props
186
+
187
+ <ArgTypes />
188
+
189
+ ```typescript
190
+ type PopoverSide = 'top' | 'right' | 'bottom' | 'left'
191
+ type PopoverAlign = 'start' | 'center' | 'end'
192
+
193
+ type PopoverProps = {
194
+ open?: boolean
195
+ side?: PopoverSide
196
+ align?: PopoverAlign
197
+ sideOffset?: number
198
+ ariaLabel?: string
199
+ }
200
+ ```
201
+
202
+ ## Components
203
+
204
+ - `TelaPopover` - Root popover container
205
+ - `TelaPopoverTrigger` - Trigger button/element
206
+ - `TelaPopoverContent` - Content panel
207
+
208
+ ## Features
209
+
210
+ - **Flexible Positioning**: All sides and alignments
211
+ - **Click to Open**: Opens on click (vs hover for tooltip)
212
+ - **Click Outside to Close**: Closes when clicking outside
213
+ - **Escape Key**: Press Escape to close
214
+ - **Custom Content**: Full control over popover content
215
+ - **Side Offset**: Control distance from trigger
216
+ - **Accessible**: Built on reka-ui with proper ARIA
217
+ - **Portal Rendering**: Renders in portal to avoid z-index issues
218
+
219
+ ## Popover vs Tooltip
220
+
221
+ - **Popover**: Click to open, rich interactive content
222
+ - **Tooltip**: Hover to show, brief informational text
223
+
224
+ ## Best Practices
225
+
226
+ 1. **Use for Actions**: Popovers are for interactive content
227
+ 2. **Keep Content Focused**: Don't overload with too much content
228
+ 3. **Provide Close Option**: Ensure users can close easily
229
+ 4. **Position Wisely**: Ensure popover doesn't cover important UI
230
+ 5. **Mobile Friendly**: Popovers work better than tooltips on touch
231
+
232
+ ## Accessibility
233
+
234
+ - Built on reka-ui primitives
235
+ - Proper ARIA attributes (role="dialog")
236
+ - Keyboard navigation (Escape to close)
237
+ - Focus management
238
+ - Click outside to close
239
+ - Screen reader support
@@ -0,0 +1,150 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import { fn } from '@storybook/test'
3
+ import Popover from './popover.vue'
4
+ import PopoverTrigger from './popover-trigger.vue'
5
+ import PopoverContent from './popover-content.vue'
6
+
7
+ const meta: Meta<typeof Popover> = {
8
+ title: 'Core/Popover',
9
+ component: Popover,
10
+ subcomponents: { PopoverTrigger, PopoverContent },
11
+ parameters: {
12
+ layout: 'centered',
13
+ docs: {
14
+ description: {
15
+ component: 'A popover component that displays content in a floating panel. Supports positioning on all sides (top, right, bottom, left) with different alignments (start, center, end). Built with composable subcomponents for flexible usage.',
16
+ },
17
+ },
18
+ },
19
+ argTypes: {
20
+ open: {
21
+ control: 'boolean',
22
+ description: 'Controls the open state of the popover. Use v-model:open for two-way binding.',
23
+ },
24
+ side: {
25
+ control: 'select',
26
+ options: ['top', 'right', 'bottom', 'left'],
27
+ description: 'Side of the trigger element where the popover should appear.',
28
+ },
29
+ align: {
30
+ control: 'select',
31
+ options: ['start', 'center', 'end'],
32
+ description: 'Alignment of the popover content relative to the trigger element.',
33
+ },
34
+ sideOffset: {
35
+ control: 'number',
36
+ description: 'Distance in pixels from the trigger element to the popover content.',
37
+ },
38
+ ariaLabel: {
39
+ control: 'text',
40
+ description: 'Accessibility label for the popover trigger element.',
41
+ },
42
+ },
43
+ args: {
44
+ 'onUpdate:open': fn(),
45
+ 'side': 'bottom',
46
+ 'align': 'center',
47
+ 'ariaLabel': 'Popover trigger',
48
+ } as any,
49
+ }
50
+
51
+ export default meta
52
+
53
+ type Story = StoryObj<typeof meta>
54
+
55
+ export const Default: Story = {
56
+ render: args => ({
57
+ components: { Popover, PopoverTrigger, PopoverContent },
58
+ setup() {
59
+ const isOpen = ref(false)
60
+ return { args, isOpen }
61
+ },
62
+ template: `
63
+ <div style="padding: 100px; display: flex; justify-content: center;">
64
+ <Popover v-model:open="isOpen" v-bind="args">
65
+ <PopoverTrigger>
66
+ <button>Click me</button>
67
+ </PopoverTrigger>
68
+ <PopoverContent>
69
+ <h3 class="text-lg font-medium">Popover Content</h3>
70
+ <p class="mt-2">This is the content of the popover.</p>
71
+ </PopoverContent>
72
+ </Popover>
73
+ </div>
74
+ `,
75
+ }),
76
+ }
77
+
78
+ export const WithCustomContent: Story = {
79
+ render: args => ({
80
+ components: { Popover, PopoverTrigger, PopoverContent },
81
+ setup() {
82
+ const isOpen = ref(false)
83
+ return { args, isOpen }
84
+ },
85
+ template: `
86
+ <div style="padding: 100px; display: flex; justify-content: center;">
87
+ <Popover v-model:open="isOpen" v-bind="args">
88
+ <PopoverTrigger>
89
+ <button class="px-4 py-2 bg-blue-500 text-white rounded">
90
+ Hover me
91
+ </button>
92
+ </PopoverTrigger>
93
+ <PopoverContent>
94
+ <div class="flex flex-col gap-2">
95
+ <button class="p-2 hover:bg-gray-100 rounded">Option 1</button>
96
+ <button class="p-2 hover:bg-gray-100 rounded">Option 2</button>
97
+ <button class="p-2 hover:bg-gray-100 rounded">Option 3</button>
98
+ </div>
99
+ </PopoverContent>
100
+ </Popover>
101
+ </div>
102
+ `,
103
+ }),
104
+ }
105
+
106
+ export const WithDifferentPositions: Story = {
107
+ render: args => ({
108
+ components: { Popover, PopoverTrigger, PopoverContent },
109
+ setup() {
110
+ return { args }
111
+ },
112
+ template: `
113
+ <div style="padding: 100px; display: flex; gap: 100px; justify-content: center; flex-wrap: wrap;">
114
+ <Popover v-for="side in ['top', 'right', 'bottom', 'left']" :key="side" v-bind="args">
115
+ <PopoverTrigger>
116
+ <button class="px-4 py-2 bg-gray-200 rounded">
117
+ {{ side }}
118
+ </button>
119
+ </PopoverTrigger>
120
+ <PopoverContent :side="side">
121
+ Popover on {{ side }}
122
+ </PopoverContent>
123
+ </Popover>
124
+ </div>
125
+ `,
126
+ }),
127
+ }
128
+
129
+ export const WithDifferentAlignments: Story = {
130
+ render: args => ({
131
+ components: { Popover, PopoverTrigger, PopoverContent },
132
+ setup() {
133
+ return { args }
134
+ },
135
+ template: `
136
+ <div style="padding: 100px; display: flex; gap: 100px; justify-content: center; flex-wrap: wrap;">
137
+ <Popover v-for="align in ['start', 'center', 'end']" :key="align" v-bind="args">
138
+ <PopoverTrigger>
139
+ <button class="px-4 py-2 bg-gray-200 rounded">
140
+ {{ align }}
141
+ </button>
142
+ </PopoverTrigger>
143
+ <PopoverContent :align="align">
144
+ Popover on {{ align }}
145
+ </PopoverContent>
146
+ </Popover>
147
+ </div>
148
+ `,
149
+ }),
150
+ }
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import type { PopoverRootEmits, PopoverRootProps } from 'reka-ui'
3
+ import { PopoverRoot, useForwardPropsEmits } from 'reka-ui'
4
+
5
+ const props = defineProps<PopoverRootProps>()
6
+ const emits = defineEmits<PopoverRootEmits>()
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits)
9
+ </script>
10
+
11
+ <template>
12
+ <PopoverRoot v-bind="forwarded">
13
+ <slot />
14
+ </PopoverRoot>
15
+ </template>
@@ -0,0 +1,104 @@
1
+ <script setup lang="ts" generic="T">
2
+ interface PopoverListNestedProps<T> {
3
+ items: T[]
4
+ depth?: number
5
+ variant?: 'attributes' | 'detailed'
6
+ hasChildrenFn: (item: T) => boolean
7
+ getChildrenFn: (item: T) => T[]
8
+ }
9
+
10
+ const props = defineProps<PopoverListNestedProps<T>>()
11
+
12
+ function getNestedItemName(item: T): string {
13
+ if (typeof item === 'object' && item !== null) {
14
+ const obj = item as any
15
+ return obj.name || obj.id || 'Item'
16
+ }
17
+ return String(item)
18
+ }
19
+
20
+ function getNestedItemValue(item: T): any {
21
+ if (typeof item === 'object' && item !== null) {
22
+ const obj = item as any
23
+ const value = obj.value !== undefined ? obj.value : item
24
+
25
+ // Se o valor é um objeto complexo, não exibir no modo detailed
26
+ if (typeof value === 'object' && value !== null) {
27
+ return null
28
+ }
29
+
30
+ return value
31
+ }
32
+ return item
33
+ }
34
+
35
+ function shouldShowValue(item: T): boolean {
36
+ const value = getNestedItemValue(item)
37
+ return value !== null && value !== undefined
38
+ }
39
+
40
+ const textStyle = computed(() => props.depth
41
+ ? 'text-gray-300 text-[11px] tracking-[-0.022px]'
42
+ : 'text-[#EFF1F3] text-[12px] tracking-[-0.024px]')
43
+ </script>
44
+
45
+ <template>
46
+ <div v-for="(item, index) in items" :key="`${getNestedItemName(item)}-${index}`">
47
+ <!-- Detailed variant -->
48
+ <div v-if="getNestedItemName(item) && variant === 'detailed'" class="flex flex-col items-start self-stretch pb-8px rounded-md p-1">
49
+ <span class="text-white text-[12px] font-semibold">
50
+ <slot name="item" :item="item" :index="index" :depth="depth">
51
+ {{ getNestedItemName(item) }}
52
+ </slot>
53
+ </span>
54
+ <span v-if="shouldShowValue(item)" class="text-[#BDC4CC] text-[12px]">
55
+ {{ getNestedItemValue(item) }}
56
+ </span>
57
+ </div>
58
+
59
+ <!-- Detailed variant without name -->
60
+ <div v-else-if="variant === 'detailed' && !getNestedItemName(item)" class="flex flex-col items-start self-stretch pb-8px rounded-md p-1">
61
+ <span v-if="shouldShowValue(item)" class="text-[#BDC4CC] text-[12px]">
62
+ <slot name="item" :item="item" :index="index" :depth="depth">
63
+ {{ getNestedItemValue(item) }}
64
+ </slot>
65
+ </span>
66
+ <span v-else class="text-[#BDC4CC] text-[12px]">
67
+ No value yet
68
+ </span>
69
+ </div>
70
+
71
+ <!-- Attributes variant -->
72
+ <div v-if="getNestedItemName(item) && variant === 'attributes'" class="flex items-center gap-4px self-stretch py-2px rounded-md px-1">
73
+ <div class="w-2 h-2 rounded-full flex py-[2px] items-center gap-4px self-stretch">
74
+ <svg width="6" height="8" viewBox="0 0 6 8" fill="none" xmlns="http://www.w3.org/2000/svg">
75
+ <g id="ColorArea">
76
+ <circle id="Color" cx="2" cy="5" r="2" fill="#8BA5FF" />
77
+ </g>
78
+ </svg>
79
+ </div>
80
+ <p class="text-justify font-inter font-medium leading-[12px] max-w-[150px] truncate text-ellipsis" :class="[textStyle]">
81
+ <slot name="item" :item="item" :index="index" :depth="depth">
82
+ {{ getNestedItemName(item) }}
83
+ </slot>
84
+ </p>
85
+ </div>
86
+
87
+ <!-- Nested children -->
88
+ <template v-if="hasChildrenFn(item)">
89
+ <div class="pl-4">
90
+ <PopoverListNested
91
+ :items="getChildrenFn(item)"
92
+ :depth="(depth ?? 0) + 1"
93
+ :variant="variant"
94
+ :has-children-fn="hasChildrenFn"
95
+ :get-children-fn="getChildrenFn"
96
+ >
97
+ <template #item="slotProps: any">
98
+ <slot name="item" v-bind="slotProps" />
99
+ </template>
100
+ </PopoverListNested>
101
+ </div>
102
+ </template>
103
+ </div>
104
+ </template>