@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.
Files changed (230) hide show
  1. package/package.json +27 -0
  2. package/src/ds-accordion/ds-accordion-item.js +288 -0
  3. package/src/ds-accordion/ds-accordion-item.stories.js +82 -0
  4. package/src/ds-accordion/ds-accordion.a11y.test.js +92 -0
  5. package/src/ds-accordion/ds-accordion.js +68 -0
  6. package/src/ds-accordion/ds-accordion.stories.js +118 -0
  7. package/src/ds-accordion/ds-accordion.test.js +146 -0
  8. package/src/ds-accordion/index.js +2 -0
  9. package/src/ds-action-bar/ds-action-bar.js +116 -0
  10. package/src/ds-action-bar/ds-action-bar.stories.js +86 -0
  11. package/src/ds-action-bar/ds-action-bar.test.js +64 -0
  12. package/src/ds-action-bar/index.js +1 -0
  13. package/src/ds-alert/ds-alert.a11y.test.js +151 -0
  14. package/src/ds-alert/ds-alert.js +223 -0
  15. package/src/ds-alert/ds-alert.mdx +142 -0
  16. package/src/ds-alert/ds-alert.stories.js +166 -0
  17. package/src/ds-alert/ds-alert.test.js +256 -0
  18. package/src/ds-alert/index.js +1 -0
  19. package/src/ds-avatar/ds-avatar.a11y.test.js +45 -0
  20. package/src/ds-avatar/ds-avatar.js +216 -0
  21. package/src/ds-avatar/ds-avatar.stories.js +120 -0
  22. package/src/ds-avatar/ds-avatar.test.js +83 -0
  23. package/src/ds-avatar/index.js +1 -0
  24. package/src/ds-avatar-extended/ds-avatar-extended.a11y.test.js +29 -0
  25. package/src/ds-avatar-extended/ds-avatar-extended.js +108 -0
  26. package/src/ds-avatar-extended/ds-avatar-extended.stories.js +93 -0
  27. package/src/ds-avatar-extended/ds-avatar-extended.test.js +66 -0
  28. package/src/ds-avatar-extended/index.js +1 -0
  29. package/src/ds-banner/ds-banner.a11y.test.js +51 -0
  30. package/src/ds-banner/ds-banner.js +233 -0
  31. package/src/ds-banner/ds-banner.stories.js +185 -0
  32. package/src/ds-banner/ds-banner.test.js +116 -0
  33. package/src/ds-banner/index.js +1 -0
  34. package/src/ds-breadcrumb-item/ds-breadcrumb-item.js +135 -0
  35. package/src/ds-breadcrumb-item/ds-breadcrumb-item.stories.js +49 -0
  36. package/src/ds-breadcrumb-item/ds-breadcrumb-item.test.js +55 -0
  37. package/src/ds-breadcrumbs/ds-breadcrumbs.js +194 -0
  38. package/src/ds-breadcrumbs/ds-breadcrumbs.stories.js +54 -0
  39. package/src/ds-breadcrumbs/ds-breadcrumbs.test.js +33 -0
  40. package/src/ds-button/ds-button.a11y.test.js +49 -0
  41. package/src/ds-button/ds-button.js +205 -0
  42. package/src/ds-button/ds-button.mdx +141 -0
  43. package/src/ds-button/ds-button.stories.js +152 -0
  44. package/src/ds-button/ds-button.test.js +62 -0
  45. package/src/ds-button/index.js +1 -0
  46. package/src/ds-button-group/ds-button-group.js +82 -0
  47. package/src/ds-button-group/ds-button-group.mdx +39 -0
  48. package/src/ds-button-group/ds-button-group.stories.js +47 -0
  49. package/src/ds-button-group/ds-button-group.test.js +47 -0
  50. package/src/ds-button-group/index.js +1 -0
  51. package/src/ds-checkbox/ds-checkbox.a11y.test.js +79 -0
  52. package/src/ds-checkbox/ds-checkbox.js +271 -0
  53. package/src/ds-checkbox/ds-checkbox.stories.js +77 -0
  54. package/src/ds-checkbox/ds-checkbox.test.js +191 -0
  55. package/src/ds-checkbox/index.js +1 -0
  56. package/src/ds-checkbox-group/ds-checkbox-group.a11y.test.js +146 -0
  57. package/src/ds-checkbox-group/ds-checkbox-group.js +235 -0
  58. package/src/ds-checkbox-group/ds-checkbox-group.stories.js +210 -0
  59. package/src/ds-checkbox-group/ds-checkbox-group.test.js +150 -0
  60. package/src/ds-checkbox-group/index.js +1 -0
  61. package/src/ds-dialog/ds-dialog.js +466 -0
  62. package/src/ds-dialog/ds-dialog.stories.js +274 -0
  63. package/src/ds-dialog/ds-dialog.test.js +441 -0
  64. package/src/ds-dialog/index.js +1 -0
  65. package/src/ds-dropdown/ds-dropdown.a11y.test.js +80 -0
  66. package/src/ds-dropdown/ds-dropdown.js +891 -0
  67. package/src/ds-dropdown/ds-dropdown.stories.js +259 -0
  68. package/src/ds-dropdown/ds-dropdown.test.js +268 -0
  69. package/src/ds-dropdown/index.js +1 -0
  70. package/src/ds-dropdown-group/ds-dropdown-group.js +55 -0
  71. package/src/ds-dropdown-panel/ds-dropdown-panel.js +34 -0
  72. package/src/ds-file-uploaded/ds-file-uploaded.a11y.test.js +40 -0
  73. package/src/ds-file-uploaded/ds-file-uploaded.js +135 -0
  74. package/src/ds-file-uploaded/ds-file-uploaded.mdx +33 -0
  75. package/src/ds-file-uploaded/ds-file-uploaded.stories.js +81 -0
  76. package/src/ds-file-uploaded/ds-file-uploaded.test.js +85 -0
  77. package/src/ds-file-uploader/ds-file-uploader.a11y.test.js +61 -0
  78. package/src/ds-file-uploader/ds-file-uploader.js +442 -0
  79. package/src/ds-file-uploader/ds-file-uploader.mdx +44 -0
  80. package/src/ds-file-uploader/ds-file-uploader.stories.js +76 -0
  81. package/src/ds-file-uploader/ds-file-uploader.test.js +142 -0
  82. package/src/ds-header/ds-header.a11y.test.js +38 -0
  83. package/src/ds-header/ds-header.js +149 -0
  84. package/src/ds-header/ds-header.stories.js +63 -0
  85. package/src/ds-header/ds-header.test.js +52 -0
  86. package/src/ds-header/index.js +1 -0
  87. package/src/ds-header-nav/ds-header-nav.a11y.test.js +69 -0
  88. package/src/ds-header-nav/ds-header-nav.js +114 -0
  89. package/src/ds-header-nav/ds-header-nav.stories.js +17 -0
  90. package/src/ds-header-nav/ds-header-nav.test.js +93 -0
  91. package/src/ds-header-nav-item/ds-header-nav-item.a11y.test.js +71 -0
  92. package/src/ds-header-nav-item/ds-header-nav-item.js +124 -0
  93. package/src/ds-header-nav-item/ds-header-nav-item.stories.js +43 -0
  94. package/src/ds-header-nav-item/ds-header-nav-item.test.js +61 -0
  95. package/src/ds-icon/ds-icon.a11y.test.js +49 -0
  96. package/src/ds-icon/ds-icon.js +75 -0
  97. package/src/ds-icon/ds-icon.mdx +36 -0
  98. package/src/ds-icon/ds-icon.stories.js +88 -0
  99. package/src/ds-icon/ds-icon.test.js +97 -0
  100. package/src/ds-icon/index.js +1 -0
  101. package/src/ds-icon-button/ds-icon-button.a11y.test.js +55 -0
  102. package/src/ds-icon-button/ds-icon-button.js +224 -0
  103. package/src/ds-icon-button/ds-icon-button.mdx +131 -0
  104. package/src/ds-icon-button/ds-icon-button.stories.js +128 -0
  105. package/src/ds-icon-button/ds-icon-button.test.js +90 -0
  106. package/src/ds-icon-button/index.js +1 -0
  107. package/src/ds-input/ds-input.a11y.test.js +145 -0
  108. package/src/ds-input/ds-input.js +645 -0
  109. package/src/ds-input/ds-input.mdx +251 -0
  110. package/src/ds-input/ds-input.stories.js +298 -0
  111. package/src/ds-input/ds-input.test.js +792 -0
  112. package/src/ds-input/index.js +1 -0
  113. package/src/ds-link/ds-link.js +111 -0
  114. package/src/ds-link/ds-link.stories.js +56 -0
  115. package/src/ds-link/ds-link.test.js +74 -0
  116. package/src/ds-list-item/ds-list-item.a11y.test.js +39 -0
  117. package/src/ds-list-item/ds-list-item.js +292 -0
  118. package/src/ds-list-item/ds-list-item.stories.js +101 -0
  119. package/src/ds-list-item/ds-list-item.test.js +63 -0
  120. package/src/ds-menu/ds-menu.js +30 -0
  121. package/src/ds-menu/ds-menu.stories.js +120 -0
  122. package/src/ds-menu/ds-menu.test.js +123 -0
  123. package/src/ds-menu-group/ds-menu-group.js +101 -0
  124. package/src/ds-menu-group/ds-menu-group.stories.js +99 -0
  125. package/src/ds-nav-item/ds-nav-item.a11y.test.js +91 -0
  126. package/src/ds-nav-item/ds-nav-item.js +307 -0
  127. package/src/ds-nav-item/ds-nav-item.stories.js +99 -0
  128. package/src/ds-nav-item/ds-nav-item.test.js +169 -0
  129. package/src/ds-nav-item/index.js +1 -0
  130. package/src/ds-nav-vertical/ds-nav-vertical.a11y.test.js +69 -0
  131. package/src/ds-nav-vertical/ds-nav-vertical.js +173 -0
  132. package/src/ds-nav-vertical/ds-nav-vertical.stories.js +124 -0
  133. package/src/ds-nav-vertical/ds-nav-vertical.test.js +176 -0
  134. package/src/ds-nav-vertical/index.js +1 -0
  135. package/src/ds-pagination/ds-pagination.a11y.test.js +50 -0
  136. package/src/ds-pagination/ds-pagination.js +232 -0
  137. package/src/ds-pagination/ds-pagination.stories.js +63 -0
  138. package/src/ds-pagination/ds-pagination.test.js +141 -0
  139. package/src/ds-pagination/index.js +1 -0
  140. package/src/ds-progress-bar/ds-progress-bar.a11y.test.js +25 -0
  141. package/src/ds-progress-bar/ds-progress-bar.js +81 -0
  142. package/src/ds-progress-bar/ds-progress-bar.stories.js +69 -0
  143. package/src/ds-progress-bar/ds-progress-bar.test.js +60 -0
  144. package/src/ds-radio/ds-radio.a11y.test.js +69 -0
  145. package/src/ds-radio/ds-radio.js +240 -0
  146. package/src/ds-radio/ds-radio.stories.js +102 -0
  147. package/src/ds-radio/ds-radio.test.js +114 -0
  148. package/src/ds-radio/index.js +1 -0
  149. package/src/ds-radio-group/ds-radio-group.a11y.test.js +164 -0
  150. package/src/ds-radio-group/ds-radio-group.js +257 -0
  151. package/src/ds-radio-group/ds-radio-group.stories.js +247 -0
  152. package/src/ds-radio-group/ds-radio-group.test.js +194 -0
  153. package/src/ds-radio-group/index.js +1 -0
  154. package/src/ds-rich-list/ds-rich-list.js +246 -0
  155. package/src/ds-rich-list/ds-rich-list.stories.js +368 -0
  156. package/src/ds-rich-list/ds-rich-list.test.js +293 -0
  157. package/src/ds-rich-list-item/ds-rich-list-item.js +579 -0
  158. package/src/ds-rich-list-item/ds-rich-list-item.stories.js +197 -0
  159. package/src/ds-rich-list-item/ds-rich-list-item.test.js +434 -0
  160. package/src/ds-slider/ds-slider.js +399 -0
  161. package/src/ds-slider/ds-slider.stories.js +107 -0
  162. package/src/ds-slider/ds-slider.test.js +308 -0
  163. package/src/ds-spinner/ds-spinner.js +173 -0
  164. package/src/ds-spinner/ds-spinner.stories.js +52 -0
  165. package/src/ds-spinner/ds-spinner.test.js +50 -0
  166. package/src/ds-status-border/ds-status-border.js +88 -0
  167. package/src/ds-status-border/ds-status-border.stories.js +242 -0
  168. package/src/ds-status-border/ds-status-border.test.js +168 -0
  169. package/src/ds-stepper/ds-stepper.a11y.test.js +198 -0
  170. package/src/ds-stepper/ds-stepper.js +207 -0
  171. package/src/ds-stepper/ds-stepper.stories.js +530 -0
  172. package/src/ds-stepper/ds-stepper.test.js +311 -0
  173. package/src/ds-stepper-item/ds-stepper-item.js +485 -0
  174. package/src/ds-stepper-item/ds-stepper-item.stories.js +288 -0
  175. package/src/ds-switch/ds-switch.js +348 -0
  176. package/src/ds-switch/ds-switch.stories.js +145 -0
  177. package/src/ds-switch/ds-switch.test.js +226 -0
  178. package/src/ds-switch/index.js +1 -0
  179. package/src/ds-tab-item/ds-tab-item.js +341 -0
  180. package/src/ds-tab-item/ds-tab-item.stories.js +69 -0
  181. package/src/ds-tabs/ds-tab-panel.js +48 -0
  182. package/src/ds-tabs/ds-tabs.a11y.test.js +56 -0
  183. package/src/ds-tabs/ds-tabs.js +180 -0
  184. package/src/ds-tabs/ds-tabs.stories.js +152 -0
  185. package/src/ds-tabs/ds-tabs.test.js +306 -0
  186. package/src/ds-tabs/index.js +3 -0
  187. package/src/ds-tag-action/ds-tag-action.a11y.test.js +32 -0
  188. package/src/ds-tag-action/ds-tag-action.js +185 -0
  189. package/src/ds-tag-action/ds-tag-action.stories.js +55 -0
  190. package/src/ds-tag-action/ds-tag-action.test.js +44 -0
  191. package/src/ds-tag-removable/ds-tag-removable.a11y.test.js +24 -0
  192. package/src/ds-tag-removable/ds-tag-removable.js +146 -0
  193. package/src/ds-tag-removable/ds-tag-removable.stories.js +52 -0
  194. package/src/ds-tag-removable/ds-tag-removable.test.js +46 -0
  195. package/src/ds-tag-status/ds-tag-status.a11y.test.js +93 -0
  196. package/src/ds-tag-status/ds-tag-status.js +164 -0
  197. package/src/ds-tag-status/ds-tag-status.stories.js +200 -0
  198. package/src/ds-tag-status/ds-tag-status.test.js +140 -0
  199. package/src/ds-tag-status/index.js +1 -0
  200. package/src/ds-textarea/ds-textarea-clearable.test.js +89 -0
  201. package/src/ds-textarea/ds-textarea.a11y.test.js +66 -0
  202. package/src/ds-textarea/ds-textarea.js +505 -0
  203. package/src/ds-textarea/ds-textarea.stories.js +335 -0
  204. package/src/ds-textarea/ds-textarea.test.js +218 -0
  205. package/src/ds-textarea/index.js +1 -0
  206. package/src/ds-thumbnail/ds-thumbnail.js +207 -0
  207. package/src/ds-thumbnail/ds-thumbnail.stories.js +217 -0
  208. package/src/ds-thumbnail/ds-thumbnail.test.js +220 -0
  209. package/src/ds-toast/ds-toast-provider.js +110 -0
  210. package/src/ds-toast/ds-toast.a11y.test.js +34 -0
  211. package/src/ds-toast/ds-toast.js +243 -0
  212. package/src/ds-toast/ds-toast.stories.js +143 -0
  213. package/src/ds-toast/ds-toast.test.js +93 -0
  214. package/src/ds-toast/index.js +2 -0
  215. package/src/ds-tooltip/ds-tooltip.a11y.test.js +110 -0
  216. package/src/ds-tooltip/ds-tooltip.js +217 -0
  217. package/src/ds-tooltip/ds-tooltip.mdx +75 -0
  218. package/src/ds-tooltip/ds-tooltip.stories.js +72 -0
  219. package/src/ds-tooltip/ds-tooltip.test.js +191 -0
  220. package/src/ds-tooltip/index.js +1 -0
  221. package/src/ds-tooltip/positioner.js +117 -0
  222. package/src/index.js +50 -0
  223. package/src/mixins/field-label.mixin.js +113 -0
  224. package/src/mixins/field-message.mixin.js +66 -0
  225. package/src/token-provider/index.js +1 -0
  226. package/src/token-provider/token-provider.a11y.test.js +44 -0
  227. package/src/token-provider/token-provider.js +85 -0
  228. package/src/token-provider/token-provider.stories.js +105 -0
  229. package/src/token-provider/token-provider.test.js +134 -0
  230. package/src/utils/number-input.utils.js +42 -0
