@meistrari/tela-build 1.20.0 → 1.22.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.
- package/components/tela/card/card.mdx +62 -0
- package/components/tela/card/card.stories.ts +143 -0
- package/components/tela/card/card.vue +33 -0
- package/components/tela/scroll-area/scroll-area.stories.ts +130 -0
- package/components/tela/segment-toggle/segment-toggle.mdx +89 -0
- package/components/tela/select-menu/select-menu.vue +1 -1
- package/components/tela/status/status.vue +5 -1
- package/components/tela/tabs/tabs-trigger.vue +3 -3
- package/components/tela/tooltip/tooltip-content.vue +2 -6
- package/lib/doc-generator.ts +22 -17
- package/package.json +1 -1
- package/components/tela/card.vue +0 -28
- /package/components/tela/{segment-toggle.stories.ts → segment-toggle/segment-toggle.stories.ts} +0 -0
- /package/components/tela/{segment-toggle.vue → segment-toggle/segment-toggle.vue} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# TelaCard
|
|
2
|
+
|
|
3
|
+
A surface container component used to group related content with consistent visual boundaries.
|
|
4
|
+
|
|
5
|
+
## Size Prop
|
|
6
|
+
|
|
7
|
+
Always use the `size` prop to control card padding — it maps directly to the standardized values. Never apply padding manually to `<TelaCard>` or its inner elements.
|
|
8
|
+
|
|
9
|
+
| `size` | Applied classes | Use for |
|
|
10
|
+
|--------|------------------|---------|
|
|
11
|
+
| `md` *(default)* | `p-32px sm:p-48px rounded-24px` | Standard and large cards |
|
|
12
|
+
| `sm` | `p-24px rounded-12px` | Small cards, inner containers |
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<!-- Correct — use size prop -->
|
|
16
|
+
<TelaCard size="md">...</TelaCard>
|
|
17
|
+
<TelaCard size="sm">...</TelaCard>
|
|
18
|
+
<TelaCard>...</TelaCard> <!-- md is the default -->
|
|
19
|
+
|
|
20
|
+
<!-- Incorrect — never apply padding manually -->
|
|
21
|
+
<TelaCard class="p-20px">...</TelaCard>
|
|
22
|
+
<TelaCard>
|
|
23
|
+
<div class="p-20px">...</div>
|
|
24
|
+
</TelaCard>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### Standard Card (default)
|
|
30
|
+
|
|
31
|
+
```vue
|
|
32
|
+
<TelaCard>
|
|
33
|
+
<h2 class="heading-h4-semibold text-contrast">Title</h2>
|
|
34
|
+
<p class="body-14-regular text-secondary">Supporting description text.</p>
|
|
35
|
+
</TelaCard>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Minor / Inner Card
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<TelaCard size="sm">
|
|
42
|
+
<span class="body-12-medium text-secondary">Compact content</span>
|
|
43
|
+
</TelaCard>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Card Grid
|
|
47
|
+
|
|
48
|
+
```vue
|
|
49
|
+
<div class="grid grid-cols-3 gap-4">
|
|
50
|
+
<TelaCard v-for="item in items" :key="item.id">...</TelaCard>
|
|
51
|
+
</div>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Props
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Default | Description |
|
|
57
|
+
|------|------|---------|-------------|
|
|
58
|
+
| `size` | `'sm' \| 'md'` | `'md'` | `md` = `p-32px sm:p-48px rounded-24px`, `sm` = `p-24px rounded-12px` |
|
|
59
|
+
|
|
60
|
+
## Slots
|
|
61
|
+
|
|
62
|
+
- `default` — Card body content
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import Card from './card.vue'
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Card> = {
|
|
5
|
+
title: 'Core/Card',
|
|
6
|
+
component: Card,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component: 'A surface container that groups related content with consistent visual boundaries. Use the `size` prop to control padding — `md` for standard cards, `sm` for minor or inner containers.',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
argTypes: {
|
|
16
|
+
size: {
|
|
17
|
+
control: 'select',
|
|
18
|
+
options: ['md', 'sm'],
|
|
19
|
+
description: '`md` applies standard card padding. `sm` applies minor/inner container padding.',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default meta
|
|
25
|
+
|
|
26
|
+
type Story = StoryObj<typeof meta>
|
|
27
|
+
|
|
28
|
+
export const Default: Story = {
|
|
29
|
+
render: args => ({
|
|
30
|
+
components: { Card },
|
|
31
|
+
setup() {
|
|
32
|
+
return { args }
|
|
33
|
+
},
|
|
34
|
+
template: `
|
|
35
|
+
<Card :size="args.size">
|
|
36
|
+
<div style="display: flex; flex-direction: column; gap: 8px; min-width: 280px;">
|
|
37
|
+
<p class="heading-h4-semibold text-contrast">Card Title</p>
|
|
38
|
+
<p class="body-14-regular text-secondary">This is supporting content inside the card. It adapts to the selected size.</p>
|
|
39
|
+
</div>
|
|
40
|
+
</Card>
|
|
41
|
+
`,
|
|
42
|
+
}),
|
|
43
|
+
args: {
|
|
44
|
+
size: 'md',
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const Standard: Story = {
|
|
49
|
+
render: () => ({
|
|
50
|
+
components: { Card },
|
|
51
|
+
template: `
|
|
52
|
+
<Card size="md">
|
|
53
|
+
<div style="display: flex; flex-direction: column; gap: 8px; min-width: 280px;">
|
|
54
|
+
<p class="heading-h4-semibold text-contrast">Standard Card</p>
|
|
55
|
+
<p class="body-14-regular text-secondary">Used for large, standard, and medium cards.</p>
|
|
56
|
+
</div>
|
|
57
|
+
</Card>
|
|
58
|
+
`,
|
|
59
|
+
}),
|
|
60
|
+
parameters: {
|
|
61
|
+
docs: {
|
|
62
|
+
description: {
|
|
63
|
+
story: 'Default size (`md`). Use for primary content surfaces.',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Minor: Story = {
|
|
70
|
+
render: () => ({
|
|
71
|
+
components: { Card },
|
|
72
|
+
template: `
|
|
73
|
+
<Card size="sm">
|
|
74
|
+
<div style="display: flex; flex-direction: column; gap: 8px; min-width: 240px;">
|
|
75
|
+
<p class="heading-h5-semibold text-contrast">Minor Card</p>
|
|
76
|
+
<p class="body-12-regular text-secondary">Used for small cards and inner containers.</p>
|
|
77
|
+
</div>
|
|
78
|
+
</Card>
|
|
79
|
+
`,
|
|
80
|
+
}),
|
|
81
|
+
parameters: {
|
|
82
|
+
docs: {
|
|
83
|
+
description: {
|
|
84
|
+
story: 'Small size (`sm`). Use for compact cards or nested inner containers.',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const SizeComparison: Story = {
|
|
91
|
+
render: () => ({
|
|
92
|
+
components: { Card },
|
|
93
|
+
template: `
|
|
94
|
+
<div style="display: flex; gap: 16px; align-items: flex-start;">
|
|
95
|
+
<Card size="md">
|
|
96
|
+
<div style="display: flex; flex-direction: column; gap: 6px; min-width: 200px;">
|
|
97
|
+
<p class="body-12-medium text-secondary">size="md"</p>
|
|
98
|
+
<p class="heading-h4-semibold text-contrast">Standard</p>
|
|
99
|
+
<p class="body-14-regular text-tertiary">p-32px sm:p-48px padding</p>
|
|
100
|
+
</div>
|
|
101
|
+
</Card>
|
|
102
|
+
<Card size="sm">
|
|
103
|
+
<div style="display: flex; flex-direction: column; gap: 6px; min-width: 200px;">
|
|
104
|
+
<p class="body-12-medium text-secondary">size="sm"</p>
|
|
105
|
+
<p class="heading-h4-semibold text-contrast">Minor</p>
|
|
106
|
+
<p class="body-14-regular text-tertiary">p-24px padding</p>
|
|
107
|
+
</div>
|
|
108
|
+
</Card>
|
|
109
|
+
</div>
|
|
110
|
+
`,
|
|
111
|
+
}),
|
|
112
|
+
parameters: {
|
|
113
|
+
docs: {
|
|
114
|
+
description: {
|
|
115
|
+
story: 'Side-by-side comparison of both size variants.',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const Grid: Story = {
|
|
122
|
+
render: () => ({
|
|
123
|
+
components: { Card },
|
|
124
|
+
template: `
|
|
125
|
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; width: 640px;">
|
|
126
|
+
<Card v-for="n in 3" :key="n">
|
|
127
|
+
<div style="display: flex; flex-direction: column; gap: 4px;">
|
|
128
|
+
<p class="heading-h5-semibold text-contrast">Card {{ n }}</p>
|
|
129
|
+
<p class="body-12-regular text-secondary">Grid item</p>
|
|
130
|
+
</div>
|
|
131
|
+
</Card>
|
|
132
|
+
</div>
|
|
133
|
+
`,
|
|
134
|
+
}),
|
|
135
|
+
parameters: {
|
|
136
|
+
layout: 'padded',
|
|
137
|
+
docs: {
|
|
138
|
+
description: {
|
|
139
|
+
story: 'Cards used in a grid layout. No padding override needed — `size="md"` is the default.',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
size?: 'sm' | 'md'
|
|
6
|
+
class?: HTMLAttributes['class']
|
|
7
|
+
/** @deprecated Use `class` instead */
|
|
8
|
+
contentPadding?: HTMLAttributes['class']
|
|
9
|
+
/** @deprecated Use `class` instead */
|
|
10
|
+
borderRadius?: HTMLAttributes['class']
|
|
11
|
+
}>(), {
|
|
12
|
+
size: 'md',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const sizeStyles = computed(() => (({
|
|
16
|
+
sm: { padding: 'p-24px', rounded: 'rounded-12px' },
|
|
17
|
+
md: { padding: 'p-32px sm:p-48px', rounded: 'rounded-24px' },
|
|
18
|
+
}) as Record<string, { padding: string, rounded: string }>)[props.size ?? 'md'] ?? { padding: '', rounded: '' })
|
|
19
|
+
|
|
20
|
+
const paddingClass = computed(() => props.contentPadding ?? sizeStyles.value.padding)
|
|
21
|
+
const borderRadiusClass = computed(() => props.borderRadius ?? sizeStyles.value.rounded)
|
|
22
|
+
const rootEl = ref<HTMLElement | null>(null)
|
|
23
|
+
|
|
24
|
+
defineExpose({
|
|
25
|
+
el: rootEl,
|
|
26
|
+
})
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<div ref="rootEl" :class="cn('bg border-0.5px border', paddingClass, borderRadiusClass, props.class)">
|
|
31
|
+
<slot />
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
import ScrollArea from './scroll-area.vue'
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof ScrollArea> = {
|
|
5
|
+
title: 'Utility/ScrollArea',
|
|
6
|
+
component: ScrollArea,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: 'A scroll area component that provides custom-styled scrollbars. Built on reka-ui for consistent scrollbar appearance across browsers. Useful for creating scrollable containers with better visual consistency than native scrollbars.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
type: {
|
|
18
|
+
control: 'select',
|
|
19
|
+
options: ['auto', 'always', 'scroll', 'hover'],
|
|
20
|
+
description: 'Scrollbar visibility behavior.',
|
|
21
|
+
},
|
|
22
|
+
orientation: {
|
|
23
|
+
control: 'select',
|
|
24
|
+
options: ['vertical', 'horizontal', 'both'],
|
|
25
|
+
description: 'Direction(s) of scrolling.',
|
|
26
|
+
},
|
|
27
|
+
scrollHideDelay: {
|
|
28
|
+
control: 'number',
|
|
29
|
+
description: 'Delay in ms before scrollbars are hidden (when type is hover or scroll).',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
type: 'hover',
|
|
34
|
+
orientation: 'vertical',
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default meta
|
|
39
|
+
|
|
40
|
+
type Story = StoryObj<typeof meta>
|
|
41
|
+
|
|
42
|
+
export const Default: Story = {
|
|
43
|
+
render: args => ({
|
|
44
|
+
components: { ScrollArea },
|
|
45
|
+
setup() {
|
|
46
|
+
const items = Array.from({ length: 30 }, (_, i) => `Item ${i + 1}`)
|
|
47
|
+
return { args, items }
|
|
48
|
+
},
|
|
49
|
+
template: `
|
|
50
|
+
<ScrollArea v-bind="args" class="h-200px w-300px border border-gray-200 rounded-md">
|
|
51
|
+
<div class="p-4 flex flex-col gap-2">
|
|
52
|
+
<div v-for="item in items" :key="item" class="text-sm py-1 border-b border-gray-100 last:border-0">
|
|
53
|
+
{{ item }}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</ScrollArea>
|
|
57
|
+
`,
|
|
58
|
+
}),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const AlwaysVisible: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
type: 'always',
|
|
64
|
+
},
|
|
65
|
+
render: args => ({
|
|
66
|
+
components: { ScrollArea },
|
|
67
|
+
setup() {
|
|
68
|
+
const items = Array.from({ length: 30 }, (_, i) => `Item ${i + 1}`)
|
|
69
|
+
return { args, items }
|
|
70
|
+
},
|
|
71
|
+
template: `
|
|
72
|
+
<ScrollArea v-bind="args" class="h-200px w-300px border border-gray-200 rounded-md">
|
|
73
|
+
<div class="p-4 flex flex-col gap-2">
|
|
74
|
+
<div v-for="item in items" :key="item" class="text-sm py-1 border-b border-gray-100 last:border-0">
|
|
75
|
+
{{ item }}
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</ScrollArea>
|
|
79
|
+
`,
|
|
80
|
+
}),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const Horizontal: Story = {
|
|
84
|
+
args: {
|
|
85
|
+
orientation: 'horizontal',
|
|
86
|
+
type: 'always',
|
|
87
|
+
},
|
|
88
|
+
render: args => ({
|
|
89
|
+
components: { ScrollArea },
|
|
90
|
+
setup() {
|
|
91
|
+
const items = Array.from({ length: 20 }, (_, i) => `Card ${i + 1}`)
|
|
92
|
+
return { args, items }
|
|
93
|
+
},
|
|
94
|
+
template: `
|
|
95
|
+
<ScrollArea v-bind="args" class="w-400px border border-gray-200 rounded-md">
|
|
96
|
+
<div class="flex gap-3 p-4" style="width: 1200px">
|
|
97
|
+
<div v-for="item in items" :key="item" class="flex-shrink-0 w-120px h-80px bg-gray-100 rounded flex items-center justify-center text-sm text-gray-600">
|
|
98
|
+
{{ item }}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</ScrollArea>
|
|
102
|
+
`,
|
|
103
|
+
}),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const Both: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
orientation: 'both',
|
|
109
|
+
type: 'always',
|
|
110
|
+
},
|
|
111
|
+
render: args => ({
|
|
112
|
+
components: { ScrollArea },
|
|
113
|
+
setup() {
|
|
114
|
+
const rows = Array.from({ length: 20 }, (_, i) => `Row ${i + 1}`)
|
|
115
|
+
return { args, rows }
|
|
116
|
+
},
|
|
117
|
+
template: `
|
|
118
|
+
<ScrollArea v-bind="args" class="h-250px w-400px border border-gray-200 rounded-md">
|
|
119
|
+
<div style="width: 900px">
|
|
120
|
+
<div v-for="row in rows" :key="row" class="flex items-center px-4 py-2 border-b border-gray-100 text-sm gap-4">
|
|
121
|
+
<span class="w-100px flex-shrink-0 font-medium">{{ row }}</span>
|
|
122
|
+
<span class="w-200px flex-shrink-0 text-gray-500">Column B content here</span>
|
|
123
|
+
<span class="w-200px flex-shrink-0 text-gray-500">Column C content here</span>
|
|
124
|
+
<span class="w-200px flex-shrink-0 text-gray-500">Column D content here</span>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</ScrollArea>
|
|
128
|
+
`,
|
|
129
|
+
}),
|
|
130
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as SegmentToggleStories from './segment-toggle.stories.ts';
|
|
3
|
+
|
|
4
|
+
<Meta of={SegmentToggleStories} />
|
|
5
|
+
|
|
6
|
+
# TelaSegmentToggle
|
|
7
|
+
|
|
8
|
+
A segment toggle component that displays multiple options as connected segments. Only one option can be selected at a time. Supports v-model binding, different sizes, and disabled states. Useful for mutually exclusive option selection with a modern segmented control interface.
|
|
9
|
+
|
|
10
|
+
## Examples
|
|
11
|
+
|
|
12
|
+
### Default
|
|
13
|
+
|
|
14
|
+
<Canvas of={SegmentToggleStories.Default} />
|
|
15
|
+
|
|
16
|
+
### Small Size
|
|
17
|
+
|
|
18
|
+
<Canvas of={SegmentToggleStories.Small} />
|
|
19
|
+
|
|
20
|
+
### Disabled
|
|
21
|
+
|
|
22
|
+
<Canvas of={SegmentToggleStories.Disabled} />
|
|
23
|
+
|
|
24
|
+
### Two Options
|
|
25
|
+
|
|
26
|
+
<Canvas of={SegmentToggleStories.TwoOptions} />
|
|
27
|
+
|
|
28
|
+
### Preselected Middle
|
|
29
|
+
|
|
30
|
+
<Canvas of={SegmentToggleStories.PreselectedMiddle} />
|
|
31
|
+
|
|
32
|
+
## Basic Usage
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<script setup>
|
|
36
|
+
import { ref } from 'vue'
|
|
37
|
+
|
|
38
|
+
const alignment = ref('left')
|
|
39
|
+
const options = [
|
|
40
|
+
{ label: 'Left', value: 'left' },
|
|
41
|
+
{ label: 'Center', value: 'center' },
|
|
42
|
+
{ label: 'Right', value: 'right' },
|
|
43
|
+
]
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<TelaSegmentToggle v-model="alignment" :options="options" />
|
|
48
|
+
</template>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Small Size
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<TelaSegmentToggle v-model="value" :options="options" size="small" />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Disabled State
|
|
58
|
+
|
|
59
|
+
```vue
|
|
60
|
+
<TelaSegmentToggle v-model="value" :options="options" disabled />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Props
|
|
64
|
+
|
|
65
|
+
<ArgTypes />
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
interface Option {
|
|
69
|
+
label: string
|
|
70
|
+
value: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type SegmentToggleProps = {
|
|
74
|
+
modelValue: string
|
|
75
|
+
options: Option[]
|
|
76
|
+
size?: 'small' | 'medium'
|
|
77
|
+
disabled?: boolean
|
|
78
|
+
class?: string
|
|
79
|
+
buttonsClass?: string
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Features
|
|
84
|
+
|
|
85
|
+
- **Two-way Binding**: Full v-model support for reactive state
|
|
86
|
+
- **Multiple Sizes**: Small and medium size options
|
|
87
|
+
- **Animated Selection**: Spring-animated indicator for smooth transitions
|
|
88
|
+
- **Disabled State**: Proper disabled styling and interaction prevention
|
|
89
|
+
- **Accessible**: Keyboard navigation support via native button elements
|
|
@@ -110,7 +110,7 @@ function handleOpenChange(open: boolean) {
|
|
|
110
110
|
v-if="currentOption?.icon && !(currentOption.value === '')"
|
|
111
111
|
shrink-0 rounded-4px flex items-center justify-center
|
|
112
112
|
>
|
|
113
|
-
<
|
|
113
|
+
<TelaIcon v-if="typeof currentOption.icon === 'string'" :name="currentOption.icon" />
|
|
114
114
|
<Component :is="currentOption.icon" v-else />
|
|
115
115
|
</div>
|
|
116
116
|
<div v-if="!currentOption?.icon && currentOption?.externalIconSrc" mr-4px flex h-20px w-16px shrink-0 items-center justify-center rounded-4px>
|
|
@@ -336,7 +336,11 @@ watch(
|
|
|
336
336
|
{ immediate: true },
|
|
337
337
|
)
|
|
338
338
|
|
|
339
|
-
onMounted(
|
|
339
|
+
onMounted(() => {
|
|
340
|
+
requestAnimationFrame(() => {
|
|
341
|
+
requestAnimationFrame(measureContentWidth)
|
|
342
|
+
})
|
|
343
|
+
})
|
|
340
344
|
|
|
341
345
|
const shineClass = computed(() => {
|
|
342
346
|
const baseColor = currentStatus.value.textColor.replace('text-', '')
|
|
@@ -5,9 +5,9 @@ import { TabsTrigger, useForwardProps } from 'reka-ui'
|
|
|
5
5
|
import type { TabsTriggerProps } from 'reka-ui'
|
|
6
6
|
import { cn } from '@/lib/utils'
|
|
7
7
|
|
|
8
|
-
const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes['class'] }>()
|
|
8
|
+
const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes['class'], textClass?: HTMLAttributes['class'] }>()
|
|
9
9
|
|
|
10
|
-
const delegatedProps = reactiveOmit(props, 'class')
|
|
10
|
+
const delegatedProps = reactiveOmit(props, 'class', 'textClass')
|
|
11
11
|
|
|
12
12
|
const forwardedProps = useForwardProps(delegatedProps)
|
|
13
13
|
</script>
|
|
@@ -20,7 +20,7 @@ const forwardedProps = useForwardProps(delegatedProps)
|
|
|
20
20
|
props.class,
|
|
21
21
|
)"
|
|
22
22
|
>
|
|
23
|
-
<span class="truncate">
|
|
23
|
+
<span :class="cn('truncate', props.textClass)">
|
|
24
24
|
<slot />
|
|
25
25
|
</span>
|
|
26
26
|
</TabsTrigger>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { TooltipContent, TooltipPortal, useForwardPropsEmits } from 'reka-ui'
|
|
3
3
|
import type { TooltipContentEmits, TooltipContentProps } from 'reka-ui'
|
|
4
|
-
import {
|
|
4
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
5
5
|
import type { HTMLAttributes } from 'vue'
|
|
6
6
|
|
|
7
7
|
defineOptions({
|
|
@@ -16,11 +16,7 @@ const emits = defineEmits<TooltipContentEmits & {
|
|
|
16
16
|
click: [event: Event]
|
|
17
17
|
}>()
|
|
18
18
|
|
|
19
|
-
const delegatedProps =
|
|
20
|
-
const { class: _, ...delegated } = props
|
|
21
|
-
|
|
22
|
-
return delegated
|
|
23
|
-
})
|
|
19
|
+
const delegatedProps = reactiveOmit(props, 'class')
|
|
24
20
|
|
|
25
21
|
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
26
22
|
</script>
|
package/lib/doc-generator.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { join, resolve, relative, dirname, basename } from 'pathe'
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs'
|
|
4
4
|
import { parse as parseVue } from 'vue-docgen-api'
|
|
5
5
|
// Load glob dynamically for compatibility across versions (v8 vs v11)
|
|
6
|
-
import { getTypeResolver
|
|
7
|
-
import {
|
|
6
|
+
import { getTypeResolver } from './type-resolver'
|
|
7
|
+
import type { TypeResolver } from './type-resolver'
|
|
8
|
+
import { createVolarExtractor } from './extractors/volar-extract'
|
|
9
|
+
import type { VolarExtractor } from './extractors/volar-extract'
|
|
8
10
|
|
|
9
11
|
const colors = {
|
|
10
12
|
gray: '\x1B[90m',
|
|
@@ -544,20 +546,23 @@ export function generateDocsToDirectory(componentDocs: ComponentDoc[], typeResol
|
|
|
544
546
|
componentLinks.push(`- [${title}](components/${groupSlug}.md)`)
|
|
545
547
|
}
|
|
546
548
|
|
|
547
|
-
// Read
|
|
548
|
-
let
|
|
549
|
+
// Read all .md files from docs/ and append them to SKILL.md
|
|
550
|
+
let docsSection = ''
|
|
549
551
|
if (layerPath) {
|
|
550
|
-
const
|
|
551
|
-
if (existsSync(
|
|
552
|
-
|
|
552
|
+
const docsDir = join(layerPath, 'docs')
|
|
553
|
+
if (existsSync(docsDir)) {
|
|
554
|
+
const docFiles = readdirSync(docsDir)
|
|
555
|
+
.filter(f => f.endsWith('.md'))
|
|
556
|
+
.sort()
|
|
557
|
+
for (const file of docFiles) {
|
|
558
|
+
const content = readFileSync(join(docsDir, file), 'utf-8')
|
|
559
|
+
docsSection += `\n\n---\n\n${content}`
|
|
560
|
+
}
|
|
553
561
|
}
|
|
554
562
|
}
|
|
555
563
|
|
|
556
564
|
// Create SKILL.md describing Tela Build with links to supporting md
|
|
557
565
|
const skillDescription = buildTelaBuildSkillDescription()
|
|
558
|
-
const designTokensSection = designTokensContent
|
|
559
|
-
? `\n\n---\n\n${designTokensContent}`
|
|
560
|
-
: ''
|
|
561
566
|
const body = dedent`
|
|
562
567
|
# Tela Build
|
|
563
568
|
|
|
@@ -574,7 +579,7 @@ Use it when building, refactoring, or using Tela components — props, events, s
|
|
|
574
579
|
|
|
575
580
|
## Components Index
|
|
576
581
|
|
|
577
|
-
${componentLinks.join('\n')}${
|
|
582
|
+
${componentLinks.join('\n')}${docsSection}
|
|
578
583
|
`
|
|
579
584
|
|
|
580
585
|
const skillMd = wrapWithSkillFrontmatter({ name: 'tela-build', description: skillDescription }, body)
|
|
@@ -675,13 +680,13 @@ function toKebabFromTag(tagName: string): string {
|
|
|
675
680
|
return tagName
|
|
676
681
|
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
677
682
|
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
678
|
-
.replace(/[^a-
|
|
683
|
+
.replace(/[^a-z0-9-]/gi, '-')
|
|
679
684
|
.toLowerCase()
|
|
680
|
-
.replace(
|
|
685
|
+
.replace(/-{2,}/g, '-')
|
|
681
686
|
.replace(/^-+|-+$/g, '')
|
|
682
687
|
}
|
|
683
688
|
|
|
684
|
-
function wrapWithSkillFrontmatter(meta: { name: string
|
|
689
|
+
function wrapWithSkillFrontmatter(meta: { name: string, description: string, allowedTools?: string[] }, body: string): string {
|
|
685
690
|
const { name, description, allowedTools } = meta
|
|
686
691
|
const lines: string[] = []
|
|
687
692
|
lines.push('---')
|
|
@@ -700,7 +705,7 @@ function wrapWithSkillFrontmatter(meta: { name: string; description: string; all
|
|
|
700
705
|
|
|
701
706
|
function sanitizeSkillName(name: string): string {
|
|
702
707
|
// Lowercase + hyphens + digits only, max 64 chars
|
|
703
|
-
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-').slice(0, 64).replace(
|
|
708
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-').slice(0, 64).replace(/-{2,}/g, '-')
|
|
704
709
|
}
|
|
705
710
|
|
|
706
711
|
function sanitizeDescription(desc: string): string {
|
|
@@ -804,7 +809,7 @@ function sanitizeInlineComment(value?: string): string {
|
|
|
804
809
|
if (!value)
|
|
805
810
|
return ''
|
|
806
811
|
|
|
807
|
-
const withoutMarkdown = value.replace(/\[([^\]]+)\]\([
|
|
812
|
+
const withoutMarkdown = value.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
808
813
|
const singleLine = withoutMarkdown.replace(/\s+/g, ' ').trim()
|
|
809
814
|
if (!singleLine)
|
|
810
815
|
return ''
|
package/package.json
CHANGED
package/components/tela/card.vue
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
defineProps<{
|
|
3
|
-
contentPadding?: string
|
|
4
|
-
borderRadius?: string
|
|
5
|
-
}>()
|
|
6
|
-
|
|
7
|
-
const rootEl = ref<HTMLElement | null>(null)
|
|
8
|
-
|
|
9
|
-
defineExpose({
|
|
10
|
-
el: rootEl,
|
|
11
|
-
})
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<template>
|
|
15
|
-
<div
|
|
16
|
-
ref="rootEl"
|
|
17
|
-
bg-white
|
|
18
|
-
:class="borderRadius ? `rounded-${borderRadius}` : 'rounded-16px'"
|
|
19
|
-
b=".5 gray-200"
|
|
20
|
-
>
|
|
21
|
-
<div :class="contentPadding ?? 'p-32px'">
|
|
22
|
-
<slot />
|
|
23
|
-
</div>
|
|
24
|
-
<div v-if="$slots.footer" p-19px b="t-1 #EBEBEB">
|
|
25
|
-
<slot name="footer" />
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</template>
|
/package/components/tela/{segment-toggle.stories.ts → segment-toggle/segment-toggle.stories.ts}
RENAMED
|
File without changes
|
|
File without changes
|