@meistrari/tela-build 1.52.0 → 1.52.2
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.
- package/components/tela/button/button.vue +48 -25
- package/components/tela/combobox/combobox-group.vue +1 -1
- package/components/tela/combobox/combobox-indicator.vue +1 -1
- package/components/tela/combobox/combobox-input.vue +16 -6
- package/components/tela/combobox/combobox-item.vue +1 -1
- package/components/tela/combobox/combobox-label.vue +1 -1
- package/components/tela/combobox/combobox-list.vue +2 -12
- package/components/tela/combobox/combobox-module-selector.vue +6 -16
- package/components/tela/combobox/combobox-trigger.vue +20 -2
- package/components/tela/combobox/combobox.stories.ts +3 -3
- package/components/tela/combobox/combobox.vue +157 -305
- package/components/tela/icon-button/icon-button.vue +10 -10
- package/components/tela/preview/preview-select-variable.vue +10 -22
- package/components/tela/tabs/tabs-trigger.vue +13 -3
- package/components/tela/tabs/tabs.mdx +13 -0
- package/docs/tokens.md +8 -1
- package/modules/tela-build-docs/__tests__/ensure-claude-symlink.test.ts +53 -4
- package/modules/tela-build-docs/index.ts +56 -4
- package/package.json +1 -1
- package/unocss.config.ts +4 -4
- package/utils/design-tokens.ts +68 -36
|
@@ -25,40 +25,50 @@ const resolvedVariant = computed(() =>
|
|
|
25
25
|
|| 'primary',
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
+
const slots = useSlots()
|
|
29
|
+
|
|
30
|
+
const hasLeadingIcon = computed(() => !!((props.loading && props.leading) || slots.leading || (props.icon && props.leading)))
|
|
31
|
+
const hasTrailingIcon = computed(() => !!((props.loading && !props.leading) || slots.trailing || (props.icon && !props.leading)))
|
|
32
|
+
|
|
28
33
|
const sizeStyle = computed(() => (({
|
|
29
|
-
sm: 'text-12px leading-16px
|
|
30
|
-
md: 'text-14px leading-18px
|
|
31
|
-
lg: 'text-16px leading-20px
|
|
34
|
+
sm: '[--padding-x:10px] text-[12px] leading-[16px] tracking-normal py-[4px] rounded-[9px]',
|
|
35
|
+
md: '[--padding-x:12px] text-[14px] leading-[18px] -tracking-[0.15px] py-[7px] rounded-[11px]',
|
|
36
|
+
lg: '[--padding-x:16px] text-[16px] leading-[20px] -tracking-[0.15px] py-[10px] rounded-[13px]',
|
|
32
37
|
}) as Record<ButtonSize, string>)[resolvedSize.value] ?? '')
|
|
33
38
|
|
|
39
|
+
const paddingStyle = computed(() => [
|
|
40
|
+
hasLeadingIcon.value ? 'pl-[calc(var(--padding-x)_-_2px)]' : 'pl-[var(--padding-x)]',
|
|
41
|
+
hasTrailingIcon.value ? 'pr-[calc(var(--padding-x)_-_2px)]' : 'pr-[var(--padding-x)]',
|
|
42
|
+
].join(' '))
|
|
43
|
+
|
|
34
44
|
const variantStyle = computed(() => (({
|
|
35
45
|
'primary': fold`
|
|
36
|
-
bg-
|
|
37
|
-
hover:bg-
|
|
38
|
-
active:bg-
|
|
46
|
+
bg-btn-primary text-inverse
|
|
47
|
+
hover:bg-btn-primary-hover
|
|
48
|
+
active:bg-btn-primary-active
|
|
39
49
|
focus-visible:ring-0.5px focus-visible:ring-cyan-600
|
|
40
50
|
`,
|
|
41
51
|
'secondary': fold`
|
|
42
|
-
bg-
|
|
52
|
+
bg-btn-secondary text-contrast border border-0.5px
|
|
43
53
|
[box-shadow:0_1px_6px_0_rgba(103,127,148,0.05)]
|
|
44
|
-
hover:bg-
|
|
45
|
-
active:bg-
|
|
54
|
+
hover:bg-btn-secondary-hover hover:border-strong
|
|
55
|
+
active:bg-btn-secondary-active active:border-neutral-400/60
|
|
46
56
|
focus-visible:ring-0.5px focus-visible:ring-cyan-600
|
|
47
57
|
`,
|
|
48
58
|
'ghost': fold`
|
|
49
|
-
bg-
|
|
50
|
-
hover:bg-
|
|
59
|
+
bg-btn-ghost text-contrast
|
|
60
|
+
hover:bg-btn-ghost-hover
|
|
51
61
|
focus-visible:ring-0.5px focus-visible:ring-cyan-600
|
|
52
62
|
`,
|
|
53
63
|
'disabled': fold`
|
|
54
|
-
bg-
|
|
64
|
+
bg-btn-disabled text-tertiary !cursor-not-allowed
|
|
55
65
|
`,
|
|
56
66
|
'loading': fold`
|
|
57
|
-
bg-
|
|
67
|
+
bg-btn-loading text-neutral-600
|
|
58
68
|
`,
|
|
59
69
|
'danger': fold`
|
|
60
|
-
bg-
|
|
61
|
-
hover:bg-
|
|
70
|
+
bg-btn-danger text-red-500
|
|
71
|
+
hover:bg-btn-danger-hover
|
|
62
72
|
focus:outline-red-600
|
|
63
73
|
`,
|
|
64
74
|
'ghost-danger': fold`
|
|
@@ -67,14 +77,26 @@ const variantStyle = computed(() => (({
|
|
|
67
77
|
focus:outline-red-600
|
|
68
78
|
`,
|
|
69
79
|
'dark': fold`
|
|
70
|
-
bg-
|
|
71
|
-
hover:bg-
|
|
80
|
+
bg-btn-dark text-white border-0.5px border-white/16
|
|
81
|
+
hover:bg-btn-dark-hover active:bg-btn-dark-active
|
|
72
82
|
focus-visible:ring-0.5px focus-visible:ring-cyan-600
|
|
73
83
|
`,
|
|
74
84
|
}) as Record<ButtonVariant | 'disabled' | 'loading', string>)[resolvedVariant.value] ?? '')
|
|
75
85
|
|
|
86
|
+
const iconColorStyle = computed(() => (({
|
|
87
|
+
'primary': 'icon-inverse',
|
|
88
|
+
'secondary': 'icon-secondary',
|
|
89
|
+
'ghost': 'icon-secondary',
|
|
90
|
+
'disabled': 'icon-subtle',
|
|
91
|
+
'loading': 'icon-tertiary',
|
|
92
|
+
'danger': 'red-500',
|
|
93
|
+
'ghost-danger': 'red-700',
|
|
94
|
+
'dark': 'icon-subtle',
|
|
95
|
+
}) as Record<ButtonVariant | 'disabled' | 'loading', string>)[resolvedVariant.value] ?? '')
|
|
96
|
+
|
|
76
97
|
const resolvedStyle = computed(() => [
|
|
77
98
|
sizeStyle.value,
|
|
99
|
+
paddingStyle.value,
|
|
78
100
|
variantStyle.value,
|
|
79
101
|
].join(' '))
|
|
80
102
|
|
|
@@ -100,19 +122,20 @@ const iconSize = computed(() => {
|
|
|
100
122
|
<component
|
|
101
123
|
:is="tag"
|
|
102
124
|
:to="to"
|
|
103
|
-
:class="
|
|
125
|
+
:class="cn(
|
|
126
|
+
'box-border font-540 select-none flex items-center justify-center gap-6px ease-out duration-40',
|
|
127
|
+
disabled ? 'cursor-not-allowed' : 'cursor-pointer',
|
|
128
|
+
resolvedStyle,
|
|
129
|
+
)"
|
|
104
130
|
:disabled="disabled"
|
|
105
|
-
:cursor="disabled ? 'not-allowed' : 'pointer'"
|
|
106
131
|
:target="target"
|
|
107
|
-
border-box
|
|
108
|
-
select-none
|
|
109
132
|
>
|
|
110
|
-
<TelaIconSpinner v-if="loading && leading" animate-spin />
|
|
133
|
+
<TelaIconSpinner v-if="loading && leading" class="animate-spin" />
|
|
111
134
|
<slot v-else-if="$slots.leading" name="leading" />
|
|
112
|
-
<TelaIcon v-else-if="icon && leading" :name="icon" :size="iconSize" min-h-14px min-w-14px />
|
|
135
|
+
<TelaIcon v-else-if="icon && leading" :name="icon" :size="iconSize" :color="iconColorStyle" class="min-h-14px min-w-14px" />
|
|
113
136
|
<slot />
|
|
114
|
-
<TelaIconSpinner v-if="loading && !leading" animate-spin
|
|
137
|
+
<TelaIconSpinner v-if="loading && !leading" class="animate-spin min-h-14px min-w-14px" />
|
|
115
138
|
<slot v-else-if="$slots.trailing" name="trailing" />
|
|
116
|
-
<TelaIcon v-else-if="icon && !leading" :name="icon" :size="iconSize" />
|
|
139
|
+
<TelaIcon v-else-if="icon && !leading" :name="icon" :size="iconSize" :color="iconColorStyle" class="min-h-14px min-w-14px" />
|
|
117
140
|
</component>
|
|
118
141
|
</template>
|
|
@@ -15,7 +15,7 @@ const delegatedProps = reactiveOmit(props, 'class')
|
|
|
15
15
|
<template>
|
|
16
16
|
<ComboboxGroup
|
|
17
17
|
v-bind="delegatedProps"
|
|
18
|
-
:class="cn('overflow-hidden
|
|
18
|
+
:class="cn('overflow-hidden p-[4px]', props.class)"
|
|
19
19
|
>
|
|
20
20
|
<slot />
|
|
21
21
|
</ComboboxGroup>
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
} from 'reka-ui'
|
|
9
9
|
import type { ComboboxInputEmits, ComboboxInputProps } from 'reka-ui'
|
|
10
10
|
|
|
11
|
+
defineOptions({ inheritAttrs: false })
|
|
12
|
+
|
|
11
13
|
const props = defineProps<ComboboxInputProps & {
|
|
12
14
|
class?: HTMLAttributes['class']
|
|
13
15
|
}>()
|
|
@@ -20,10 +22,18 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
|
20
22
|
</script>
|
|
21
23
|
|
|
22
24
|
<template>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
25
|
+
<div class="relative">
|
|
26
|
+
<span class="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center pl-[13px]">
|
|
27
|
+
<TelaIcon name="i-ph-magnifying-glass-bold" size="12px" class="text-tertiary" />
|
|
28
|
+
</span>
|
|
29
|
+
<ComboboxInput
|
|
30
|
+
v-bind="{ ...forwarded, ...$attrs }"
|
|
31
|
+
:class="cn('flex h-[36px] w-full bg border-b-[0.5px] border-border pl-32px pr-3 body-14-regular text-primary transition-colors placeholder:text-tertiary focus-visible:bg focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50', $slots.deleteSearchValue && 'pr-30px', props.class)"
|
|
32
|
+
>
|
|
33
|
+
<slot />
|
|
34
|
+
</ComboboxInput>
|
|
35
|
+
<div v-if="$slots.deleteSearchValue" class="absolute inset-y-0 end-0 flex items-center justify-center px-2.5">
|
|
36
|
+
<slot name="deleteSearchValue" />
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
29
39
|
</template>
|
|
@@ -19,7 +19,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
|
19
19
|
<template>
|
|
20
20
|
<ComboboxItem
|
|
21
21
|
v-bind="forwarded"
|
|
22
|
-
:class="cn('relative flex cursor-pointer gap-2 select-none justify-between items-center rounded-
|
|
22
|
+
:class="cn('relative flex cursor-pointer gap-2 select-none justify-between items-center rounded-[12px] pl-[10px] pr-[8px] py-[7px] body-14-medium outline-none data-[highlighted]:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0', props.class)"
|
|
23
23
|
>
|
|
24
24
|
<slot />
|
|
25
25
|
</ComboboxItem>
|
|
@@ -15,7 +15,7 @@ const forwarded = useForwardProps(delegatedProps)
|
|
|
15
15
|
<template>
|
|
16
16
|
<ComboboxLabel
|
|
17
17
|
v-bind="forwarded"
|
|
18
|
-
:class="cn('
|
|
18
|
+
:class="cn('py-[4px] pl-[10px] body-12-semibold text-secondary', props.class)"
|
|
19
19
|
>
|
|
20
20
|
<slot />
|
|
21
21
|
</ComboboxLabel>
|
|
@@ -28,20 +28,10 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<template>
|
|
31
|
-
<
|
|
31
|
+
<ComboboxPortal :disabled="props.disablePortal">
|
|
32
32
|
<ComboboxContent
|
|
33
33
|
v-bind="forwarded"
|
|
34
|
-
:class="cn('ComboboxContent z-[9999] shadow-
|
|
35
|
-
>
|
|
36
|
-
<ComboboxViewport>
|
|
37
|
-
<slot />
|
|
38
|
-
</ComboboxViewport>
|
|
39
|
-
</ComboboxContent>
|
|
40
|
-
</template>
|
|
41
|
-
<ComboboxPortal v-else>
|
|
42
|
-
<ComboboxContent
|
|
43
|
-
v-bind="forwarded"
|
|
44
|
-
:class="cn('ComboboxContent z-[9999] shadow-lg outline-none rounded-xl bg-white-1000 border-[0.5px] border-gray-200 pointer-events-auto', props.class)"
|
|
34
|
+
:class="cn('ComboboxContent z-[9999] [box-shadow:0_4px_16px_0_rgba(85,91,98,0.14)] overflow-hidden outline-none rounded-[16px] bg border-0.5px border pointer-events-auto', props.class)"
|
|
45
35
|
>
|
|
46
36
|
<ComboboxViewport>
|
|
47
37
|
<slot />
|
|
@@ -263,24 +263,14 @@ watch(innerValue, (value) => {
|
|
|
263
263
|
@pointer-down-outside="closeOnOutsideClick ? undefined : $event.preventDefault()"
|
|
264
264
|
@escape-key-down="closeOnEscape ? undefined : $event.preventDefault()"
|
|
265
265
|
>
|
|
266
|
-
<
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
<ComboboxInput
|
|
271
|
-
v-model="search" class="pl-7 rounded-b-none"
|
|
272
|
-
:placeholder="t('models.labels.search')"
|
|
273
|
-
/>
|
|
274
|
-
<div v-if="search.length > 0" class="absolute inset-y-0 end-0 flex items-center justify-center px-2.5">
|
|
275
|
-
<button class="flex items-center justify-center" @click="handleDeleteSearchValue">
|
|
276
|
-
<TelaIcon name="i-ph-x-circle" size="16px" class="text-gray-400" />
|
|
277
|
-
</button>
|
|
278
|
-
</div>
|
|
279
|
-
</div>
|
|
266
|
+
<ComboboxInput
|
|
267
|
+
v-model="search"
|
|
268
|
+
:placeholder="t('models.labels.search')"
|
|
269
|
+
/>
|
|
280
270
|
<Tabs v-model="selectedTab" :default-value="selectedTab">
|
|
281
271
|
<TabsList class="sticky z-10 top-0 shrink-0 flex gap-2 w-full">
|
|
282
272
|
<TabsIndicator />
|
|
283
|
-
<TabsTrigger v-for="tab in tabs" :key="tab.tab" :value="tab.tab">
|
|
273
|
+
<TabsTrigger v-for="tab in tabs" :key="tab.tab" :value="tab.tab" size="sm">
|
|
284
274
|
{{ tab.label }}
|
|
285
275
|
</TabsTrigger>
|
|
286
276
|
</TabsList>
|
|
@@ -315,7 +305,7 @@ watch(innerValue, (value) => {
|
|
|
315
305
|
</TelaButton>
|
|
316
306
|
</ComboboxEmpty>
|
|
317
307
|
<template v-for="group in groupedOptions" :key="group.heading">
|
|
318
|
-
<ComboboxGroup :heading="group.heading"
|
|
308
|
+
<ComboboxGroup :heading="group.heading">
|
|
319
309
|
<ComboboxLabel v-if="!search.trim()" class="py-0 tracking-normal">
|
|
320
310
|
{{ group.heading }}
|
|
321
311
|
</ComboboxLabel>
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
2
4
|
import { ComboboxTrigger } from 'reka-ui'
|
|
3
5
|
import type { ComboboxTriggerProps } from 'reka-ui'
|
|
4
6
|
|
|
5
|
-
const props = defineProps<ComboboxTriggerProps>()
|
|
7
|
+
const props = defineProps<ComboboxTriggerProps & { class?: HTMLAttributes['class'] }>()
|
|
8
|
+
|
|
9
|
+
const delegatedProps = reactiveOmit(props, 'class')
|
|
6
10
|
</script>
|
|
7
11
|
|
|
8
12
|
<template>
|
|
9
|
-
<ComboboxTrigger
|
|
13
|
+
<ComboboxTrigger
|
|
14
|
+
v-bind="delegatedProps"
|
|
15
|
+
:class="cn(
|
|
16
|
+
'group select-none flex items-center justify-between body-14-semibold gap-3 rounded-10px pl-11px pr-10px py-7px bg-white border-0.5px border transition hover:border-strong hover:bg-subtle',
|
|
17
|
+
'data-[state=open]:text-secondary data-[state=open]:border-strong data-[state=open]:bg-subtle',
|
|
18
|
+
'[box-shadow:0_1px_6px_0_rgba(103,127,148,0.05)]',
|
|
19
|
+
props.class,
|
|
20
|
+
)"
|
|
21
|
+
>
|
|
10
22
|
<slot />
|
|
23
|
+
<TelaIcon
|
|
24
|
+
name="i-ph-caret-down-bold"
|
|
25
|
+
size="15px"
|
|
26
|
+
color="icon-secondary"
|
|
27
|
+
class="shrink-0 transition-transform ease-out duration-150 group-data-[state=open]:rotate-180"
|
|
28
|
+
/>
|
|
11
29
|
</ComboboxTrigger>
|
|
12
30
|
</template>
|
|
@@ -93,7 +93,7 @@ const meta: Meta<typeof Combobox> = {
|
|
|
93
93
|
|
|
94
94
|
export default meta
|
|
95
95
|
|
|
96
|
-
export const Default: StoryObj<{ options: Array<{ value: string
|
|
96
|
+
export const Default: StoryObj<{ options: Array<{ value: string, label: string }> }> = {
|
|
97
97
|
render: args => ({
|
|
98
98
|
components: { ComboboxRoot, ComboboxAnchor, ComboboxTrigger, TelaIcon, TelaButton, ComboboxInput, ComboboxList, ComboboxEmpty, ComboboxGroup, ComboboxItem, ComboboxItemIndicator, ComboboxLabel },
|
|
99
99
|
setup() {
|
|
@@ -105,14 +105,14 @@ export const Default: StoryObj<{ options: Array<{ value: string; label: string }
|
|
|
105
105
|
return selectedValue.value
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
return args.options.find(
|
|
108
|
+
return args.options.find(option => option.value === selectedValue.value)
|
|
109
109
|
})
|
|
110
110
|
|
|
111
111
|
const filteredOptions = computed(() => {
|
|
112
112
|
if (!search.value.trim()) {
|
|
113
113
|
return args.options
|
|
114
114
|
}
|
|
115
|
-
return args.options.filter(
|
|
115
|
+
return args.options.filter(option =>
|
|
116
116
|
option.label.toLowerCase().includes(search.value.toLowerCase()),
|
|
117
117
|
)
|
|
118
118
|
})
|