@@ -0,0 +1,135 @@
1
+ import { LitElement, html, css, nothing } from 'lit';
2
+ import '../ds-rich-list-item/ds-rich-list-item.js';
3
+ import '../ds-icon/ds-icon.js';
4
+ import '../ds-icon-button/ds-icon-button.js';
5
+ import '../ds-progress-bar/ds-progress-bar.js';
6
+ import '../ds-thumbnail/ds-thumbnail.js';
7
+
8
+ /**
9
+ * File Uploaded — represents an individual file upload item.
10
+ *
11
+ * @element ds-file-uploaded
12
+ *
13
+ * @prop {string} filename - The name of the file.
14
+ * @prop {string} size - The size of the file (e.g., '1.2 MB').
15
+ * @prop {number} progress - The upload progress (0 to 100).
16
+ * @prop {boolean} loading - Whether the file is currently uploading.
17
+ * @prop {boolean} error - Whether the upload failed.
18
+ * @prop {string} errorMessage - The error message to display if error is true.
19
+ * @prop {boolean} disabled - Whether the component is disabled.
20
+ *
21
+ * @slot media - The file type icon. Defaults to a document icon.
22
+ *
23
+ * @fires ds-remove-file - Fired when the close (x) button is clicked.
24
+ */
25
+ export class DsFileUploaded extends LitElement {
26
+ static properties = {
27
+ filename: { type: String, reflect: true },
28
+ size: { type: String, reflect: true },
29
+ progress: { type: Number, reflect: true },
30
+ loading: { type: Boolean, reflect: true },
31
+ error: { type: Boolean, reflect: true },
32
+ errorMessage: { type: String, attribute: 'error-message' },
33
+ disabled: { type: Boolean, reflect: true },
34
+ previewUrl: { type: String, attribute: 'preview-url' },
35
+ icon: { type: String }
36
+ };
37
+
38
+ static styles = css`
39
+ :host {
40
+ display: block;
41
+ width: 100%;
42
+ }
43
+
44
+ .error-text {
45
+ font: var(--ds-typo-content-body-regular);
46
+ color: var(--ds-color-text-error);
47
+ display: flex;
48
+ align-items: center;
49
+ gap: var(--ds-space-xs);
50
+ white-space: nowrap;
51
+ overflow: hidden;
52
+ text-overflow: ellipsis;
53
+ }
54
+
55
+ .error-icon {
56
+ color: var(--ds-color-icon-error);
57
+ flex-shrink: 0;
58
+ }
59
+
60
+ .progress-container {
61
+ display: flex;
62
+ align-items: center;
63
+ width: 100%;
64
+ min-width: 100px;
65
+ }
66
+
67
+ ds-rich-list-item {
68
+ width: 100%;
69
+ }
70
+ `;
71
+
72
+ constructor() {
73
+ super();
74
+ this.filename = '';
75
+ this.size = '';
76
+ this.progress = 0;
77
+ this.loading = false;
78
+ this.error = false;
79
+ this.errorMessage = '';
80
+ this.disabled = false;
81
+ this.previewUrl = '';
82
+ this.icon = 'document';
83
+ }
84
+
85
+ _handleRemoveClick(e) {
86
+ e.stopPropagation();
87
+ if (this.disabled) return;
88
+ this.dispatchEvent(new CustomEvent('ds-remove-file', {
89
+ bubbles: true,
90
+ composed: true,
91
+ detail: { filename: this.filename }
92
+ }));
93
+ }
94
+
95
+ render() {
96
+ return html`
97
+ <ds-rich-list-item ?disabled=${this.disabled}>
98
+ <slot name="media" slot="media">
99
+ <ds-thumbnail src="${this.previewUrl || ''}" icon="${this.icon}"></ds-thumbnail>
100
+ </slot>
101
+
102
+ <span slot="title">${this.filename}</span>
103
+ <span slot="description">${this.size}</span>
104
+
105
+ <div slot="custom" class="custom-area">
106
+ ${this.loading ? html`
107
+ <div class="progress-container">
108
+ <ds-progress-bar value="${this.progress}" ?disabled=${this.disabled} label="Upload progress"></ds-progress-bar>
109
+ </div>
110
+ ` : nothing}
111
+ ${this.error && !this.loading ? html`
112
+ <div class="error-text">
113
+ <ds-icon name="warning" size="sm" class="error-icon"></ds-icon>
114
+ <span>${this.errorMessage}</span>
115
+ </div>
116
+ ` : nothing}
117
+ </div>
118
+
119
+ <ds-icon-button
120
+ slot="action-group"
121
+ icon="close"
122
+ variant="action"
123
+ size="m"
124
+ aria-label="Remove file"
125
+ ?disabled=${this.disabled}
126
+ @click=${this._handleRemoveClick}
127
+ ></ds-icon-button>
128
+ </ds-rich-list-item>
129
+ `;
130
+ }
131
+ }
132
+
133
+ if (!customElements.get('ds-file-uploaded')) {
134
+ customElements.define('ds-file-uploaded', DsFileUploaded);
135
+ }
@@ -0,0 +1,33 @@
1
+ import { Meta, Story, Canvas, ArgsTable, Description } from '@storybook/blocks';
2
+ import * as DsFileUploadedStories from './ds-file-uploaded.stories';
3
+
4
+ <Meta of={DsFileUploadedStories} />
5
+
6
+ # DsFileUploaded
7
+
8
+ <Description />
9
+
10
+ The `ds-file-uploaded` component represents a single file either currently being uploaded or already uploaded.
11
+
12
+ ## Anatomy
13
+ It leverages the `ds-rich-list-item` and supports custom `media` slots, a close button, and states for loading (with progress) and error.
14
+
15
+ ## Examples
16
+
17
+ ### Default
18
+ <Canvas>
19
+ <Story of={DsFileUploadedStories.Default} />
20
+ </Canvas>
21
+
22
+ ### Loading
23
+ <Canvas>
24
+ <Story of={DsFileUploadedStories.Loading} />
25
+ </Canvas>
26
+
27
+ ### Error
28
+ <Canvas>
29
+ <Story of={DsFileUploadedStories.Error} />
30
+ </Canvas>
31
+
32
+ ## API Reference
33
+ <ArgsTable />
@@ -0,0 +1,81 @@
1
+ import './ds-file-uploaded.js';
2
+ import { html } from 'lit';
3
+
4
+ export default {
5
+ title: 'Components/File Uploaded',
6
+ component: 'ds-file-uploaded',
7
+ tags: ['autodocs'],
8
+ argTypes: {
9
+ filename: { control: 'text' },
10
+ size: { control: 'text' },
11
+ progress: { control: { type: 'range', min: 0, max: 100 } },
12
+ loading: { control: 'boolean' },
13
+ error: { control: 'boolean' },
14
+ errorMessage: { control: 'text', name: 'error-message' },
15
+ disabled: { control: 'boolean' },
16
+ previewUrl: { control: 'text', name: 'preview-url' },
17
+ icon: { control: 'text' }
18
+ },
19
+ parameters: {
20
+ actions: {
21
+ handles: ['ds-remove-file']
22
+ }
23
+ }
24
+ };
25
+
26
+ const Template = (args) => html`
27
+ <ds-file-uploaded
28
+ filename=${args.filename}
29
+ size=${args.size}
30
+ progress=${args.progress}
31
+ ?loading=${args.loading}
32
+ ?error=${args.error}
33
+ error-message=${args.errorMessage || ''}
34
+ ?disabled=${args.disabled}
35
+ preview-url=${args.previewUrl || ''}
36
+ icon=${args.icon || 'document'}
37
+ ></ds-file-uploaded>
38
+ `;
39
+
40
+ export const Default = Template.bind({});
41
+ Default.args = {
42
+ filename: 'document.pdf',
43
+ size: '1.2 MB',
44
+ progress: 0,
45
+ loading: false,
46
+ error: false,
47
+ errorMessage: '',
48
+ disabled: false,
49
+ icon: 'image'
50
+ };
51
+
52
+ export const Loading = Template.bind({});
53
+ Loading.args = {
54
+ ...Default.args,
55
+ progress: 45,
56
+ loading: true
57
+ };
58
+
59
+ export const Error = Template.bind({});
60
+ Error.args = {
61
+ ...Default.args,
62
+ filename: 'corrupted-file.zip',
63
+ size: '12 KB',
64
+ error: true,
65
+ errorMessage: 'File must be a valid format'
66
+ };
67
+
68
+ export const Disabled = Template.bind({});
69
+ Disabled.args = {
70
+ ...Default.args,
71
+ disabled: true
72
+ };
73
+
74
+ export const CustomMedia = (args) => html`
75
+ <ds-file-uploaded
76
+ filename="image-placeholder.png"
77
+ size="350 KB"
78
+ >
79
+ <ds-thumbnail slot="media" src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=400&h=400&fit=crop" icon="image"></ds-thumbnail>
80
+ </ds-file-uploaded>
81
+ `;
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import './ds-file-uploaded.js';
3
+
4
+ describe('DsFileUploaded', () => {
5
+ let container;
6
+
7
+ beforeEach(() => {
8
+ container = document.createElement('div');
9
+ document.body.appendChild(container);
10
+ });
11
+
12
+ afterEach(() => {
13
+ container.remove();
14
+ vi.restoreAllMocks();
15
+ });
16
+
17
+ it('should render correctly', async () => {
18
+ container.innerHTML = '<ds-file-uploaded filename="test.pdf" size="1.2 MB"></ds-file-uploaded>';
19
+ const el = container.querySelector('ds-file-uploaded');
20
+ await new Promise(resolve => setTimeout(resolve, 0));
21
+ expect(el).toBeTruthy();
22
+ expect(el.shadowRoot.querySelector('ds-rich-list-item')).toBeTruthy();
23
+ });
24
+
25
+ it('displays the filename and size', async () => {
26
+ container.innerHTML = '<ds-file-uploaded filename="document.pdf" size="2 MB"></ds-file-uploaded>';
27
+ const el = container.querySelector('ds-file-uploaded');
28
+ await new Promise(resolve => setTimeout(resolve, 0));
29
+
30
+ const title = el.shadowRoot.querySelector('span[slot="title"]');
31
+ const desc = el.shadowRoot.querySelector('span[slot="description"]');
32
+ expect(title.textContent).toBe('document.pdf');
33
+ expect(desc.textContent).toBe('2 MB');
34
+ });
35
+
36
+ it('shows progress bar when loading', async () => {
37
+ container.innerHTML = '<ds-file-uploaded filename="doc.pdf" loading progress="50"></ds-file-uploaded>';
38
+ const el = container.querySelector('ds-file-uploaded');
39
+ await new Promise(resolve => setTimeout(resolve, 0));
40
+
41
+ const progressBar = el.shadowRoot.querySelector('ds-progress-bar');
42
+ expect(progressBar).toBeTruthy();
43
+ expect(progressBar.getAttribute('value')).toBe('50');
44
+ });
45
+
46
+ it('shows error message when error is true', async () => {
47
+ container.innerHTML = '<ds-file-uploaded filename="doc.pdf" error error-message="File too large"></ds-file-uploaded>';
48
+ const el = container.querySelector('ds-file-uploaded');
49
+ await new Promise(resolve => setTimeout(resolve, 0));
50
+
51
+ const errorText = el.shadowRoot.querySelector('.error-text span');
52
+ expect(errorText).toBeTruthy();
53
+ expect(errorText.textContent).toBe('File too large');
54
+ });
55
+
56
+ it('dispatches ds-remove-file event when close button is clicked', async () => {
57
+ container.innerHTML = '<ds-file-uploaded filename="doc.pdf"></ds-file-uploaded>';
58
+ const el = container.querySelector('ds-file-uploaded');
59
+ await new Promise(resolve => setTimeout(resolve, 0));
60
+
61
+ const removeSpy = vi.fn();
62
+ el.addEventListener('ds-remove-file', removeSpy);
63
+
64
+ const closeButton = el.shadowRoot.querySelector('ds-icon-button');
65
+ closeButton.click();
66
+
67
+ expect(removeSpy).toHaveBeenCalledOnce();
68
+ const eventDetail = removeSpy.mock.calls[0][0].detail;
69
+ expect(eventDetail.filename).toBe('doc.pdf');
70
+ });
71
+
72
+ it('does not dispatch ds-remove-file when disabled', async () => {
73
+ container.innerHTML = '<ds-file-uploaded filename="doc.pdf" disabled></ds-file-uploaded>';
74
+ const el = container.querySelector('ds-file-uploaded');
75
+ await new Promise(resolve => setTimeout(resolve, 0));
76
+
77
+ const removeSpy = vi.fn();
78
+ el.addEventListener('ds-remove-file', removeSpy);
79
+
80
+ const closeButton = el.shadowRoot.querySelector('ds-icon-button');
81
+ closeButton.click();
82
+
83
+ expect(removeSpy).not.toHaveBeenCalled();
84
+ });
85
+ });
@@ -0,0 +1,61 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import axe from 'axe-core';
3
+ import './ds-file-uploader.js';
4
+
5
+ describe('DsFileUploader A11y', () => {
6
+ let container;
7
+
8
+ beforeEach(() => {
9
+ container = document.createElement('div');
10
+ document.body.appendChild(container);
11
+ });
12
+
13
+ afterEach(() => {
14
+ container.remove();
15
+ });
16
+
17
+ it('default state passes axe a11y checks', async () => {
18
+ container.innerHTML = '<ds-file-uploader label="Upload Area" help-text="Only PNGs"></ds-file-uploader>';
19
+ await new Promise(resolve => setTimeout(resolve, 0));
20
+
21
+ const results = await axe.run(container);
22
+ expect(results.violations).toHaveLength(0);
23
+ });
24
+
25
+ it('disabled state passes axe a11y checks', async () => {
26
+ container.innerHTML = '<ds-file-uploader disabled label="Upload Area"></ds-file-uploader>';
27
+ await new Promise(resolve => setTimeout(resolve, 0));
28
+
29
+ const results = await axe.run(container);
30
+ expect(results.violations).toHaveLength(0);
31
+ });
32
+
33
+ it('error state passes axe a11y checks', async () => {
34
+ container.innerHTML = '<ds-file-uploader error-text="Invalid file" label="Upload Area"></ds-file-uploader>';
35
+ await new Promise(resolve => setTimeout(resolve, 0));
36
+
37
+ const results = await axe.run(container);
38
+ expect(results.violations).toHaveLength(0);
39
+ });
40
+
41
+ it('populated list passes axe a11y checks', async () => {
42
+ container.innerHTML = '<ds-file-uploader label="Upload Area"></ds-file-uploader>';
43
+ const el = container.querySelector('ds-file-uploader');
44
+ await new Promise(resolve => setTimeout(resolve, 0));
45
+
46
+ // Manually add a file
47
+ el.files = [{
48
+ id: '123',
49
+ filename: 'a11y-test.pdf',
50
+ size: '12 KB',
51
+ progress: 0,
52
+ loading: false,
53
+ error: false,
54
+ errorMessage: ''
55
+ }];
56
+ await new Promise(resolve => setTimeout(resolve, 0));
57
+
58
+ const results = await axe.run(container);
59
+ expect(results.violations).toHaveLength(0);
60
+ });
61
+ });