@solid-design-system/mcp 7.0.3 → 7.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Changelog
2
2
 
3
+ ## 7.1.0
4
+
3
5
  ## 7.0.3
4
6
 
5
7
  ## 7.0.2
@@ -16,6 +16,7 @@ Use the components tool by passing the args `component` and `example` for any of
16
16
  - component: sd-datepicker, example: disabled
17
17
  - component: sd-datepicker, example: visually-disabled
18
18
  - component: sd-datepicker, example: help-text
19
+ - component: sd-datepicker, example: clearable
19
20
  - component: sd-datepicker, example: required
20
21
  - component: sd-datepicker, example: valid
21
22
  - component: sd-datepicker, example: invalid
@@ -56,6 +57,7 @@ Use the components tool by passing the args `component` and `example` for any of
56
57
  - prop.visuallyDisabled [attr: visually-disabled]: boolean, default=false — Makes the control non-interactive visually (like disabled) without disabling it functionally.
57
58
  - prop.styleOnValid [attr: style-on-valid]: boolean, default=false — When true, applies success styling for valid selections.
58
59
  - prop.readonly: boolean, default=false — Makes the input read-only (non-editable) when true.
60
+ - prop.clearable: boolean, default=false — Adds a clear button when the datepicker is not empty.
59
61
  - prop.placement: 'top'|'bottom', default='bottom' — Preferred placement of the flyout relative to the input (top|bottom).
60
62
  - prop.placeholder: string, default='' — Placeholder text for the input when no date is selected.
61
63
  - prop.name: string, default='' — The name of the datepicker, submitted as a name/value pair with form data.
@@ -79,6 +81,7 @@ Use the components tool by passing the args `component` and `example` for any of
79
81
  - event.sd-blur: Emitted when the datepicker is blurred.
80
82
  - event.sd-month-change: Emitted when the month is changed.
81
83
  - event.sd-month-year: Emitted when the year is changed.
84
+ - event.sd-clear: Emitted when the clear button is activated.
82
85
 
83
86
  ### Slots
84
87
 
@@ -86,6 +89,7 @@ Use the components tool by passing the args `component` and `example` for any of
86
89
  - slot.label: The label for the date input.
87
90
  - slot.help-text: The help text, displayed below the input.
88
91
  - slot.tooltip: The tooltip icon and content.
92
+ - slot.clear-icon: An icon to use in lieu of the default clear icon.
89
93
 
90
94
  ### CSS Parts
91
95
 
@@ -106,6 +110,7 @@ Use the components tool by passing the args `component` and `example` for any of
106
110
  - part.invalid-icon: The icon shown when the input is invalid.
107
111
  - part.valid-icon: The icon shown when the input is valid.
108
112
  - part.form-control-help-text: The help text, displayed below the input.
113
+ - part.clear-button: The clear button.
109
114
 
110
115
  ## Guidelines
111
116
 
@@ -0,0 +1,7 @@
1
+ Use the `clearable` attribute to add a clear button that removes the datepicker value.
2
+
3
+ ```html
4
+ <div class="max-w-[370px] h-[500px]">
5
+ <sd-datepicker label="Label" value="2026.01.01" clearable></sd-datepicker>
6
+ </div>
7
+ ```
@@ -29,16 +29,16 @@
29
29
  "displayNameDe": "Sonne",
30
30
  "tags": ["sonnig", "hell", "schönes Wetter"]
31
31
  },
32
- {
33
- "technicalId": "settings",
34
- "displayNameDe": "Einstellungen",
35
- "tags": ["anpassen", "Bearbeitung", "Zahnrad"]
36
- },
37
32
  {
38
33
  "technicalId": "volume",
39
34
  "displayNameDe": "Lautstärke",
40
35
  "tags": ["Ton", "Pegel", "Geräuschpegel"]
41
36
  },
37
+ {
38
+ "technicalId": "settings",
39
+ "displayNameDe": "Einstellungen",
40
+ "tags": ["anpassen", "Bearbeitung", "Zahnrad"]
41
+ },
42
42
  {
43
43
  "technicalId": "hand",
44
44
  "displayNameDe": "Hand",
@@ -844,16 +844,16 @@
844
844
  "displayNameDe": "Lesezeichen",
845
845
  "tags": ["merken", "Markierung", "markiert", "Favoriten"]
846
846
  },
