@nuvia-ui/components 4.0.1
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/package.json +27 -0
- package/src/ds-accordion/ds-accordion-item.js +288 -0
- package/src/ds-accordion/ds-accordion-item.stories.js +82 -0
- package/src/ds-accordion/ds-accordion.a11y.test.js +92 -0
- package/src/ds-accordion/ds-accordion.js +68 -0
- package/src/ds-accordion/ds-accordion.stories.js +118 -0
- package/src/ds-accordion/ds-accordion.test.js +146 -0
- package/src/ds-accordion/index.js +2 -0
- package/src/ds-action-bar/ds-action-bar.js +116 -0
- package/src/ds-action-bar/ds-action-bar.stories.js +86 -0
- package/src/ds-action-bar/ds-action-bar.test.js +64 -0
- package/src/ds-action-bar/index.js +1 -0
- package/src/ds-alert/ds-alert.a11y.test.js +151 -0
- package/src/ds-alert/ds-alert.js +223 -0
- package/src/ds-alert/ds-alert.mdx +142 -0
- package/src/ds-alert/ds-alert.stories.js +166 -0
- package/src/ds-alert/ds-alert.test.js +256 -0
- package/src/ds-alert/index.js +1 -0
- package/src/ds-avatar/ds-avatar.a11y.test.js +45 -0
- package/src/ds-avatar/ds-avatar.js +216 -0
- package/src/ds-avatar/ds-avatar.stories.js +120 -0
- package/src/ds-avatar/ds-avatar.test.js +83 -0
- package/src/ds-avatar/index.js +1 -0
- package/src/ds-avatar-extended/ds-avatar-extended.a11y.test.js +29 -0
- package/src/ds-avatar-extended/ds-avatar-extended.js +108 -0
- package/src/ds-avatar-extended/ds-avatar-extended.stories.js +93 -0
- package/src/ds-avatar-extended/ds-avatar-extended.test.js +66 -0
- package/src/ds-avatar-extended/index.js +1 -0
- package/src/ds-banner/ds-banner.a11y.test.js +51 -0
- package/src/ds-banner/ds-banner.js +233 -0
- package/src/ds-banner/ds-banner.stories.js +185 -0
- package/src/ds-banner/ds-banner.test.js +116 -0
- package/src/ds-banner/index.js +1 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.js +135 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.stories.js +49 -0
- package/src/ds-breadcrumb-item/ds-breadcrumb-item.test.js +55 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.js +194 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.stories.js +54 -0
- package/src/ds-breadcrumbs/ds-breadcrumbs.test.js +33 -0
- package/src/ds-button/ds-button.a11y.test.js +49 -0
- package/src/ds-button/ds-button.js +205 -0
- package/src/ds-button/ds-button.mdx +141 -0
- package/src/ds-button/ds-button.stories.js +152 -0
- package/src/ds-button/ds-button.test.js +62 -0
- package/src/ds-button/index.js +1 -0
- package/src/ds-button-group/ds-button-group.js +82 -0
- package/src/ds-button-group/ds-button-group.mdx +39 -0
- package/src/ds-button-group/ds-button-group.stories.js +47 -0
- package/src/ds-button-group/ds-button-group.test.js +47 -0
- package/src/ds-button-group/index.js +1 -0
- package/src/ds-checkbox/ds-checkbox.a11y.test.js +79 -0
- package/src/ds-checkbox/ds-checkbox.js +271 -0
- package/src/ds-checkbox/ds-checkbox.stories.js +77 -0
- package/src/ds-checkbox/ds-checkbox.test.js +191 -0
- package/src/ds-checkbox/index.js +1 -0
- package/src/ds-checkbox-group/ds-checkbox-group.a11y.test.js +146 -0
- package/src/ds-checkbox-group/ds-checkbox-group.js +235 -0
- package/src/ds-checkbox-group/ds-checkbox-group.stories.js +210 -0
- package/src/ds-checkbox-group/ds-checkbox-group.test.js +150 -0
- package/src/ds-checkbox-group/index.js +1 -0
- package/src/ds-dialog/ds-dialog.js +466 -0
- package/src/ds-dialog/ds-dialog.stories.js +274 -0
- package/src/ds-dialog/ds-dialog.test.js +441 -0
- package/src/ds-dialog/index.js +1 -0
- package/src/ds-dropdown/ds-dropdown.a11y.test.js +80 -0
- package/src/ds-dropdown/ds-dropdown.js +891 -0
- package/src/ds-dropdown/ds-dropdown.stories.js +259 -0
- package/src/ds-dropdown/ds-dropdown.test.js +268 -0
- package/src/ds-dropdown/index.js +1 -0
- package/src/ds-dropdown-group/ds-dropdown-group.js +55 -0
- package/src/ds-dropdown-panel/ds-dropdown-panel.js +34 -0
- package/src/ds-file-uploaded/ds-file-uploaded.a11y.test.js +40 -0
- package/src/ds-file-uploaded/ds-file-uploaded.js +135 -0
- package/src/ds-file-uploaded/ds-file-uploaded.mdx +33 -0
- package/src/ds-file-uploaded/ds-file-uploaded.stories.js +81 -0
- package/src/ds-file-uploaded/ds-file-uploaded.test.js +85 -0
- package/src/ds-file-uploader/ds-file-uploader.a11y.test.js +61 -0
- package/src/ds-file-uploader/ds-file-uploader.js +442 -0
- package/src/ds-file-uploader/ds-file-uploader.mdx +44 -0
- package/src/ds-file-uploader/ds-file-uploader.stories.js +76 -0
- package/src/ds-file-uploader/ds-file-uploader.test.js +142 -0
- package/src/ds-header/ds-header.a11y.test.js +38 -0
- package/src/ds-header/ds-header.js +149 -0
- package/src/ds-header/ds-header.stories.js +63 -0
- package/src/ds-header/ds-header.test.js +52 -0
- package/src/ds-header/index.js +1 -0
- package/src/ds-header-nav/ds-header-nav.a11y.test.js +69 -0
- package/src/ds-header-nav/ds-header-nav.js +114 -0
- package/src/ds-header-nav/ds-header-nav.stories.js +17 -0
- package/src/ds-header-nav/ds-header-nav.test.js +93 -0
- package/src/ds-header-nav-item/ds-header-nav-item.a11y.test.js +71 -0
- package/src/ds-header-nav-item/ds-header-nav-item.js +124 -0
- package/src/ds-header-nav-item/ds-header-nav-item.stories.js +43 -0
- package/src/ds-header-nav-item/ds-header-nav-item.test.js +61 -0
- package/src/ds-icon/ds-icon.a11y.test.js +49 -0
- package/src/ds-icon/ds-icon.js +75 -0
- package/src/ds-icon/ds-icon.mdx +36 -0
- package/src/ds-icon/ds-icon.stories.js +88 -0
- package/src/ds-icon/ds-icon.test.js +97 -0
- package/src/ds-icon/index.js +1 -0
- package/src/ds-icon-button/ds-icon-button.a11y.test.js +55 -0
- package/src/ds-icon-button/ds-icon-button.js +224 -0
- package/src/ds-icon-button/ds-icon-button.mdx +131 -0
- package/src/ds-icon-button/ds-icon-button.stories.js +128 -0
- package/src/ds-icon-button/ds-icon-button.test.js +90 -0
- package/src/ds-icon-button/index.js +1 -0
- package/src/ds-input/ds-input.a11y.test.js +145 -0
- package/src/ds-input/ds-input.js +645 -0
- package/src/ds-input/ds-input.mdx +251 -0
- package/src/ds-input/ds-input.stories.js +298 -0
- package/src/ds-input/ds-input.test.js +792 -0
- package/src/ds-input/index.js +1 -0
- package/src/ds-link/ds-link.js +111 -0
- package/src/ds-link/ds-link.stories.js +56 -0
- package/src/ds-link/ds-link.test.js +74 -0
- package/src/ds-list-item/ds-list-item.a11y.test.js +39 -0
- package/src/ds-list-item/ds-list-item.js +292 -0
- package/src/ds-list-item/ds-list-item.stories.js +101 -0
- package/src/ds-list-item/ds-list-item.test.js +63 -0
- package/src/ds-menu/ds-menu.js +30 -0
- package/src/ds-menu/ds-menu.stories.js +120 -0
- package/src/ds-menu/ds-menu.test.js +123 -0
- package/src/ds-menu-group/ds-menu-group.js +101 -0
- package/src/ds-menu-group/ds-menu-group.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.a11y.test.js +91 -0
- package/src/ds-nav-item/ds-nav-item.js +307 -0
- package/src/ds-nav-item/ds-nav-item.stories.js +99 -0
- package/src/ds-nav-item/ds-nav-item.test.js +169 -0
- package/src/ds-nav-item/index.js +1 -0
- package/src/ds-nav-vertical/ds-nav-vertical.a11y.test.js +69 -0
- package/src/ds-nav-vertical/ds-nav-vertical.js +173 -0
- package/src/ds-nav-vertical/ds-nav-vertical.stories.js +124 -0
- package/src/ds-nav-vertical/ds-nav-vertical.test.js +176 -0
- package/src/ds-nav-vertical/index.js +1 -0
- package/src/ds-pagination/ds-pagination.a11y.test.js +50 -0
- package/src/ds-pagination/ds-pagination.js +232 -0
- package/src/ds-pagination/ds-pagination.stories.js +63 -0
- package/src/ds-pagination/ds-pagination.test.js +141 -0
- package/src/ds-pagination/index.js +1 -0
- package/src/ds-progress-bar/ds-progress-bar.a11y.test.js +25 -0
- package/src/ds-progress-bar/ds-progress-bar.js +81 -0
- package/src/ds-progress-bar/ds-progress-bar.stories.js +69 -0
- package/src/ds-progress-bar/ds-progress-bar.test.js +60 -0
- package/src/ds-radio/ds-radio.a11y.test.js +69 -0
- package/src/ds-radio/ds-radio.js +240 -0
- package/src/ds-radio/ds-radio.stories.js +102 -0
- package/src/ds-radio/ds-radio.test.js +114 -0
- package/src/ds-radio/index.js +1 -0
- package/src/ds-radio-group/ds-radio-group.a11y.test.js +164 -0
- package/src/ds-radio-group/ds-radio-group.js +257 -0
- package/src/ds-radio-group/ds-radio-group.stories.js +247 -0
- package/src/ds-radio-group/ds-radio-group.test.js +194 -0
- package/src/ds-radio-group/index.js +1 -0
- package/src/ds-rich-list/ds-rich-list.js +246 -0
- package/src/ds-rich-list/ds-rich-list.stories.js +368 -0
- package/src/ds-rich-list/ds-rich-list.test.js +293 -0
- package/src/ds-rich-list-item/ds-rich-list-item.js +579 -0
- package/src/ds-rich-list-item/ds-rich-list-item.stories.js +197 -0
- package/src/ds-rich-list-item/ds-rich-list-item.test.js +434 -0
- package/src/ds-slider/ds-slider.js +399 -0
- package/src/ds-slider/ds-slider.stories.js +107 -0
- package/src/ds-slider/ds-slider.test.js +308 -0
- package/src/ds-spinner/ds-spinner.js +173 -0
- package/src/ds-spinner/ds-spinner.stories.js +52 -0
- package/src/ds-spinner/ds-spinner.test.js +50 -0
- package/src/ds-status-border/ds-status-border.js +88 -0
- package/src/ds-status-border/ds-status-border.stories.js +242 -0
- package/src/ds-status-border/ds-status-border.test.js +168 -0
- package/src/ds-stepper/ds-stepper.a11y.test.js +198 -0
- package/src/ds-stepper/ds-stepper.js +207 -0
- package/src/ds-stepper/ds-stepper.stories.js +530 -0
- package/src/ds-stepper/ds-stepper.test.js +311 -0
- package/src/ds-stepper-item/ds-stepper-item.js +485 -0
- package/src/ds-stepper-item/ds-stepper-item.stories.js +288 -0
- package/src/ds-switch/ds-switch.js +348 -0
- package/src/ds-switch/ds-switch.stories.js +145 -0
- package/src/ds-switch/ds-switch.test.js +226 -0
- package/src/ds-switch/index.js +1 -0
- package/src/ds-tab-item/ds-tab-item.js +341 -0
- package/src/ds-tab-item/ds-tab-item.stories.js +69 -0
- package/src/ds-tabs/ds-tab-panel.js +48 -0
- package/src/ds-tabs/ds-tabs.a11y.test.js +56 -0
- package/src/ds-tabs/ds-tabs.js +180 -0
- package/src/ds-tabs/ds-tabs.stories.js +152 -0
- package/src/ds-tabs/ds-tabs.test.js +306 -0
- package/src/ds-tabs/index.js +3 -0
- package/src/ds-tag-action/ds-tag-action.a11y.test.js +32 -0
- package/src/ds-tag-action/ds-tag-action.js +185 -0
- package/src/ds-tag-action/ds-tag-action.stories.js +55 -0
- package/src/ds-tag-action/ds-tag-action.test.js +44 -0
- package/src/ds-tag-removable/ds-tag-removable.a11y.test.js +24 -0
- package/src/ds-tag-removable/ds-tag-removable.js +146 -0
- package/src/ds-tag-removable/ds-tag-removable.stories.js +52 -0
- package/src/ds-tag-removable/ds-tag-removable.test.js +46 -0
- package/src/ds-tag-status/ds-tag-status.a11y.test.js +93 -0
- package/src/ds-tag-status/ds-tag-status.js +164 -0
- package/src/ds-tag-status/ds-tag-status.stories.js +200 -0
- package/src/ds-tag-status/ds-tag-status.test.js +140 -0
- package/src/ds-tag-status/index.js +1 -0
- package/src/ds-textarea/ds-textarea-clearable.test.js +89 -0
- package/src/ds-textarea/ds-textarea.a11y.test.js +66 -0
- package/src/ds-textarea/ds-textarea.js +505 -0
- package/src/ds-textarea/ds-textarea.stories.js +335 -0
- package/src/ds-textarea/ds-textarea.test.js +218 -0
- package/src/ds-textarea/index.js +1 -0
- package/src/ds-thumbnail/ds-thumbnail.js +207 -0
- package/src/ds-thumbnail/ds-thumbnail.stories.js +217 -0
- package/src/ds-thumbnail/ds-thumbnail.test.js +220 -0
- package/src/ds-toast/ds-toast-provider.js +110 -0
- package/src/ds-toast/ds-toast.a11y.test.js +34 -0
- package/src/ds-toast/ds-toast.js +243 -0
- package/src/ds-toast/ds-toast.stories.js +143 -0
- package/src/ds-toast/ds-toast.test.js +93 -0
- package/src/ds-toast/index.js +2 -0
- package/src/ds-tooltip/ds-tooltip.a11y.test.js +110 -0
- package/src/ds-tooltip/ds-tooltip.js +217 -0
- package/src/ds-tooltip/ds-tooltip.mdx +75 -0
- package/src/ds-tooltip/ds-tooltip.stories.js +72 -0
- package/src/ds-tooltip/ds-tooltip.test.js +191 -0
- package/src/ds-tooltip/index.js +1 -0
- package/src/ds-tooltip/positioner.js +117 -0
- package/src/index.js +50 -0
- package/src/mixins/field-label.mixin.js +113 -0
- package/src/mixins/field-message.mixin.js +66 -0
- package/src/token-provider/index.js +1 -0
- package/src/token-provider/token-provider.a11y.test.js +44 -0
- package/src/token-provider/token-provider.js +85 -0
- package/src/token-provider/token-provider.stories.js +105 -0
- package/src/token-provider/token-provider.test.js +134 -0
- package/src/utils/number-input.utils.js +42 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { html, nothing } from 'lit';
|
|
2
|
+
import './ds-textarea.js';
|
|
3
|
+
import '../token-provider/token-provider.js';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Textarea',
|
|
7
|
+
component: 'ds-textarea',
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
argTypes: {
|
|
10
|
+
label: { control: 'text' },
|
|
11
|
+
info: { control: 'text' },
|
|
12
|
+
labelPosition: {
|
|
13
|
+
control: 'select',
|
|
14
|
+
options: ['top', 'inline-start']
|
|
15
|
+
},
|
|
16
|
+
labelWidth: { control: 'text' },
|
|
17
|
+
placeholder: { control: 'text' },
|
|
18
|
+
value: { control: 'text' },
|
|
19
|
+
helper: { control: 'text' },
|
|
20
|
+
validationStatus: {
|
|
21
|
+
control: 'select',
|
|
22
|
+
options: ['', 'error', 'success']
|
|
23
|
+
},
|
|
24
|
+
validationMessage: { control: 'text' },
|
|
25
|
+
disabled: { control: 'boolean' },
|
|
26
|
+
readonly: { control: 'boolean' },
|
|
27
|
+
required: { control: 'boolean' },
|
|
28
|
+
rows: { control: 'number' },
|
|
29
|
+
minlength: { control: 'number' },
|
|
30
|
+
maxlength: { control: 'number' },
|
|
31
|
+
showCounter: { control: 'boolean' },
|
|
32
|
+
resize: {
|
|
33
|
+
control: 'select',
|
|
34
|
+
options: ['none', 'vertical']
|
|
35
|
+
},
|
|
36
|
+
autoResize: { control: 'boolean' },
|
|
37
|
+
clearable: { control: 'boolean' }
|
|
38
|
+
},
|
|
39
|
+
args: {
|
|
40
|
+
label: 'Description',
|
|
41
|
+
info: '',
|
|
42
|
+
labelPosition: 'top',
|
|
43
|
+
labelWidth: '',
|
|
44
|
+
placeholder: 'Enter your text here...',
|
|
45
|
+
value: '',
|
|
46
|
+
helper: '',
|
|
47
|
+
validationStatus: '',
|
|
48
|
+
validationMessage: '',
|
|
49
|
+
disabled: false,
|
|
50
|
+
readonly: false,
|
|
51
|
+
required: false,
|
|
52
|
+
rows: 3,
|
|
53
|
+
minlength: undefined,
|
|
54
|
+
maxlength: undefined,
|
|
55
|
+
showCounter: false,
|
|
56
|
+
resize: 'vertical',
|
|
57
|
+
autoResize: false,
|
|
58
|
+
clearable: false
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Default = {
|
|
63
|
+
render: (args) => html`
|
|
64
|
+
<ds-textarea
|
|
65
|
+
label="${args.label}"
|
|
66
|
+
info="${args.info || nothing}"
|
|
67
|
+
label-position="${args.labelPosition || nothing}"
|
|
68
|
+
label-width="${args.labelWidth || nothing}"
|
|
69
|
+
placeholder="${args.placeholder}"
|
|
70
|
+
value="${args.value}"
|
|
71
|
+
helper="${args.helper || nothing}"
|
|
72
|
+
validation-status="${args.validationStatus || nothing}"
|
|
73
|
+
validation-message="${args.validationMessage || nothing}"
|
|
74
|
+
?disabled="${args.disabled}"
|
|
75
|
+
?readonly="${args.readonly}"
|
|
76
|
+
?required="${args.required}"
|
|
77
|
+
rows="${args.rows}"
|
|
78
|
+
minlength="${args.minlength || nothing}"
|
|
79
|
+
maxlength="${args.maxlength || nothing}"
|
|
80
|
+
?show-counter="${args.showCounter}"
|
|
81
|
+
resize="${args.resize}"
|
|
82
|
+
?auto-resize="${args.autoResize}"
|
|
83
|
+
?clearable="${args.clearable}"
|
|
84
|
+
></ds-textarea>
|
|
85
|
+
`
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const WithCounter = {
|
|
89
|
+
args: {
|
|
90
|
+
label: 'Bio',
|
|
91
|
+
placeholder: 'Tell us about yourself...',
|
|
92
|
+
maxlength: 200,
|
|
93
|
+
showCounter: true,
|
|
94
|
+
helper: 'Maximum 200 characters'
|
|
95
|
+
},
|
|
96
|
+
render: (args) => html`
|
|
97
|
+
<ds-textarea
|
|
98
|
+
label="${args.label}"
|
|
99
|
+
placeholder="${args.placeholder}"
|
|
100
|
+
maxlength="${args.maxlength}"
|
|
101
|
+
?show-counter="${args.showCounter}"
|
|
102
|
+
helper="${args.helper}"
|
|
103
|
+
></ds-textarea>
|
|
104
|
+
`
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const WithError = {
|
|
108
|
+
args: {
|
|
109
|
+
label: 'Comments',
|
|
110
|
+
value: 'Too short',
|
|
111
|
+
validationStatus: 'error',
|
|
112
|
+
validationMessage: 'Comment must be at least 10 characters',
|
|
113
|
+
minlength: 10,
|
|
114
|
+
maxlength: 500,
|
|
115
|
+
showCounter: true
|
|
116
|
+
},
|
|
117
|
+
render: (args) => html`
|
|
118
|
+
<ds-textarea
|
|
119
|
+
label="${args.label}"
|
|
120
|
+
value="${args.value}"
|
|
121
|
+
validation-status="${args.validationStatus}"
|
|
122
|
+
validation-message="${args.validationMessage}"
|
|
123
|
+
minlength="${args.minlength}"
|
|
124
|
+
maxlength="${args.maxlength}"
|
|
125
|
+
?show-counter="${args.showCounter}"
|
|
126
|
+
></ds-textarea>
|
|
127
|
+
`
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const AutoResize = {
|
|
131
|
+
args: {
|
|
132
|
+
label: 'Auto-growing textarea',
|
|
133
|
+
placeholder: 'Type something and watch it grow...',
|
|
134
|
+
helper: 'This textarea automatically grows with your content',
|
|
135
|
+
autoResize: true,
|
|
136
|
+
rows: 2
|
|
137
|
+
},
|
|
138
|
+
render: (args) => html`
|
|
139
|
+
<ds-textarea
|
|
140
|
+
label="${args.label}"
|
|
141
|
+
placeholder="${args.placeholder}"
|
|
142
|
+
helper="${args.helper}"
|
|
143
|
+
?auto-resize="${args.autoResize}"
|
|
144
|
+
rows="${args.rows}"
|
|
145
|
+
></ds-textarea>
|
|
146
|
+
`
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const ResizeNone = {
|
|
150
|
+
args: {
|
|
151
|
+
label: 'Fixed height textarea',
|
|
152
|
+
placeholder: 'This textarea cannot be resized manually',
|
|
153
|
+
resize: 'none',
|
|
154
|
+
rows: 5
|
|
155
|
+
},
|
|
156
|
+
render: (args) => html`
|
|
157
|
+
<ds-textarea
|
|
158
|
+
label="${args.label}"
|
|
159
|
+
placeholder="${args.placeholder}"
|
|
160
|
+
resize="${args.resize}"
|
|
161
|
+
rows="${args.rows}"
|
|
162
|
+
></ds-textarea>
|
|
163
|
+
`
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const Disabled = {
|
|
167
|
+
args: {
|
|
168
|
+
label: 'Disabled textarea',
|
|
169
|
+
value: 'This content cannot be edited',
|
|
170
|
+
disabled: true,
|
|
171
|
+
rows: 4
|
|
172
|
+
},
|
|
173
|
+
render: (args) => html`
|
|
174
|
+
<ds-textarea
|
|
175
|
+
label="${args.label}"
|
|
176
|
+
value="${args.value}"
|
|
177
|
+
?disabled="${args.disabled}"
|
|
178
|
+
rows="${args.rows}"
|
|
179
|
+
></ds-textarea>
|
|
180
|
+
`
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const Readonly = {
|
|
184
|
+
args: {
|
|
185
|
+
label: 'Read-only textarea',
|
|
186
|
+
value: 'This content is read-only and can be selected but not modified.',
|
|
187
|
+
readonly: true,
|
|
188
|
+
rows: 3
|
|
189
|
+
},
|
|
190
|
+
render: (args) => html`
|
|
191
|
+
<ds-textarea
|
|
192
|
+
label="${args.label}"
|
|
193
|
+
value="${args.value}"
|
|
194
|
+
?readonly="${args.readonly}"
|
|
195
|
+
rows="${args.rows}"
|
|
196
|
+
></ds-textarea>
|
|
197
|
+
`
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const WithInfo = {
|
|
201
|
+
args: {
|
|
202
|
+
label: 'Feedback',
|
|
203
|
+
info: 'Please provide detailed feedback about your experience',
|
|
204
|
+
placeholder: 'Share your thoughts...',
|
|
205
|
+
maxlength: 1000,
|
|
206
|
+
showCounter: true,
|
|
207
|
+
rows: 5
|
|
208
|
+
},
|
|
209
|
+
render: (args) => html`
|
|
210
|
+
<ds-textarea
|
|
211
|
+
label="${args.label}"
|
|
212
|
+
info="${args.info}"
|
|
213
|
+
placeholder="${args.placeholder}"
|
|
214
|
+
maxlength="${args.maxlength}"
|
|
215
|
+
?show-counter="${args.showCounter}"
|
|
216
|
+
rows="${args.rows}"
|
|
217
|
+
></ds-textarea>
|
|
218
|
+
`
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export const Clearable = {
|
|
222
|
+
args: {
|
|
223
|
+
label: 'Clearable textarea',
|
|
224
|
+
value: 'This text can be cleared',
|
|
225
|
+
clearable: true,
|
|
226
|
+
helper: 'Focus the field to see the clear button (or press Escape)',
|
|
227
|
+
rows: 3
|
|
228
|
+
},
|
|
229
|
+
render: (args) => html`
|
|
230
|
+
<ds-textarea
|
|
231
|
+
label="${args.label}"
|
|
232
|
+
value="${args.value}"
|
|
233
|
+
?clearable="${args.clearable}"
|
|
234
|
+
helper="${args.helper}"
|
|
235
|
+
rows="${args.rows}"
|
|
236
|
+
></ds-textarea>
|
|
237
|
+
`
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
export const AllStates = {
|
|
241
|
+
render: () => html`
|
|
242
|
+
<div style="display: flex; flex-direction: column; gap: 24px;">
|
|
243
|
+
<ds-textarea
|
|
244
|
+
label="Default"
|
|
245
|
+
placeholder="Enter text..."
|
|
246
|
+
rows="3"
|
|
247
|
+
></ds-textarea>
|
|
248
|
+
|
|
249
|
+
<ds-textarea
|
|
250
|
+
label="With counter"
|
|
251
|
+
maxlength="100"
|
|
252
|
+
show-counter
|
|
253
|
+
value="Sample text"
|
|
254
|
+
rows="3"
|
|
255
|
+
></ds-textarea>
|
|
256
|
+
|
|
257
|
+
<ds-textarea
|
|
258
|
+
label="Auto-resize"
|
|
259
|
+
placeholder="Grows automatically..."
|
|
260
|
+
auto-resize
|
|
261
|
+
rows="2"
|
|
262
|
+
></ds-textarea>
|
|
263
|
+
|
|
264
|
+
<ds-textarea
|
|
265
|
+
label="With error"
|
|
266
|
+
value="Too short"
|
|
267
|
+
validation-status="error"
|
|
268
|
+
validation-message="Minimum 20 characters required"
|
|
269
|
+
minlength="20"
|
|
270
|
+
rows="3"
|
|
271
|
+
></ds-textarea>
|
|
272
|
+
|
|
273
|
+
<ds-textarea
|
|
274
|
+
label="Disabled"
|
|
275
|
+
value="Disabled content"
|
|
276
|
+
disabled
|
|
277
|
+
rows="3"
|
|
278
|
+
></ds-textarea>
|
|
279
|
+
|
|
280
|
+
<ds-textarea
|
|
281
|
+
label="Read-only"
|
|
282
|
+
value="Read-only content that can be selected"
|
|
283
|
+
readonly
|
|
284
|
+
rows="3"
|
|
285
|
+
></ds-textarea>
|
|
286
|
+
|
|
287
|
+
<ds-textarea
|
|
288
|
+
label="Fixed height (no resize)"
|
|
289
|
+
resize="none"
|
|
290
|
+
placeholder="Cannot be resized manually"
|
|
291
|
+
rows="4"
|
|
292
|
+
></ds-textarea>
|
|
293
|
+
|
|
294
|
+
<ds-textarea
|
|
295
|
+
label="With info button"
|
|
296
|
+
info="This is additional information about this field"
|
|
297
|
+
placeholder="Enter description..."
|
|
298
|
+
rows="3"
|
|
299
|
+
></ds-textarea>
|
|
300
|
+
|
|
301
|
+
<ds-textarea
|
|
302
|
+
label="Clearable"
|
|
303
|
+
value="Focus me to see clear button"
|
|
304
|
+
clearable
|
|
305
|
+
helper="Press Escape or click the X button to clear"
|
|
306
|
+
rows="3"
|
|
307
|
+
></ds-textarea>
|
|
308
|
+
</div>
|
|
309
|
+
`
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
export const InlineLabel = {
|
|
313
|
+
args: {
|
|
314
|
+
label: 'Description',
|
|
315
|
+
labelPosition: 'inline-start',
|
|
316
|
+
labelWidth: '120px',
|
|
317
|
+
placeholder: 'Enter your text...',
|
|
318
|
+
helper: 'Label is positioned inline with the field',
|
|
319
|
+
maxlength: 200,
|
|
320
|
+
showCounter: true,
|
|
321
|
+
rows: 4
|
|
322
|
+
},
|
|
323
|
+
render: (args) => html`
|
|
324
|
+
<ds-textarea
|
|
325
|
+
label="${args.label}"
|
|
326
|
+
label-position="${args.labelPosition}"
|
|
327
|
+
label-width="${args.labelWidth}"
|
|
328
|
+
placeholder="${args.placeholder}"
|
|
329
|
+
helper="${args.helper}"
|
|
330
|
+
maxlength="${args.maxlength}"
|
|
331
|
+
?show-counter="${args.showCounter}"
|
|
332
|
+
rows="${args.rows}"
|
|
333
|
+
></ds-textarea>
|
|
334
|
+
`
|
|
335
|
+
};
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import './ds-textarea.js';
|
|
3
|
+
|
|
4
|
+
describe('ds-textarea', () => {
|
|
5
|
+
let container;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
container = document.createElement('div');
|
|
9
|
+
document.body.appendChild(container);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
container.remove();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders with default values', async () => {
|
|
17
|
+
container.innerHTML = '<ds-textarea></ds-textarea>';
|
|
18
|
+
const element = container.querySelector('ds-textarea');
|
|
19
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
20
|
+
|
|
21
|
+
expect(element.label).toBe('');
|
|
22
|
+
expect(element.value).toBe('');
|
|
23
|
+
expect(element.rows).toBe(3);
|
|
24
|
+
expect(element.resize).toBe('vertical');
|
|
25
|
+
expect(element.autoResize).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('renders label when provided', async () => {
|
|
29
|
+
container.innerHTML = '<ds-textarea label="Description"></ds-textarea>';
|
|
30
|
+
const element = container.querySelector('ds-textarea');
|
|
31
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
32
|
+
|
|
33
|
+
const label = element.shadowRoot.querySelector('label');
|
|
34
|
+
expect(label.textContent).toBe('Description');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('renders textarea with correct rows', async () => {
|
|
38
|
+
container.innerHTML = '<ds-textarea rows="5"></ds-textarea>';
|
|
39
|
+
const element = container.querySelector('ds-textarea');
|
|
40
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
41
|
+
|
|
42
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
43
|
+
expect(textarea.getAttribute('rows')).toBe('5');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('binds value to textarea', async () => {
|
|
47
|
+
container.innerHTML = '<ds-textarea value="Test content"></ds-textarea>';
|
|
48
|
+
const element = container.querySelector('ds-textarea');
|
|
49
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
50
|
+
|
|
51
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
52
|
+
expect(textarea.value).toBe('Test content');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('updates value on input', async () => {
|
|
56
|
+
container.innerHTML = '<ds-textarea></ds-textarea>';
|
|
57
|
+
const element = container.querySelector('ds-textarea');
|
|
58
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
59
|
+
|
|
60
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
61
|
+
textarea.value = 'New content';
|
|
62
|
+
textarea.dispatchEvent(new Event('input'));
|
|
63
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
64
|
+
|
|
65
|
+
expect(element.value).toBe('New content');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('dispatches input event when typing', async () => {
|
|
69
|
+
container.innerHTML = '<ds-textarea></ds-textarea>';
|
|
70
|
+
const element = container.querySelector('ds-textarea');
|
|
71
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
72
|
+
|
|
73
|
+
const inputSpy = vi.fn();
|
|
74
|
+
element.addEventListener('input', inputSpy);
|
|
75
|
+
|
|
76
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
77
|
+
textarea.value = 'Test';
|
|
78
|
+
textarea.dispatchEvent(new Event('input'));
|
|
79
|
+
|
|
80
|
+
expect(inputSpy).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(inputSpy.mock.calls[0][0].detail.value).toBe('Test');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('dispatches change event on blur', async () => {
|
|
85
|
+
container.innerHTML = '<ds-textarea value="Test"></ds-textarea>';
|
|
86
|
+
const element = container.querySelector('ds-textarea');
|
|
87
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
88
|
+
|
|
89
|
+
const changeSpy = vi.fn();
|
|
90
|
+
element.addEventListener('change', changeSpy);
|
|
91
|
+
|
|
92
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
93
|
+
textarea.dispatchEvent(new Event('change'));
|
|
94
|
+
|
|
95
|
+
expect(changeSpy).toHaveBeenCalledTimes(1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('shows counter when maxlength and show-counter are set', async () => {
|
|
99
|
+
container.innerHTML = '<ds-textarea maxlength="100" show-counter value="Hello"></ds-textarea>';
|
|
100
|
+
const element = container.querySelector('ds-textarea');
|
|
101
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
102
|
+
|
|
103
|
+
const counter = element.shadowRoot.querySelector('.counter');
|
|
104
|
+
expect(counter).toBeTruthy();
|
|
105
|
+
expect(counter.textContent).toBe('5/100');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('updates counter on input', async () => {
|
|
109
|
+
container.innerHTML = '<ds-textarea maxlength="50" show-counter></ds-textarea>';
|
|
110
|
+
const element = container.querySelector('ds-textarea');
|
|
111
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
112
|
+
|
|
113
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
114
|
+
textarea.value = 'Test content';
|
|
115
|
+
textarea.dispatchEvent(new Event('input'));
|
|
116
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
117
|
+
|
|
118
|
+
const counter = element.shadowRoot.querySelector('.counter');
|
|
119
|
+
expect(counter.textContent).toBe('12/50');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('marks counter as over-limit when exceeding maxlength', async () => {
|
|
123
|
+
container.innerHTML = '<ds-textarea maxlength="5" show-counter value="This is too long"></ds-textarea>';
|
|
124
|
+
const element = container.querySelector('ds-textarea');
|
|
125
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
126
|
+
|
|
127
|
+
const counter = element.shadowRoot.querySelector('.counter');
|
|
128
|
+
expect(counter.classList.contains('over-limit')).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('applies resize attribute correctly', async () => {
|
|
132
|
+
container.innerHTML = '<ds-textarea resize="none"></ds-textarea>';
|
|
133
|
+
const element = container.querySelector('ds-textarea');
|
|
134
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
135
|
+
|
|
136
|
+
expect(element.getAttribute('resize')).toBe('none');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('disables textarea when disabled', async () => {
|
|
140
|
+
container.innerHTML = '<ds-textarea disabled></ds-textarea>';
|
|
141
|
+
const element = container.querySelector('ds-textarea');
|
|
142
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
143
|
+
|
|
144
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
145
|
+
expect(textarea.disabled).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('makes textarea readonly when readonly', async () => {
|
|
149
|
+
container.innerHTML = '<ds-textarea readonly></ds-textarea>';
|
|
150
|
+
const element = container.querySelector('ds-textarea');
|
|
151
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
152
|
+
|
|
153
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
154
|
+
expect(textarea.readOnly).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('sets required attribute', async () => {
|
|
158
|
+
container.innerHTML = '<ds-textarea required></ds-textarea>';
|
|
159
|
+
const element = container.querySelector('ds-textarea');
|
|
160
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
161
|
+
|
|
162
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
163
|
+
expect(textarea.required).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('applies minlength and maxlength', async () => {
|
|
167
|
+
container.innerHTML = '<ds-textarea minlength="10" maxlength="100"></ds-textarea>';
|
|
168
|
+
const element = container.querySelector('ds-textarea');
|
|
169
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
170
|
+
|
|
171
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
172
|
+
expect(textarea.getAttribute('minlength')).toBe('10');
|
|
173
|
+
expect(textarea.getAttribute('maxlength')).toBe('100');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('renders helper text', async () => {
|
|
177
|
+
container.innerHTML = '<ds-textarea helper="Enter your description"></ds-textarea>';
|
|
178
|
+
const element = container.querySelector('ds-textarea');
|
|
179
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
180
|
+
|
|
181
|
+
const message = element.shadowRoot.querySelector('.field-message__text');
|
|
182
|
+
expect(message.textContent).toBe('Enter your description');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('renders error message', async () => {
|
|
186
|
+
container.innerHTML = `
|
|
187
|
+
<ds-textarea
|
|
188
|
+
validation-status="error"
|
|
189
|
+
validation-message="This field is required"
|
|
190
|
+
></ds-textarea>
|
|
191
|
+
`;
|
|
192
|
+
const element = container.querySelector('ds-textarea');
|
|
193
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
194
|
+
|
|
195
|
+
const errorMessage = element.shadowRoot.querySelector('.field-message--error');
|
|
196
|
+
expect(errorMessage).toBeTruthy();
|
|
197
|
+
const icon = element.shadowRoot.querySelector('.field-message__icon');
|
|
198
|
+
expect(icon).toBeTruthy();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('sets aria-invalid when validation status is error', async () => {
|
|
202
|
+
container.innerHTML = '<ds-textarea validation-status="error"></ds-textarea>';
|
|
203
|
+
const element = container.querySelector('ds-textarea');
|
|
204
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
205
|
+
|
|
206
|
+
const textarea = element.shadowRoot.querySelector('textarea');
|
|
207
|
+
expect(textarea.getAttribute('aria-invalid')).toBe('true');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('does not show counter without maxlength', async () => {
|
|
211
|
+
container.innerHTML = '<ds-textarea show-counter></ds-textarea>';
|
|
212
|
+
const element = container.querySelector('ds-textarea');
|
|
213
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
214
|
+
|
|
215
|
+
const counter = element.shadowRoot.querySelector('.counter');
|
|
216
|
+
expect(counter).toBeFalsy();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DsTextarea } from './ds-textarea.js';
|