@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.
- package/README.md +75 -0
- package/app.config.ts +73 -0
- package/components/tela/animated/animated-calculating-number.vue +16 -0
- package/components/tela/animated/animated-number.mdx +248 -0
- package/components/tela/animated/animated-number.stories.ts +52 -0
- package/components/tela/animated/animated-number.vue +23 -0
- package/components/tela/animated/animated-text.vue +124 -0
- package/components/tela/animated/animated-value.vue +68 -0
- package/components/tela/avatar/avatar.mdx +117 -0
- package/components/tela/avatar/avatar.stories.ts +62 -0
- package/components/tela/avatar/avatar.vue +71 -0
- package/components/tela/avatar/group/avatar-group.stories.ts +78 -0
- package/components/tela/avatar/group/avatar-group.vue +46 -0
- package/components/tela/badge/badge.mdx +154 -0
- package/components/tela/badge/badge.stories.ts +82 -0
- package/components/tela/badge/badge.vue +41 -0
- package/components/tela/button/button.mdx +155 -0
- package/components/tela/button/button.stories.ts +202 -0
- package/components/tela/button/button.vue +107 -0
- package/components/tela/card.vue +30 -0
- package/components/tela/chart/chart-bar.vue +58 -0
- package/components/tela/chat/chat.mdx +268 -0
- package/components/tela/chat/chat.stories.ts +253 -0
- package/components/tela/chat/command/index.vue +41 -0
- package/components/tela/chat/command/mention/index.vue +138 -0
- package/components/tela/chat/index.vue +112 -0
- package/components/tela/chat/pure-text-input/chat-text-input.vue +190 -0
- package/components/tela/chat/text-input/chat-text-input.stories.ts +128 -0
- package/components/tela/chat/text-input/index.vue +217 -0
- package/components/tela/chat/text-message/chat-text-message.stories.ts +138 -0
- package/components/tela/chat/text-message/index.vue +355 -0
- package/components/tela/chat/types.ts +19 -0
- package/components/tela/checkbox/checkbox-card.vue +30 -0
- package/components/tela/checkbox/checkbox.mdx +164 -0
- package/components/tela/checkbox/checkbox.stories.ts +104 -0
- package/components/tela/checkbox/checkbox.vue +43 -0
- package/components/tela/collapsible/Collapsible.vue +15 -0
- package/components/tela/collapsible/CollapsibleContent.vue +59 -0
- package/components/tela/collapsible/CollapsibleTrigger.vue +12 -0
- package/components/tela/collapsible/collapsible.mdx +157 -0
- package/components/tela/collapsible-section/collapsible-section.mdx +180 -0
- package/components/tela/collapsible-section/collapsible-section.stories.ts +53 -0
- package/components/tela/collapsible-section/collapsible-section.vue +51 -0
- package/components/tela/collapsible-section-with-actions.vue +98 -0
- package/components/tela/combobox/combobox-anchor.vue +24 -0
- package/components/tela/combobox/combobox-empty.vue +19 -0
- package/components/tela/combobox/combobox-group.vue +24 -0
- package/components/tela/combobox/combobox-indicator.vue +22 -0
- package/components/tela/combobox/combobox-input.vue +31 -0
- package/components/tela/combobox/combobox-item.vue +28 -0
- package/components/tela/combobox/combobox-label.vue +24 -0
- package/components/tela/combobox/combobox-list.vue +90 -0
- package/components/tela/combobox/combobox-module-selector.vue +366 -0
- package/components/tela/combobox/combobox-root.vue +15 -0
- package/components/tela/combobox/combobox-trigger.vue +12 -0
- package/components/tela/combobox/combobox.mdx +285 -0
- package/components/tela/combobox/combobox.stories.ts +232 -0
- package/components/tela/combobox/combobox.vue +497 -0
- package/components/tela/command/command-dialog.vue +22 -0
- package/components/tela/command/command-empty.vue +25 -0
- package/components/tela/command/command-group.vue +46 -0
- package/components/tela/command/command-input.vue +38 -0
- package/components/tela/command/command-item.vue +78 -0
- package/components/tela/command/command-list.vue +78 -0
- package/components/tela/command/command-separator.vue +23 -0
- package/components/tela/command/command-shortcut.vue +13 -0
- package/components/tela/command/command.vue +88 -0
- package/components/tela/command/dialog-base.vue +15 -0
- package/components/tela/command/dialog-content.vue +50 -0
- package/components/tela/command/utils.ts +15 -0
- package/components/tela/complex-table/complex-table-cell.stories.ts +145 -0
- package/components/tela/complex-table/complex-table-cell.vue +45 -0
- package/components/tela/complex-table/complex-table-header-cell.stories.ts +103 -0
- package/components/tela/complex-table/complex-table-header-cell.vue +48 -0
- package/components/tela/complex-table/complex-table-header.stories.ts +89 -0
- package/components/tela/complex-table/complex-table-header.vue +70 -0
- package/components/tela/complex-table/complex-table-row.vue +199 -0
- package/components/tela/complex-table/complex-table-virtualized.vue +326 -0
- package/components/tela/complex-table/complex-table.stories.ts +358 -0
- package/components/tela/complex-table/complex-table.vue +237 -0
- package/components/tela/complex-table/composables/table-common.ts +93 -0
- package/components/tela/complex-table/composables/table-selection.ts +87 -0
- package/components/tela/complex-table/composables/virtual-scroll.ts +252 -0
- package/components/tela/complex-table/styles/table-shared.css +170 -0
- package/components/tela/complex-table/types.ts +63 -0
- package/components/tela/complex-table/utils.ts +35 -0
- package/components/tela/confirm-button/confirm-button.vue +137 -0
- package/components/tela/confirmation-modal/confirmation-modal.vue +72 -0
- package/components/tela/copy-button.vue +86 -0
- package/components/tela/date-range-picker.vue +221 -0
- package/components/tela/dialog/dialog.mdx +170 -0
- package/components/tela/dialog/dialog.vue +182 -0
- package/components/tela/disabled-area.vue +16 -0
- package/components/tela/disclaimer/disclaimer.mdx +238 -0
- package/components/tela/disclaimer/disclaimer.stories.ts +196 -0
- package/components/tela/disclaimer/disclaimer.vue +125 -0
- package/components/tela/dropdown-menu/DropdownMenu.vue +121 -0
- package/components/tela/dropdown-menu/DropdownMenuCheckboxItem.vue +40 -0
- package/components/tela/dropdown-menu/DropdownMenuContent.vue +75 -0
- package/components/tela/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/components/tela/dropdown-menu/DropdownMenuItem.vue +137 -0
- package/components/tela/dropdown-menu/DropdownMenuLabel.vue +26 -0
- package/components/tela/dropdown-menu/DropdownMenuRadioGroup.vue +18 -0
- package/components/tela/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
- package/components/tela/dropdown-menu/DropdownMenuRoot.vue +15 -0
- package/components/tela/dropdown-menu/DropdownMenuSeparator.vue +21 -0
- package/components/tela/dropdown-menu/DropdownMenuShortcut.vue +14 -0
- package/components/tela/dropdown-menu/DropdownMenuSub.vue +18 -0
- package/components/tela/dropdown-menu/DropdownMenuSubContent.vue +30 -0
- package/components/tela/dropdown-menu/DropdownMenuSubTrigger.vue +35 -0
- package/components/tela/dropdown-menu/DropdownMenuTrigger.vue +14 -0
- package/components/tela/dropdown-menu/dropdown-menu.mdx +265 -0
- package/components/tela/dropdown-menu/dropdown-menu.stories.ts +156 -0
- package/components/tela/expandable-input.vue +96 -0
- package/components/tela/file-drop.vue +37 -0
- package/components/tela/file-upload/file-upload.mdx +189 -0
- package/components/tela/file-upload/file-upload.stories.ts +48 -0
- package/components/tela/file-upload/file-upload.vue +205 -0
- package/components/tela/filters/checkbox-filter.stories.ts +218 -0
- package/components/tela/filters/checkbox-filter.vue +165 -0
- package/components/tela/filters/date-filter.stories.ts +258 -0
- package/components/tela/filters/date-filter.vue +200 -0
- package/components/tela/filters/user-filter.stories.ts +344 -0
- package/components/tela/filters/user-filter.vue +271 -0
- package/components/tela/hover-card/hover-card.mdx +221 -0
- package/components/tela/hover-card/hover-card.stories.ts +87 -0
- package/components/tela/hover-card/hover-card.vue +61 -0
- package/components/tela/icon/custom.vue +319 -0
- package/components/tela/icon/spinner.vue +12 -0
- package/components/tela/icon-button/icon-button.vue +114 -0
- package/components/tela/icon.vue +37 -0
- package/components/tela/initials.vue +28 -0
- package/components/tela/inline-input.vue +77 -0
- package/components/tela/input/input.mdx +182 -0
- package/components/tela/input/input.stories.ts +153 -0
- package/components/tela/input/tela-input.vue +240 -0
- package/components/tela/kbd/kbd-return.vue +6 -0
- package/components/tela/kbd/kbd.mdx +238 -0
- package/components/tela/kbd/kbd.vue +18 -0
- package/components/tela/label/label.mdx +121 -0
- package/components/tela/label/label.stories.ts +37 -0
- package/components/tela/label/label.vue +25 -0
- package/components/tela/link-decoration/link-decoration.vue +19 -0
- package/components/tela/live-label.vue +32 -0
- package/components/tela/long-press-button.vue +98 -0
- package/components/tela/menubar/menubar-content.vue +77 -0
- package/components/tela/menubar/menubar-item.vue +32 -0
- package/components/tela/menubar/menubar-label.vue +14 -0
- package/components/tela/menubar/menubar-menu.vue +12 -0
- package/components/tela/menubar/menubar-root.vue +30 -0
- package/components/tela/menubar/menubar-separator.vue +17 -0
- package/components/tela/menubar/menubar-shortcut.vue +14 -0
- package/components/tela/menubar/menubar-sub-content.vue +36 -0
- package/components/tela/menubar/menubar-sub-trigger.vue +28 -0
- package/components/tela/menubar/menubar-sub.vue +20 -0
- package/components/tela/menubar/menubar-trigger.vue +27 -0
- package/components/tela/menubar/menubar.vue +298 -0
- package/components/tela/modal/modal.mdx +145 -0
- package/components/tela/modal/modal.vue +242 -0
- package/components/tela/multiple-select/multiple-select.mdx +274 -0
- package/components/tela/multiple-select/multiple-select.stories.ts +325 -0
- package/components/tela/multiple-select/multiple-select.vue +666 -0
- package/components/tela/pane.vue +110 -0
- package/components/tela/popover/popover-content.vue +48 -0
- package/components/tela/popover/popover-trigger.vue +12 -0
- package/components/tela/popover/popover.mdx +239 -0
- package/components/tela/popover/popover.stories.ts +150 -0
- package/components/tela/popover/popover.vue +15 -0
- package/components/tela/popover-list/popover-list-nested.vue +104 -0
- package/components/tela/popover-list/popover-list.stories.ts +330 -0
- package/components/tela/popover-list/popover-list.vue +191 -0
- package/components/tela/radio-button.vue +66 -0
- package/components/tela/radio-group/radio-group-item.vue +40 -0
- package/components/tela/radio-group/radio-group-root.vue +26 -0
- package/components/tela/radio-group/radio-group.mdx +78 -0
- package/components/tela/radio-group/radio-group.stories.ts +106 -0
- package/components/tela/radio-group/radio-group.vue +23 -0
- package/components/tela/range-calendar.stories.ts +110 -0
- package/components/tela/range-calendar.vue +109 -0
- package/components/tela/scroll-area/scroll-area.mdx +183 -0
- package/components/tela/scroll-area/scroll-area.vue +30 -0
- package/components/tela/scroll-area/scroll-bar.vue +31 -0
- package/components/tela/segment-toggle.stories.ts +114 -0
- package/components/tela/segment-toggle.vue +66 -0
- package/components/tela/select-menu/select-menu-content.vue +106 -0
- package/components/tela/select-menu/select-menu-down-button.vue +20 -0
- package/components/tela/select-menu/select-menu-group.vue +16 -0
- package/components/tela/select-menu/select-menu-item.vue +40 -0
- package/components/tela/select-menu/select-menu-root.vue +15 -0
- package/components/tela/select-menu/select-menu-trigger.vue +34 -0
- package/components/tela/select-menu/select-menu-up-button.vue +20 -0
- package/components/tela/select-menu/select-menu-value.vue +12 -0
- package/components/tela/select-menu/select-menu.mdx +221 -0
- package/components/tela/select-menu/select-menu.stories.ts +91 -0
- package/components/tela/select-menu/select-menu.vue +165 -0
- package/components/tela/selector/selector.vue +47 -0
- package/components/tela/sheet/sheet-close.vue +12 -0
- package/components/tela/sheet/sheet-content.vue +57 -0
- package/components/tela/sheet/sheet-description.vue +23 -0
- package/components/tela/sheet/sheet-footer.vue +18 -0
- package/components/tela/sheet/sheet-header.vue +15 -0
- package/components/tela/sheet/sheet-root.vue +18 -0
- package/components/tela/sheet/sheet-title.vue +23 -0
- package/components/tela/sheet/sheet-trigger.vue +12 -0
- package/components/tela/sheet/sheet.client.vue +150 -0
- package/components/tela/sheet/sheet.mdx +176 -0
- package/components/tela/sheet/sheet.stories.ts +201 -0
- package/components/tela/sheet/variants.ts +22 -0
- package/components/tela/side-sheet/side-sheet.mdx +131 -0
- package/components/tela/side-sheet/side-sheet.stories.ts +134 -0
- package/components/tela/side-sheet/side-sheet.vue +106 -0
- package/components/tela/skeleton/skeleton.mdx +165 -0
- package/components/tela/skeleton/skeleton.stories.ts +35 -0
- package/components/tela/skeleton/skeleton.vue +45 -0
- package/components/tela/skeleton-icon.vue +24 -0
- package/components/tela/span.vue +24 -0
- package/components/tela/star-button.vue +70 -0
- package/components/tela/status/status-lean.vue +30 -0
- package/components/tela/status/status.mdx +187 -0
- package/components/tela/status/status.stories.ts +160 -0
- package/components/tela/status/status.vue +420 -0
- package/components/tela/status-bar/status-bar.mdx +178 -0
- package/components/tela/status-bar/status-bar.stories.ts +64 -0
- package/components/tela/status-bar/status-bar.vue +56 -0
- package/components/tela/status-bar/types.ts +5 -0
- package/components/tela/switch/switch.mdx +118 -0
- package/components/tela/switch/switch.stories.ts +80 -0
- package/components/tela/switch/switch.vue +56 -0
- package/components/tela/table/table-body.vue +13 -0
- package/components/tela/table/table-caption.vue +13 -0
- package/components/tela/table/table-cell.vue +20 -0
- package/components/tela/table/table-empty.vue +37 -0
- package/components/tela/table/table-footer.vue +13 -0
- package/components/tela/table/table-head.vue +13 -0
- package/components/tela/table/table-header.vue +13 -0
- package/components/tela/table/table-row.vue +13 -0
- package/components/tela/table/table.mdx +230 -0
- package/components/tela/table/table.stories.ts +384 -0
- package/components/tela/table/table.vue +15 -0
- package/components/tela/tabs/tabs-content.vue +20 -0
- package/components/tela/tabs/tabs-indicator.vue +22 -0
- package/components/tela/tabs/tabs-list.vue +23 -0
- package/components/tela/tabs/tabs-root.vue +15 -0
- package/components/tela/tabs/tabs-trigger.vue +27 -0
- package/components/tela/tabs/tabs.mdx +138 -0
- package/components/tela/tabs/tabs.stories.ts +72 -0
- package/components/tela/tabs/tabs.vue +61 -0
- package/components/tela/tags/tags-select.mdx +318 -0
- package/components/tela/tags/tags-select.stories.ts +47 -0
- package/components/tela/tags/tags-select.vue +637 -0
- package/components/tela/tags/tags.mdx +151 -0
- package/components/tela/tags/tags.stories.ts +118 -0
- package/components/tela/tags/tags.vue +112 -0
- package/components/tela/textarea/textarea.mdx +102 -0
- package/components/tela/textarea/textarea.stories.ts +50 -0
- package/components/tela/textarea/textarea.vue +34 -0
- package/components/tela/toggle-group.vue +91 -0
- package/components/tela/tooltip/tooltip-content.vue +45 -0
- package/components/tela/tooltip/tooltip-provider.vue +12 -0
- package/components/tela/tooltip/tooltip-root.vue +15 -0
- package/components/tela/tooltip/tooltip-trigger.vue +12 -0
- package/components/tela/tooltip/tooltip.mdx +196 -0
- package/components/tela/tooltip/tooltip.stories.ts +200 -0
- package/components/tela/tooltip/tooltip.vue +91 -0
- package/components/tela/tooltip-group/tooltip-group-trigger.vue +92 -0
- package/components/tela/tooltip-group/tooltip-group.mdx +236 -0
- package/components/tela/tooltip-group/tooltip-group.stories.ts +465 -0
- package/components/tela/tooltip-group/tooltip-group.vue +35 -0
- package/components/tela/transparent-input.vue +151 -0
- package/components/tela/variable-icon.vue +28 -0
- package/components/tela/variable-input.vue +77 -0
- package/components/tela/wide-button/wide-button.vue +40 -0
- package/components.json +18 -0
- package/composables/status-toast.ts +67 -0
- package/css/reset.css +386 -0
- package/css/text.css +22 -0
- package/lib/doc-generator.ts +903 -0
- package/lib/extractors/volar-extract.ts +186 -0
- package/lib/type-resolver.ts +402 -0
- package/lib/utils.ts +6 -0
- package/modules/tela-build-docs/index.ts +139 -0
- package/nuxt.config.ts +80 -0
- package/package.json +84 -0
- package/plugins/test-id.ts +7 -0
- package/tsconfig.json +7 -0
- package/types/custom-icon.ts +1 -0
- package/types/index.ts +2 -0
- package/types/status.ts +1 -0
- package/unocss.config.ts +89 -0
- package/utils/component-utils.ts +30 -0
- package/utils/design-tokens.ts +431 -0
- package/utils/fold.ts +8 -0
- package/utils/select-menu.ts +10 -0
- package/utils/status.ts +1 -0
- package/utils/without-keys.ts +34 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as InputStories from './input.stories.ts';
|
|
3
|
+
|
|
4
|
+
<Meta of={InputStories} />
|
|
5
|
+
|
|
6
|
+
# TelaInput
|
|
7
|
+
|
|
8
|
+
A flexible input component that supports both text input and textarea modes. Includes features like labels, error states, icons, clear buttons, and validation feedback. Supports v-model binding for two-way data binding.
|
|
9
|
+
|
|
10
|
+
## Examples
|
|
11
|
+
|
|
12
|
+
### With Clear Button
|
|
13
|
+
|
|
14
|
+
<Canvas of={InputStories.ClearButton} />
|
|
15
|
+
|
|
16
|
+
### With Icon
|
|
17
|
+
|
|
18
|
+
<Canvas of={InputStories.WithIcon} />
|
|
19
|
+
|
|
20
|
+
### With Error
|
|
21
|
+
|
|
22
|
+
<Canvas of={InputStories.WithError} />
|
|
23
|
+
|
|
24
|
+
### Disabled
|
|
25
|
+
|
|
26
|
+
<Canvas of={InputStories.Disabled} />
|
|
27
|
+
|
|
28
|
+
### Textarea
|
|
29
|
+
|
|
30
|
+
<Canvas of={InputStories.Textarea} />
|
|
31
|
+
|
|
32
|
+
### Basic Usage
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<script setup>
|
|
36
|
+
import { ref } from 'vue'
|
|
37
|
+
|
|
38
|
+
const value = ref('')
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<TelaInput
|
|
43
|
+
v-model="value"
|
|
44
|
+
label="Username"
|
|
45
|
+
placeholder="Enter your username"
|
|
46
|
+
/>
|
|
47
|
+
</template>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### With Clear Button Code
|
|
51
|
+
|
|
52
|
+
```vue
|
|
53
|
+
<TelaInput
|
|
54
|
+
v-model="value"
|
|
55
|
+
label="Email"
|
|
56
|
+
placeholder="you@example.com"
|
|
57
|
+
show-clear-button
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With Icon Code
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<TelaInput
|
|
65
|
+
v-model="searchQuery"
|
|
66
|
+
label="Search"
|
|
67
|
+
icon="i-ph-magnifying-glass"
|
|
68
|
+
placeholder="Search..."
|
|
69
|
+
/>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### With Error Code
|
|
73
|
+
|
|
74
|
+
```vue
|
|
75
|
+
<TelaInput
|
|
76
|
+
v-model="email"
|
|
77
|
+
label="Email"
|
|
78
|
+
placeholder="you@example.com"
|
|
79
|
+
error="Please enter a valid email address"
|
|
80
|
+
/>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Disabled Code
|
|
84
|
+
|
|
85
|
+
```vue
|
|
86
|
+
<TelaInput
|
|
87
|
+
label="Disabled Input"
|
|
88
|
+
placeholder="Cannot edit"
|
|
89
|
+
disabled
|
|
90
|
+
model-value="Read only value"
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```vue
|
|
95
|
+
<TelaInput
|
|
96
|
+
v-model="message"
|
|
97
|
+
type="textarea"
|
|
98
|
+
label="Message"
|
|
99
|
+
placeholder="Enter your message..."
|
|
100
|
+
/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Custom Styling
|
|
104
|
+
|
|
105
|
+
```vue
|
|
106
|
+
<TelaInput
|
|
107
|
+
v-model="value"
|
|
108
|
+
label="Custom Input"
|
|
109
|
+
label-class="text-blue-600 font-bold"
|
|
110
|
+
input-class="border-blue-400"
|
|
111
|
+
input-font-class="font-mono"
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### With Maxlength
|
|
116
|
+
|
|
117
|
+
```vue
|
|
118
|
+
<TelaInput
|
|
119
|
+
v-model="bio"
|
|
120
|
+
label="Bio"
|
|
121
|
+
placeholder="Tell us about yourself"
|
|
122
|
+
:maxlength="100"
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Props
|
|
127
|
+
|
|
128
|
+
<ArgTypes />
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
type InputSize = 'sm' | 'md'
|
|
132
|
+
|
|
133
|
+
type InputProps = {
|
|
134
|
+
id?: string
|
|
135
|
+
modelValue?: string | number
|
|
136
|
+
label?: string
|
|
137
|
+
placeholder?: string
|
|
138
|
+
hideLabel?: boolean
|
|
139
|
+
disabled?: boolean
|
|
140
|
+
size?: InputSize
|
|
141
|
+
error?: string | false
|
|
142
|
+
showClearButton?: boolean
|
|
143
|
+
tabindex?: number
|
|
144
|
+
autofocus?: boolean
|
|
145
|
+
autocomplete?: 'on' | 'off'
|
|
146
|
+
type?: string
|
|
147
|
+
labelClass?: string
|
|
148
|
+
inputFontClass?: string
|
|
149
|
+
inputClass?: string
|
|
150
|
+
icon?: string
|
|
151
|
+
showDescription?: boolean
|
|
152
|
+
maxlength?: number
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Features
|
|
157
|
+
|
|
158
|
+
- **Flexible Input Types**: Supports text, email, password, number, textarea, and more
|
|
159
|
+
- **Label Support**: Built-in label with hide option for accessibility
|
|
160
|
+
- **Error Handling**: Display validation errors with styling
|
|
161
|
+
- **Icon Integration**: Add icons inside the input field
|
|
162
|
+
- **Clear Button**: Quick clear functionality with show/hide control
|
|
163
|
+
- **Auto-focus**: Automatically focus on mount
|
|
164
|
+
- **Disabled State**: Proper disabled styling and behavior
|
|
165
|
+
- **Character Limit**: Maxlength support with counter
|
|
166
|
+
- **Custom Classes**: Granular control over label, input, and font styling
|
|
167
|
+
- **Two-way Binding**: Full v-model support
|
|
168
|
+
- **Textarea Mode**: Multi-line input support
|
|
169
|
+
|
|
170
|
+
## Sizes
|
|
171
|
+
|
|
172
|
+
- **sm**: Small input with compact padding
|
|
173
|
+
- **md**: Medium input (default) with comfortable spacing
|
|
174
|
+
|
|
175
|
+
## Accessibility
|
|
176
|
+
|
|
177
|
+
- Proper label-input association with `for` and `id` attributes
|
|
178
|
+
- Hidden label option maintains accessibility
|
|
179
|
+
- Error messages properly associated with input
|
|
180
|
+
- Keyboard navigation support
|
|
181
|
+
- Focus visible states
|
|
182
|
+
- Disabled state properly conveyed to screen readers
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
2
|
+
|
|
3
|
+
import { fn } from '@storybook/test'
|
|
4
|
+
|
|
5
|
+
import Input from './tela-input.vue'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Input> = {
|
|
8
|
+
title: 'Core/Input',
|
|
9
|
+
component: Input,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'centered',
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component: 'A flexible input component that supports both text input and textarea modes. Includes features like labels, error states, icons, clear buttons, and validation feedback. Supports v-model binding for two-way data binding.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
argTypes: {
|
|
19
|
+
id: {
|
|
20
|
+
control: 'text',
|
|
21
|
+
description: 'Unique identifier for the input element. Used for accessibility and form association.',
|
|
22
|
+
},
|
|
23
|
+
modelValue: {
|
|
24
|
+
control: 'text',
|
|
25
|
+
description: 'The input value (v-model). Supports string or number types.',
|
|
26
|
+
},
|
|
27
|
+
label: {
|
|
28
|
+
control: 'text',
|
|
29
|
+
description: 'Label text displayed above or alongside the input field.',
|
|
30
|
+
},
|
|
31
|
+
placeholder: {
|
|
32
|
+
control: 'text',
|
|
33
|
+
description: 'Placeholder text shown when the input is empty.',
|
|
34
|
+
},
|
|
35
|
+
hideLabel: {
|
|
36
|
+
control: 'boolean',
|
|
37
|
+
description: 'Hide the label visually while keeping it accessible for screen readers.',
|
|
38
|
+
},
|
|
39
|
+
disabled: {
|
|
40
|
+
control: 'boolean',
|
|
41
|
+
description: 'Disable the input, preventing user interaction.',
|
|
42
|
+
},
|
|
43
|
+
size: {
|
|
44
|
+
control: 'select',
|
|
45
|
+
options: ['sm', 'md'],
|
|
46
|
+
description: 'Size of the input field. Controls height and padding.',
|
|
47
|
+
},
|
|
48
|
+
error: {
|
|
49
|
+
control: 'text',
|
|
50
|
+
description: 'Error message to display below the input. Set to false to hide error state.',
|
|
51
|
+
},
|
|
52
|
+
showClearButton: {
|
|
53
|
+
control: 'boolean',
|
|
54
|
+
description: 'Show a clear button (X icon) that allows users to quickly clear the input value.',
|
|
55
|
+
},
|
|
56
|
+
tabindex: {
|
|
57
|
+
control: 'number',
|
|
58
|
+
description: 'Tab order of the input element. Use -1 to remove from tab sequence.',
|
|
59
|
+
},
|
|
60
|
+
autofocus: {
|
|
61
|
+
control: 'boolean',
|
|
62
|
+
description: 'Automatically focus the input when the component mounts.',
|
|
63
|
+
},
|
|
64
|
+
autocomplete: {
|
|
65
|
+
control: 'select',
|
|
66
|
+
options: ['off', 'on'],
|
|
67
|
+
description: 'HTML autocomplete attribute value. Controls browser autocomplete behavior.',
|
|
68
|
+
},
|
|
69
|
+
type: {
|
|
70
|
+
control: 'text',
|
|
71
|
+
description: 'Input type. Can be any HTML input type or "textarea" for multiline input.',
|
|
72
|
+
},
|
|
73
|
+
labelClass: {
|
|
74
|
+
control: 'text',
|
|
75
|
+
description: 'Custom CSS classes to apply to the label element.',
|
|
76
|
+
},
|
|
77
|
+
inputFontClass: {
|
|
78
|
+
control: 'text',
|
|
79
|
+
description: 'Custom CSS classes to apply to the input font styling.',
|
|
80
|
+
},
|
|
81
|
+
inputClass: {
|
|
82
|
+
control: 'text',
|
|
83
|
+
description: 'Custom CSS classes to apply to the input element.',
|
|
84
|
+
},
|
|
85
|
+
icon: {
|
|
86
|
+
control: 'text',
|
|
87
|
+
description: 'Icon name or class to display inside the input (typically on the left side).',
|
|
88
|
+
},
|
|
89
|
+
showDescription: {
|
|
90
|
+
control: 'boolean',
|
|
91
|
+
description: 'Show description text below the input field.',
|
|
92
|
+
},
|
|
93
|
+
maxlength: {
|
|
94
|
+
control: 'number',
|
|
95
|
+
description: 'Maximum number of characters allowed in the input.',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
args: {
|
|
99
|
+
'onUpdate:modelValue': fn(),
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default meta
|
|
104
|
+
|
|
105
|
+
type Story = StoryObj<typeof meta>
|
|
106
|
+
|
|
107
|
+
export const TextInput: Story = {
|
|
108
|
+
args: {
|
|
109
|
+
label: 'Label',
|
|
110
|
+
placeholder: 'Enter text',
|
|
111
|
+
autofocus: true,
|
|
112
|
+
modelValue: 'Hello',
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const ClearButton: Story = {
|
|
117
|
+
args: {
|
|
118
|
+
...TextInput.args,
|
|
119
|
+
showClearButton: true,
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const WithIcon: Story = {
|
|
124
|
+
args: {
|
|
125
|
+
...TextInput.args,
|
|
126
|
+
modelValue: 'Search...',
|
|
127
|
+
icon: 'i-ph-magnifying-glass',
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const WithError: Story = {
|
|
132
|
+
args: {
|
|
133
|
+
...TextInput.args,
|
|
134
|
+
modelValue: 'Invalid value',
|
|
135
|
+
error: 'This is an error',
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const Disabled: Story = {
|
|
140
|
+
args: {
|
|
141
|
+
...TextInput.args,
|
|
142
|
+
disabled: true,
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export const Textarea: Story = {
|
|
147
|
+
args: {
|
|
148
|
+
...TextInput.args,
|
|
149
|
+
type: 'textarea',
|
|
150
|
+
placeholder: 'Enter text',
|
|
151
|
+
modelValue: 'In the quiet of the night,\nStars above shining bright,\nWhispers of the moonlight,\nGuide my dreams till morning light.',
|
|
152
|
+
},
|
|
153
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { InputTypeHTMLAttribute } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
id?: string
|
|
6
|
+
modelValue: string | number | undefined
|
|
7
|
+
label?: string
|
|
8
|
+
placeholder?: string
|
|
9
|
+
hideLabel?: boolean
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
size?: 'sm' | 'md'
|
|
12
|
+
error?: string | false
|
|
13
|
+
showClearButton?: boolean
|
|
14
|
+
tabindex?: number
|
|
15
|
+
autofocus?: boolean
|
|
16
|
+
autocomplete?: 'off' | 'on'
|
|
17
|
+
type?: InputTypeHTMLAttribute | 'textarea'
|
|
18
|
+
labelClass?: string
|
|
19
|
+
inputFontClass?: string
|
|
20
|
+
inputClass?: string
|
|
21
|
+
icon?: string
|
|
22
|
+
showDescription?: boolean
|
|
23
|
+
maxlength?: number
|
|
24
|
+
}>()
|
|
25
|
+
|
|
26
|
+
const emit = defineEmits<{
|
|
27
|
+
'focus': []
|
|
28
|
+
'update:modelValue': [string]
|
|
29
|
+
'blur': [string]
|
|
30
|
+
}>()
|
|
31
|
+
|
|
32
|
+
const isTextarea = computed(() => props.type === 'textarea')
|
|
33
|
+
const attributes = computed(() => ({
|
|
34
|
+
size: isTextarea.value ? 'md' : undefined,
|
|
35
|
+
type: isTextarea.value ? undefined : props.type,
|
|
36
|
+
modelValue: props.modelValue,
|
|
37
|
+
value: props.modelValue,
|
|
38
|
+
maxlength: props.maxlength,
|
|
39
|
+
}))
|
|
40
|
+
|
|
41
|
+
function handleInput(data: Event | string) {
|
|
42
|
+
if (isTextarea.value)
|
|
43
|
+
emit('update:modelValue', ((data as Event).target as HTMLInputElement).value)
|
|
44
|
+
else
|
|
45
|
+
emit('update:modelValue', ((data as Event).target as HTMLInputElement).value)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function handleBlur(data: Event | string) {
|
|
49
|
+
if (isTextarea.value)
|
|
50
|
+
emit('blur', data as string)
|
|
51
|
+
else
|
|
52
|
+
emit('blur', ((data as Event).target as HTMLInputElement).value)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function clearContent() {
|
|
56
|
+
emit('update:modelValue', '')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const container = ref<HTMLElement>()
|
|
60
|
+
const { textarea: inputRef, input: textareaInput } = useTextareaAutosize({ styleProp: 'minHeight' })
|
|
61
|
+
|
|
62
|
+
function focusInput() {
|
|
63
|
+
if (container.value) {
|
|
64
|
+
setTimeout(() => container.value!.querySelector(isTextarea.value ? 'textarea' : 'input')?.focus(), 100)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onMounted(() => {
|
|
69
|
+
if (container.value && container.value.attributes.getNamedItem('data-testid')) {
|
|
70
|
+
const testId = container.value.attributes.getNamedItem('data-testid')?.value as string
|
|
71
|
+
|
|
72
|
+
// Remove the data-testid attribute from the container element
|
|
73
|
+
container.value.removeAttribute('data-testid')
|
|
74
|
+
|
|
75
|
+
// Add the data-testid attribute to the input element
|
|
76
|
+
inputRef.value?.setAttribute('data-testid', testId)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (props.autofocus) {
|
|
80
|
+
focusInput()
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const trailingContent = useTemplateRef('trailing-content')
|
|
85
|
+
const { width: trailingWidth } = useElementBounding(trailingContent)
|
|
86
|
+
|
|
87
|
+
const errorContainerRef = ref<HTMLElement>()
|
|
88
|
+
const isErrorTruncated = ref(false)
|
|
89
|
+
|
|
90
|
+
function checkTruncation() {
|
|
91
|
+
if (!errorContainerRef.value)
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
const span = errorContainerRef.value.querySelector('span')
|
|
95
|
+
if (span) {
|
|
96
|
+
isErrorTruncated.value = span.scrollWidth > span.clientWidth
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
watch(() => props.error, async () => {
|
|
101
|
+
if (props.error) {
|
|
102
|
+
await nextTick()
|
|
103
|
+
checkTruncation()
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
isErrorTruncated.value = false
|
|
107
|
+
}
|
|
108
|
+
}, { immediate: true })
|
|
109
|
+
|
|
110
|
+
useResizeObserver(errorContainerRef, () => {
|
|
111
|
+
checkTruncation()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
defineExpose({
|
|
115
|
+
focusInput,
|
|
116
|
+
})
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<template>
|
|
120
|
+
<div ref="container" flex="~ col" relative>
|
|
121
|
+
<div
|
|
122
|
+
relative
|
|
123
|
+
transition
|
|
124
|
+
cursor-text
|
|
125
|
+
overflow-hidden
|
|
126
|
+
px-3 py-8px
|
|
127
|
+
b="0.5px gray-300"
|
|
128
|
+
rounded-10px bg-white
|
|
129
|
+
class="focus-within-b-gray-400 focus-within-ring-2 focus-within-ring-gray-100"
|
|
130
|
+
:class="[
|
|
131
|
+
size === 'sm' && 'py-7px !px-12px',
|
|
132
|
+
disabled && '!bg-gray-50 cursor-not-allowed color-gray-600',
|
|
133
|
+
$attrs.class,
|
|
134
|
+
error && '!border-red-900 !text-red-900 !bg-[#FFDBDB66]',
|
|
135
|
+
props.inputClass,
|
|
136
|
+
]"
|
|
137
|
+
flex items-center
|
|
138
|
+
@click="$el.querySelector(isTextarea ? 'textarea' : 'input')?.focus()"
|
|
139
|
+
>
|
|
140
|
+
<div v-if="icon" flex mr-6px>
|
|
141
|
+
<TelaIcon :name="icon" size="sm" text="gray-600" />
|
|
142
|
+
</div>
|
|
143
|
+
<div
|
|
144
|
+
flex="~ col" grow align-center h-full
|
|
145
|
+
:style="{
|
|
146
|
+
marginRight: `${trailingWidth - 0}px`,
|
|
147
|
+
}"
|
|
148
|
+
>
|
|
149
|
+
<label
|
|
150
|
+
v-if="label"
|
|
151
|
+
:for="id"
|
|
152
|
+
text="12px #68787A"
|
|
153
|
+
leading-20px
|
|
154
|
+
flex
|
|
155
|
+
align-center
|
|
156
|
+
:class="[disabled && 'cursor-not-allowed', props.labelClass]"
|
|
157
|
+
>
|
|
158
|
+
|
|
159
|
+
<slot name="label-leading" />
|
|
160
|
+
{{ label }}
|
|
161
|
+
</label>
|
|
162
|
+
<component
|
|
163
|
+
:is="isTextarea ? 'textarea' : 'input'"
|
|
164
|
+
:id="id"
|
|
165
|
+
ref="inputRef"
|
|
166
|
+
v-bind="attributes"
|
|
167
|
+
v-model="textareaInput"
|
|
168
|
+
:name="placeholder"
|
|
169
|
+
variant="none"
|
|
170
|
+
:autocomplete="autocomplete"
|
|
171
|
+
:placeholder="placeholder"
|
|
172
|
+
:rows="1"
|
|
173
|
+
autoresize
|
|
174
|
+
w-full
|
|
175
|
+
bg-transparent
|
|
176
|
+
z-0
|
|
177
|
+
h-full
|
|
178
|
+
class="placeholder-gray-300 focus-visible:outline-none! leading-170% tracking-.01em"
|
|
179
|
+
resize-none
|
|
180
|
+
:disabled="disabled"
|
|
181
|
+
:tabindex="tabindex"
|
|
182
|
+
:class="[
|
|
183
|
+
disabled && 'cursor-not-allowed',
|
|
184
|
+
size === 'sm' && 'leading-20px body-14-regular placeholder:body-14-regular',
|
|
185
|
+
props.inputFontClass ? props.inputFontClass : 'text-14px',
|
|
186
|
+
!isTextarea && '!h-1.7em',
|
|
187
|
+
]"
|
|
188
|
+
@input="handleInput"
|
|
189
|
+
@update:model-value="handleInput"
|
|
190
|
+
@blur="handleBlur"
|
|
191
|
+
@focus="emit('focus')"
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<div v-if="!showClearButton" ref="trailing-content" absolute top-0 right-0 :bg="error ? '' : 'bg-inherit'" h-full flex="~ col" px-8px>
|
|
196
|
+
<div flex-auto />
|
|
197
|
+
<slot name="trailing" />
|
|
198
|
+
<div flex-auto />
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div v-if="showDescription" class="body-12-regular text-gray-500">
|
|
202
|
+
<slot name="description" />
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div v-if="showClearButton && modelValue" class="top-60% -translate-y-60%" right-1 absolute>
|
|
206
|
+
<TelaTooltip
|
|
207
|
+
:content="$t('common.clear')"
|
|
208
|
+
>
|
|
209
|
+
<button
|
|
210
|
+
hover:bg="#EBEFF199"
|
|
211
|
+
transition
|
|
212
|
+
p-4px rounded-full
|
|
213
|
+
class="group"
|
|
214
|
+
tabindex="-1"
|
|
215
|
+
@click="clearContent"
|
|
216
|
+
>
|
|
217
|
+
<TelaIcon name="i-ph-x-circle-light" text="#031E22" op-40 group-hover:op-100 transition />
|
|
218
|
+
</button>
|
|
219
|
+
</TelaTooltip>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
<TelaTooltip
|
|
223
|
+
v-if="error"
|
|
224
|
+
:content="error"
|
|
225
|
+
:disabled="!isErrorTruncated"
|
|
226
|
+
content-class="max-w-300px break-words z-[12000]"
|
|
227
|
+
>
|
|
228
|
+
<div
|
|
229
|
+
ref="errorContainerRef"
|
|
230
|
+
absolute bottom--14px left-0 right-0
|
|
231
|
+
body-10-medium text-red-900 flex items-center gap-3px
|
|
232
|
+
overflow-hidden text-ellipsis whitespace-nowrap
|
|
233
|
+
pr-2
|
|
234
|
+
>
|
|
235
|
+
<TelaIcon name="i-ph-warning-bold" size="sm" text="red-900" text-16px flex-shrink-0 />
|
|
236
|
+
<span class="overflow-hidden text-ellipsis">{{ error }}</span>
|
|
237
|
+
</div>
|
|
238
|
+
</TelaTooltip>
|
|
239
|
+
</div>
|
|
240
|
+
</template>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div h-20px w-20px bg="#EFF0F3" rounded-4px relative>
|
|
3
|
+
<div h-10px w-12px bg="#60798F" rounded-4px absolute class="top-50% translate-y--50% left-50% translate-x--50%" />
|
|
4
|
+
<TelaIcon name="i-ph-key-return-fill" class="h-20px! w-20px!" color="#EFF0F3" absolute top-0px left-0px />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|