847
- {
848
- "technicalId": "flash",
849
- "displayNameDe": "Blitz",
850
- "tags": ["Pfeil", "Fehler", "falsch"]
851
- },
852
847
  {
853
848
  "technicalId": "arrow-right",
854
849
  "displayNameDe": "Pfeil rechts",
855
850
  "tags": ["Pfeil", "vorwärts", "weiter"]
856
851
  },
852
+ {
853
+ "technicalId": "flash",
854
+ "displayNameDe": "Blitz",
855
+ "tags": ["Pfeil", "Fehler", "falsch"]
856
+ },
857
857
  {
858
858
  "technicalId": "arrow-top",
859
859
  "displayNameDe": "Pfeil oben",
@@ -0,0 +1,266 @@
1
+ ---
2
+ name: file-selector
3
+ title: File Selector
4
+ components:
5
+ - sd-button
6
+ - sd-divider
7
+ - sd-file-selector
8
+ - sd-headline
9
+ - sd-headline--size-3xl
10
+ - sd-headline--size-4xl
11
+ - sd-icon
12
+ - sd-input
13
+ - sd-interactive
14
+ - sd-interactive--reset
15
+ - sd-meta
16
+ - sd-meta--light
17
+ - sd-meta--size-sm
18
+ - sd-option
19
+ - sd-paragraph
20
+ - sd-progress-bar
21
+ - sd-select
22
+ - sd-tooltip
23
+ version: 1.0.0
24
+ ---
25
+
26
+ ## Template: File Selector with Default variant
27
+
28
+ ```html
29
+ <section>
30
+ <form id="identity-form" class="flex flex-col gap-6">
31
+ <div class="flex flex-col gap-2">
32
+ <h3 class="sd-headline sd-headline--size-4xl">Confirm your identity</h3>
33
+ <p class="sd-paragraph">
34
+ To safeguard your account, we need to verify who you are. Choose a document type below and upload a clear scan.
35
+ </p>
36
+ </div>
37
+ <div class="flex flex-col gap-6">
38
+ <span class="sd-meta sd-meta--size-sm sd-meta--light">Fields marked with * are required.</span>
39
+ <sd-select name="documentType" label="Document type" placeholder="Please select" required>
40
+ <sd-option value="passport">Passport</sd-option>
41
+ <sd-option value="id-card">ID card</sd-option>
42
+ </sd-select>
43
+ <sd-file-selector name="identityDocument" label="Upload document" show-label required></sd-file-selector>
44
+ </div>
45
+ </form>
46
+ </section>
47
+ ```
48
+
49
+ ## Template: File Selector with Drop Area variant
50
+
51
+ ```html
52
+ <section>
53
+ <form id="droparea-documents-form" class="flex flex-col gap-6">
54
+ <h3 class="sd-headline sd-headline--size-3xl">Tax Documents &amp; Depot Statements</h3>
55
+ <p class="sd-paragraph">
56
+ Please share your tax and depot records for the current year. Digital documents help us provide you with accurate
57
+ tax reporting services.
58
+ </p>
59
+ <div class="flex flex-col">
60
+ <span class="sd-meta sd-meta--size-sm sd-meta--light">Fields marked with * are required.</span>
61
+ <sd-file-selector
62
+ id="droparea-file-selector"
63
+ name="droparea-file-selector"
64
+ label="Upload documents"
65
+ show-label
66
+ drop-area
67
+ multiple
68
+ required
69
+ accept=".pdf,.jpg,.jpeg,.png"
70
+ help-text="Maximum file size 3 MB. Supported: PDF, JPG, PNG."
71
+ class="mt-6"
72
+ ></sd-file-selector>
73
+ <ul id="droparea-file-list" class="file-list flex flex-col gap-2 mt-2" aria-live="polite"></ul>
74
+ </div>
75
+ <div class="flex flex-col gap-4 md:flex-row md:justify-end">
76
+ <sd-button variant="secondary" onclick="alert('Cancelled process')">Cancel</sd-button>
77
+ <sd-tooltip id="droparea-submit-tooltip" trigger="hover focus" content="Please select one or more files.">
78
+ <sd-button id="droparea-submit-button" type="submit" visually-disabled>Submit documents</sd-button>
79
+ </sd-tooltip>
80
+ </div>
81
+ </form>
82
+ </section>
83
+ <script type="module">
84
+ await Promise.all([
85
+ customElements.whenDefined('sd-file-selector'),
86
+ customElements.whenDefined('sd-progress-bar'),
87
+ customElements.whenDefined('sd-button'),
88
+ customElements.whenDefined('sd-icon'),
89
+ customElements.whenDefined('sd-divider'),
90
+ customElements.whenDefined('sd-tooltip')
91
+ ]);
92
+
93
+ const MAX_FILE_SIZE = 3 * 1024 * 1024;
94
+ const ALLOWED_FILE_TYPES = ['application/pdf', 'image/jpeg', 'image/png'];
95
+ const NO_FILES_MESSAGE = 'Please select one or more files.';
96
+ const INVALID_FILES_MESSAGE = 'One or more files have errors. Please remove them and try again.';
97
+ const fileSelector = document.getElementById('droparea-file-selector');
98
+ const fileList = document.getElementById('droparea-file-list');
99
+ const submitButton = document.getElementById('droparea-submit-button');
100
+ const submitTooltip = document.getElementById('droparea-submit-tooltip');
101
+ let files = [];
102
+
103
+ // preview-ignore:start
104
+ const delay = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds));
105
+ const simulateUpload = async (file, progressBar, fileName) => {
106
+ for (let progress = 0; progress <= 100; progress += 1) {
107
+ progressBar.value = progress;
108
+ progressBar.label = 'Uploading ' + file.name + ': ' + progress + '%';
109
+
110
+ await delay(50);
111
+ }
112
+
113
+ progressBar.label = file.name + ' uploaded successfully';
114
+ await delay(300);
115
+
116
+ progressBar.remove();
117
+ fileName.classList.remove('shrink-0', 'text-neutral-700');
118
+ fileName.classList.add('flex-1', 'text-black');
119
+ };
120
+ // preview-ignore:end
121
+
122
+ const updateSubmitButtonState = () => {
123
+ const hasFiles = files.length > 0;
124
+ const hasInvalidFiles = fileList?.querySelector('li.invalid') !== null;
125
+ const isDisabled = !hasFiles || hasInvalidFiles;
126
+
127
+ submitButton.visuallyDisabled = isDisabled;
128
+ submitTooltip.disabled = !isDisabled;
129
+ submitTooltip.content = hasInvalidFiles ? INVALID_FILES_MESSAGE : NO_FILES_MESSAGE;
130
+ };
131
+
132
+ fileSelector.addEventListener('sd-input', event => {
133
+ fileList?.replaceChildren();
134
+
135
+ files = Array.from(event.currentTarget.files ?? []);
136
+ fileList?.classList.toggle('hidden', files.length === 0);
137
+
138
+ files.forEach((file, index) => {
139
+ const listItem = document.createElement('li');
140
+ const listRow = document.createElement('div');
141
+ const fileName = document.createElement('span');
142
+ const removeButton = document.createElement('button');
143
+
144
+ listItem.classList.add('flex', 'flex-col', 'text-sm', 'gap-2', 'text-left');
145
+ listRow.classList.add('flex', 'items-center', 'gap-2', 'w-full');
146
+ fileName.classList.add('shrink-0', 'truncate', 'text-neutral-700');
147
+ fileName.textContent = file.name;
148
+
149
+ removeButton.type = 'button';
150
+ removeButton.classList.add('sd-interactive', 'sd-interactive--reset', 'shrink-0', 'flex', 'items-center');
151
+ removeButton.title = 'Remove ' + file.name;
152
+ removeButton.setAttribute('aria-label', 'Remove ' + file.name);
153
+
154
+ const trashIcon = document.createElement('sd-icon');
155
+ trashIcon.setAttribute('name', 'system/trash');
156
+ trashIcon.setAttribute('color', 'currentColor');
157
+ trashIcon.setAttribute('aria-hidden', 'true');
158
+ trashIcon.classList.add('w-4', 'h-4');
159
+
160
+ removeButton.append(trashIcon);
161
+ listRow.append(fileName);
162
+
163
+ /**
164
+ * Client-side validation example.
165
+ * Files must also be validated by the server.
166
+ */
167
+ const errors = [];
168
+
169
+ if (!ALLOWED_FILE_TYPES.includes(file.type)) errors.push('Unsupported file type');
170
+ if (file.size > MAX_FILE_SIZE) errors.push('The file is too large. Maximum allowed size is 3 MB.');
171
+
172
+ if (errors.length === 0) {
173
+ const progressBar = document.createElement('sd-progress-bar');
174
+
175
+ progressBar.classList.add('flex-1');
176
+ progressBar.max = 100;
177
+ progressBar.value = 0;
178
+ progressBar.label = 'Uploading ' + file.name + ': 0%';
179
+
180
+ listRow.append(progressBar);
181
+
182
+ /**
183
+ * Connect the progress bar to your application's
184
+ * upload progress here.
185
+ */
186
+
187
+ // preview-ignore:start
188
+ simulateUpload(file, progressBar, fileName);
189
+ // preview-ignore:end
190
+ } else {
191
+ fileName.classList.add('flex-1');
192
+ }
193
+ listRow.append(removeButton);
194
+ listItem.append(listRow);
195
+
196
+ errors.forEach(message => {
197
+ const errorMessage = document.createElement('div');
198
+
199
+ errorMessage.classList.add('flex', 'items-center', 'gap-2', 'text-error', 'text-left', 'text-sm');
200
+ fileName.classList.remove('text-neutral-700');
201
+ fileName.classList.add('text-black');
202
+ errorMessage.setAttribute('role', 'alert');
203
+
204
+ const errorIcon = document.createElement('sd-icon');
205
+ errorIcon.setAttribute('name', 'system/warning');
206
+ errorIcon.setAttribute('color', 'currentColor');
207
+ errorIcon.setAttribute('aria-hidden', 'true');
208
+
209
+ const errorText = document.createElement('span');
210
+ errorText.textContent = message;
211
+
212
+ errorMessage.append(errorIcon, errorText);
213
+ listItem.append(errorMessage);
214
+ });
215
+
216
+ removeButton.addEventListener('click', () => {
217
+ files = files.filter(remainingFile => remainingFile !== file);
218
+
219
+ const dataTransfer = new DataTransfer();
220
+
221
+ files.forEach(remainingFile => {
222
+ dataTransfer.items.add(remainingFile);
223
+ });
224
+
225
+ fileSelector.files = dataTransfer.files;
226
+ listItem.remove();
227
+
228
+ const lastListItem = fileList?.querySelector('li:last-child');
229
+ const lastDivider = lastListItem?.querySelector(':scope > sd-divider');
230
+
231
+ lastDivider?.remove();
232
+ fileList?.classList.toggle('hidden', files.length === 0);
233
+ updateSubmitButtonState();
234
+ });
235
+
236
+ if (errors.length > 0) listItem.classList.add('invalid');
237
+
238
+ if (index < files.length - 1) {
239
+ const divider = document.createElement('sd-divider');
240
+ divider.setAttribute('aria-hidden', 'true');
241
+ listItem.append(divider);
242
+ }
243
+
244
+ fileList?.append(listItem);
245
+ });
246
+
247
+ updateSubmitButtonState();
248
+ });
249
+
250
+ const form = document.getElementById('droparea-documents-form');
251
+ form.onsubmit = event => {
252
+ event.preventDefault();
253
+
254
+ if (submitButton.visuallyDisabled) {
255
+ return;
256
+ }
257
+
258
+ if (form.checkValidity()) {
259
+ alert('Drop area form submitted');
260
+ return;
261
+ }
262
+
263
+ form.reportValidity();
264
+ };
265
+ </script>
266
+ ```
package/package.json CHANGED
@@ -20,9 +20,9 @@
20
20
  "prettier": "^3.9.5",
21
21
  "tsx": "^4.23.1",
22
22
  "typescript": "^5.9.3",
23
- "@solid-design-system/components": "7.0.3",
24
- "@solid-design-system/styles": "7.0.3",
25
- "@solid-design-system/tokens": "7.0.3"
23
+ "@solid-design-system/components": "7.1.0",
24
+ "@solid-design-system/styles": "7.1.0",
25
+ "@solid-design-system/tokens": "7.1.0"
26
26
  },
27
27
  "exports": {
28
28
  ".": {
@@ -59,7 +59,7 @@
59
59
  "directory": "packages/mcp"
60
60
  },
61
61
  "type": "module",
62
- "version": "7.0.3",
62
+ "version": "7.1.0",
63
63
  "scripts": {
64
64
  "build": "pnpm run build:components && pnpm run build:tokens && pnpm run build:ts && pnpm run build:metadata && cd ../.. && pnpm exec prettier --write --log-level warn packages/mcp/metadata",
65
65
  "build:components": "cd ../components && pnpm exec node scripts/make-metadata.js --outdir dist",