@meistrari/tela-build 1.51.0 → 1.52.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.
@@ -4,7 +4,6 @@ import TelaAvatarLabel from './avatar-label.vue'
4
4
  const meta = {
5
5
  title: 'Core/AvatarLabel',
6
6
  component: TelaAvatarLabel,
7
- tags: ['autodocs'],
8
7
  parameters: {
9
8
  layout: 'centered',
10
9
  docs: {
@@ -1,5 +1,4 @@
1
1
  <script lang="ts" setup>
2
- import { DialogClose } from 'radix-vue'
3
2
  import TelaModal from '../modal/modal.vue'
4
3
  import TelaButton from '../button/button.vue'
5
4
 
@@ -20,11 +19,6 @@ const emit = defineEmits<{
20
19
 
21
20
  const open = defineModel<boolean>('open')
22
21
 
23
- function handleCloseClick() {
24
- emit('cancel')
25
- open.value = false
26
- }
27
-
28
22
  const confirmButtonVariant = computed(() => {
29
23
  return props.variant === 'danger' ? 'danger' : 'primary'
30
24
  })
@@ -35,36 +29,24 @@ const confirmButtonVariant = computed(() => {
35
29
  v-model:model-value="open"
36
30
  :compact="props.compact ?? true"
37
31
  hide-dividers
32
+ :is-close-icon="false"
33
+ :style="{ paddingBlock: '20px' }"
38
34
  @close="emit('cancel')"
39
35
  >
40
- <template #actions>
41
- <DialogClose as-child>
42
- <TelaIconButton
43
- absolute
44
- top-8px
45
- right-8px
46
- icon="i-ph-x"
47
- size="md"
48
- color="secondary"
49
- outline-none
50
- @click="handleCloseClick"
51
- />
52
- </DialogClose>
53
- </template>
54
36
  <div flex="~ col" w-400px>
55
37
  <h6 body-20-semibold text-gray-900>
56
38
  {{ props.title }}
57
39
  </h6>
58
- <div body-16-regular text-gray-700 mt-8px>
40
+ <div body-16-regular text-gray-700 mt-4px>
59
41
  <slot />
60
42
  </div>
61
43
  </div>
62
44
  <template #footer>
63
45
  <div flex="~" gap-8px w-full justify-between>
64
- <TelaButton :disabled="props.loading" size="lg" variant="secondary" @click="emit('cancel')">
46
+ <TelaButton :disabled="props.loading" size="lg" variant="secondary" flex-1 whitespace-nowrap @click="emit('cancel')">
65
47
  {{ props.cancelButtonText ?? 'Cancel' }}
66
48
  </TelaButton>
67
- <TelaButton :loading="props.loading" size="lg" :variant="confirmButtonVariant" :data-testid="props.confirmButtonTestId" @click="emit('confirm')">
49
+ <TelaButton :loading="props.loading" size="lg" :variant="confirmButtonVariant" :data-testid="props.confirmButtonTestId" flex-1 whitespace-nowrap @click="emit('confirm')">
68
50
  {{ props.confirmButtonText ?? 'Confirm' }}
69
51
  </TelaButton>
70
52
  </div>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps<{
3
+ disabled?: boolean
4
+ }>()
5
+
6
+ const emit = defineEmits<{
7
+ filesDropped: [list: File[]]
8
+ }>()
9
+
10
+ const active = ref(false)
11
+ let inActiveTimeout: ReturnType<typeof setTimeout> | null = null
12
+
13
+ // setActive and setInactive use timeouts, so that when you drag an item over a child element,
14
+ // the dragleave event that is fired won't cause a flicker. A few ms should be plenty of
15
+ // time to wait for the next dragenter event to clear the timeout and set it back to active.
16
+ function setActive() {
17
+ if (props.disabled)
18
+ return
19
+ active.value = true
20
+ if (inActiveTimeout)
21
+ clearTimeout(inActiveTimeout)
22
+ }
23
+ function setInactive() {
24
+ inActiveTimeout = setTimeout(() => {
25
+ active.value = false
26
+ }, 50)
27
+ }
28
+
29
+ function onDrop(e: DragEvent) {
30
+ setInactive()
31
+ if (props.disabled)
32
+ return
33
+ if (!e.dataTransfer?.files)
34
+ return
35
+ emit('filesDropped', [...e.dataTransfer.files])
36
+ }
37
+ </script>
38
+
39
+ <template>
40
+ <div
41
+ :data-active="active"
42
+ @dragenter.prevent.stop="setActive"
43
+ @dragover.prevent.stop="setActive"
44
+ @dragleave.prevent.stop="setInactive"
45
+ @drop.prevent.stop="onDrop"
46
+ >
47
+ <slot :drop-zone-active="active" />
48
+ </div>
49
+ </template>
@@ -16,10 +16,12 @@ const props = withDefaults(defineProps<{
16
16
  label: string
17
17
  icon?: string
18
18
  iconSide?: 'left' | 'right'
19
+ trailingIcon?: string
19
20
  group?: string
20
21
  color?: 'positive' | 'caution' | 'negative'
21
22
  click: () => void
22
23
  disabled?: boolean
24
+ preventClose?: boolean
23
25
  checkbox?: {
24
26
  modelValue: boolean
25
27
  onChange: (value: boolean) => void
@@ -34,6 +36,8 @@ const props = withDefaults(defineProps<{
34
36
  triggerClass?: HTMLAttributes['class']
35
37
  contentClass?: HTMLAttributes['class']
36
38
  align?: 'start' | 'end' | 'center'
39
+ labelClass?: string
40
+ defaultOpen?: boolean
37
41
  }>(), {
38
42
  align: 'start',
39
43
  iconSide: 'left',
@@ -70,7 +74,7 @@ function onToggle(open: boolean) {
70
74
 
71
75
  <template>
72
76
  <div data-allow-mismatch @click.stop>
73
- <DropdownMenuRoot :modal="shouldBeModal" :default-open="isStorybook" @update:open="onToggle">
77
+ <DropdownMenuRoot :modal="shouldBeModal" :default-open="defaultOpen" @update:open="onToggle">
74
78
  <DropdownMenuTrigger as-child :class="cn('data-[state=open]:bg-muted', triggerClass)" @click.prevent.stop>
75
79
  <slot />
76
80
  <VisuallyHidden v-if="isStorybook" as-child>
@@ -83,6 +87,8 @@ function onToggle(open: boolean) {
83
87
  :side-offset="sideOffset"
84
88
  :class="cn('min-w-128px! z-605!', contentClass)"
85
89
  >
90
+ <slot name="header" />
91
+
86
92
  <div v-if="allowSearch" flex="~" items-center px-8px py-6px>
87
93
  <TelaIcon name="i-ph-magnifying-glass-bold" text-gray-800 mr-6px />
88
94
  <input
@@ -111,16 +117,25 @@ function onToggle(open: boolean) {
111
117
  :disabled="item.disabled"
112
118
  :icon="item.icon"
113
119
  :icon-side="item.iconSide"
120
+ :trailing-icon="item.trailingIcon"
114
121
  :color="item.color"
115
122
  :checkbox="item.checkbox"
116
123
  :tooltip="item.tooltip"
117
124
  :data-testid="item.testId"
125
+ :label-class="labelClass"
126
+ @select="(event: Event) => {
127
+ if (item.preventClose) {
128
+ event.preventDefault()
129
+ }
130
+ }"
118
131
  @click="item.click"
119
132
  >
120
- <span>{{ item.label }}</span>
133
+ {{ item.label }}
121
134
  </DropdownMenuItem>
122
135
  </DropdownMenuGroup>
123
136
  </template>
137
+
138
+ <slot name="footer" />
124
139
  </DropdownMenuContent>
125
140
  </DropdownMenuRoot>
126
141
  </div>
@@ -7,9 +7,11 @@ import type { TooltipProps } from '../tooltip/tooltip.vue'
7
7
 
8
8
  const props = defineProps<DropdownMenuItemProps & {
9
9
  class?: HTMLAttributes['class']
10
+ labelClass?: HTMLAttributes['class']
10
11
  inset?: boolean
11
12
  icon?: string
12
13
  iconSide?: 'left' | 'right'
14
+ trailingIcon?: string
13
15
  iconWithBackground?: {
14
16
  name: string
15
17
  size?: string
@@ -105,7 +107,7 @@ const isIconImage = computed(() => {
105
107
  <TelaIcon v-else-if="icon" :name="icon" :class="getIconClasses(props.color)" />
106
108
  <TelaIcon v-else-if="iconWithBackground" :name="iconWithBackground.name" :size="iconWithBackground.size" :background-class="iconWithBackground.backgroundClass" :class="getIconClasses(props.color)" />
107
109
  <TelaCheckbox v-else-if="checkbox" :model-value="checkbox?.modelValue" @update:model-value="(value) => checkbox?.onChange(value === true)" />
108
- <span text-body-14-medium font-460 :class="getItemClasses(props.color)">
110
+ <span text-body-14-medium font-460 :class="cn(getItemClasses(props.color), labelClass)">
109
111
  <slot />
110
112
  </span>
111
113
  </DropdownMenuItem>
@@ -127,10 +129,11 @@ const isIconImage = computed(() => {
127
129
  <TelaIcon v-else-if="icon && (!iconSide || iconSide === 'left')" :name="icon" :class="getIconClasses(props.color)" />
128
130
  <TelaIcon v-else-if="iconWithBackground" :name="iconWithBackground.name" :size="iconWithBackground.size" :background-class="iconWithBackground.backgroundClass" :class="getIconClasses(props.color)" />
129
131
  <TelaCheckbox v-else-if="checkbox" :model-value="checkbox?.modelValue" @update:model-value="(value) => checkbox?.onChange(value === true)" />
130
- <span text-body-14-medium font-460 :class="getItemClasses(props.color)">
132
+ <span text-body-14-medium font-460 :class="cn(getItemClasses(props.color), labelClass)">
131
133
  <slot />
132
134
  </span>
133
135
  <img v-if="icon && iconSide === 'right' && isIconImage" :src="icon" :class="cn('size-16px')">
134
136
  <TelaIcon v-else-if="icon && iconSide === 'right'" :name="icon" />
137
+ <TelaIcon v-else-if="trailingIcon" :name="trailingIcon" color="gray-400" size="14px" ml-auto />
135
138
  </DropdownMenuItem>
136
139
  </template>
@@ -44,6 +44,13 @@ const meta: Meta<typeof DropdownMenu> = {
44
44
  options: ['start', 'end', 'center'],
45
45
  description: 'Alignment of the dropdown menu relative to the trigger element.',
46
46
  },
47
+ defaultOpen: {
48
+ control: 'boolean',
49
+ description: 'Whether the dropdown menu starts open when mounted.',
50
+ },
51
+ },
52
+ args: {
53
+ defaultOpen: true,
47
54
  },
48
55
  }
49
56
 
@@ -6,7 +6,6 @@ import type { FilterConfig, FilterSelections } from './filter.vue'
6
6
  const meta: Meta<typeof Filter> = {
7
7
  title: 'Filters/Filter',
8
8
  component: Filter,
9
- tags: ['autodocs'],
10
9
  parameters: {
11
10
  layout: 'centered',
12
11
  docs: {
@@ -6,14 +6,11 @@ const props = defineProps<{
6
6
  </script>
7
7
 
8
8
  <template>
9
- <a
10
- v-if="props.href"
9
+ <component
10
+ :is="props.href ? 'a' : 'span'"
11
11
  :href="props.href"
12
12
  :class="cn('text-gray-900 underline underline-offset-3px', props.class)"
13
13
  >
14
14
  <slot />
15
- </a>
16
- <span v-else :class="cn('text-gray-900 underline underline-offset-3px', props.class)">
17
- <slot />
18
- </span>
15
+ </component>
19
16
  </template>