@inglorious/ui 6.0.0 → 7.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.
Files changed (39) hide show
  1. package/package.json +32 -12
  2. package/src/controls/controls.css +3 -1
  3. package/src/controls/file-upload/file-upload.stories.js +93 -0
  4. package/src/controls/file-upload/index.js +3 -0
  5. package/src/controls/file-upload/style.css +99 -0
  6. package/src/controls/file-upload/template.js +100 -0
  7. package/src/controls/input/input.stories.js +110 -3
  8. package/src/controls/textarea/index.js +3 -0
  9. package/src/controls/textarea/style.css +98 -0
  10. package/src/controls/textarea/template.js +94 -0
  11. package/src/controls/textarea/textarea.stories.js +158 -0
  12. package/src/data-display/before-after/before-after.stories.js +74 -0
  13. package/src/data-display/before-after/handlers.js +44 -0
  14. package/src/data-display/before-after/helpers.js +4 -0
  15. package/src/data-display/before-after/index.js +17 -0
  16. package/src/data-display/before-after/style.css +128 -0
  17. package/src/data-display/before-after/template.js +225 -0
  18. package/src/data-display/carousel/carousel.stories.js +166 -0
  19. package/src/data-display/carousel/handlers.js +78 -0
  20. package/src/data-display/carousel/helpers.js +54 -0
  21. package/src/data-display/carousel/index.js +17 -0
  22. package/src/data-display/carousel/style.css +233 -0
  23. package/src/data-display/carousel/template.js +655 -0
  24. package/src/data-display/data-display.css +2 -0
  25. package/src/examples/dashboard/app-drawer.js +12 -0
  26. package/src/examples/dashboard/before-after-data.js +29 -0
  27. package/src/examples/dashboard/primitive-content.js +220 -33
  28. package/src/index.js +4 -0
  29. package/src/layout/flex/flex.stories.js +49 -0
  30. package/src/layout/flex/style.css +59 -0
  31. package/src/layout/flex/template.js +2 -0
  32. package/types/controls/file-upload.d.ts +27 -0
  33. package/types/controls/input.d.ts +6 -0
  34. package/types/controls/textarea.d.ts +29 -0
  35. package/types/controls/upload-field.d.ts +27 -0
  36. package/types/data-display/before-after.d.ts +39 -0
  37. package/types/data-display/carousel.d.ts +72 -0
  38. package/types/index.d.ts +2 -0
  39. package/types/layout/flex.d.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/ui",
3
- "version": "6.0.0",
3
+ "version": "7.0.0",
4
4
  "description": "A design system for Inglorious Web with render-function components and customizable themes",
5
5
  "author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
@@ -38,6 +38,11 @@
38
38
  "./themes/inglorious.css": "./src/styles/themes/inglorious.css",
39
39
  "./themes/material.css": "./src/styles/themes/material.css",
40
40
  "./themes/bootstrap.css": "./src/styles/themes/bootstrap.css",
41
+ "./before-after": {
42
+ "types": "./types/data-display/before-after.d.ts",
43
+ "import": "./src/data-display/before-after/index.js"
44
+ },
45
+ "./before-after.css": "./src/data-display/before-after/style.css",
41
46
  "./button": {
42
47
  "types": "./types/controls/button.d.ts",
43
48
  "import": "./src/controls/button/index.js"
@@ -48,6 +53,11 @@
48
53
  "import": "./src/controls/button-group/index.js"
49
54
  },
50
55
  "./button-group.css": "./src/controls/button-group/style.css",
56
+ "./carousel": {
57
+ "types": "./types/data-display/carousel.d.ts",
58
+ "import": "./src/data-display/carousel/index.js"
59
+ },
60
+ "./carousel.css": "./src/data-display/carousel/style.css",
51
61
  "./checkbox": {
52
62
  "types": "./types/controls/checkbox.d.ts",
53
63
  "import": "./src/controls/checkbox/index.js"
@@ -103,6 +113,16 @@
103
113
  "import": "./src/controls/switch/index.js"
104
114
  },
105
115
  "./switch.css": "./src/controls/switch/style.css",
116
+ "./textarea": {
117
+ "types": "./types/controls/textarea.d.ts",
118
+ "import": "./src/controls/textarea/index.js"
119
+ },
120
+ "./textarea.css": "./src/controls/textarea/style.css",
121
+ "./file-upload": {
122
+ "types": "./types/controls/file-upload.d.ts",
123
+ "import": "./src/controls/file-upload/index.js"
124
+ },
125
+ "./file-upload.css": "./src/controls/file-upload/style.css",
106
126
  "./card": {
107
127
  "types": "./types/surfaces/card.d.ts",
108
128
  "import": "./src/surfaces/card/index.js"
@@ -280,28 +300,28 @@
280
300
  "**/*.css"
281
301
  ],
282
302
  "peerDependencies": {
283
- "@inglorious/charts": "9.0.0",
284
- "@inglorious/utils": "3.8.0",
285
- "@inglorious/web": "6.3.0",
286
- "@inglorious/store": "11.0.0"
303
+ "@inglorious/charts": "10.0.0",
304
+ "@inglorious/store": "11.0.0",
305
+ "@inglorious/web": "6.4.0",
306
+ "@inglorious/utils": "3.8.0"
287
307
  },
288
308
  "devDependencies": {
289
309
  "@fontsource/material-symbols-outlined": "^5.2.36",
290
310
  "@fortawesome/fontawesome-free": "^7.2.0",
291
- "@storybook/addon-docs": "^10.3.3",
292
- "@storybook/web-components-vite": "^10.3.3",
311
+ "@storybook/addon-docs": "^10.5.6",
312
+ "@storybook/web-components-vite": "^10.5.6",
293
313
  "happy-dom": "^15.11.0",
294
314
  "jsdom": "^25.0.0",
295
315
  "lucide": "^0.575.0",
296
316
  "prettier": "^3.6.2",
297
- "storybook": "^10.3.3",
317
+ "storybook": "^10.5.6",
298
318
  "vite": "^7.3.1",
299
319
  "vitest": "^4.0.15",
300
- "@inglorious/vite-plugin-jsx": "2.0.0",
320
+ "@inglorious/eslint-config": "1.1.2",
321
+ "@inglorious/web": "6.4.0",
301
322
  "@inglorious/vite-plugin-vue": "1.0.1",
302
- "@inglorious/store": "11.0.0",
303
- "@inglorious/web": "6.3.0",
304
- "@inglorious/eslint-config": "1.1.2"
323
+ "@inglorious/vite-plugin-jsx": "2.0.0",
324
+ "@inglorious/store": "11.0.0"
305
325
  },
306
326
  "engines": {
307
327
  "node": ">= 22"
@@ -1,7 +1,7 @@
1
- @import "./combobox/style.css";
2
1
  @import "./button/style.css";
3
2
  @import "./button-group/style.css";
4
3
  @import "./checkbox/style.css";
4
+ @import "./combobox/style.css";
5
5
  @import "./fab/style.css";
6
6
  @import "./icon-button/style.css";
7
7
  @import "./input/style.css";
@@ -10,3 +10,5 @@
10
10
  @import "./select/style.css";
11
11
  @import "./slider/style.css";
12
12
  @import "./switch/style.css";
13
+ @import "./textarea/style.css";
14
+ @import "./file-upload/style.css";
@@ -0,0 +1,93 @@
1
+ import { createRender } from "../../stories/notifyStory.js"
2
+ import { FileUpload } from "./index.js"
3
+
4
+ export default {
5
+ title: "Controls/FileUpload",
6
+ tags: ["autodocs"],
7
+ render: createRender(FileUpload),
8
+ argTypes: {
9
+ label: {
10
+ control: "text",
11
+ description: "Field label rendered above the upload area.",
12
+ },
13
+ name: {
14
+ control: "text",
15
+ description: "Native HTML file input name attribute.",
16
+ },
17
+ accept: {
18
+ control: "text",
19
+ description: "Accepted file types, such as .pdf,.png,image/*.",
20
+ },
21
+ isMultiple: {
22
+ control: "boolean",
23
+ description: "Allows selecting multiple files.",
24
+ },
25
+ hint: {
26
+ control: "text",
27
+ description: "Helper text shown below the field when there is no error.",
28
+ },
29
+ error: {
30
+ control: "text",
31
+ description: "Validation message shown below the field.",
32
+ },
33
+ isDisabled: {
34
+ control: "boolean",
35
+ description: "Disables user input and interaction.",
36
+ },
37
+ isRequired: {
38
+ control: "boolean",
39
+ description: "Marks the field as required.",
40
+ },
41
+ isFullWidth: {
42
+ control: "boolean",
43
+ description: "Expands the upload area width to 100% of its container.",
44
+ },
45
+ selectedFiles: {
46
+ control: "object",
47
+ description: "Current list of selected file names for display.",
48
+ },
49
+ onChange: { action: "onChange" },
50
+ onBlur: { action: "onBlur" },
51
+ onFocus: { action: "onFocus" },
52
+ },
53
+ parameters: {
54
+ docs: {
55
+ description: {
56
+ component:
57
+ "Upload area for files with native input semantics, validation, and a clean drag-and-drop style.",
58
+ },
59
+ },
60
+ },
61
+ }
62
+
63
+ export const Default = {}
64
+ Default.args = {
65
+ label: "Resume",
66
+ name: "resume",
67
+ accept: ".pdf,.doc,.docx",
68
+ isMultiple: false,
69
+ hint: "Upload your resume in PDF or DOC format.",
70
+ error: "",
71
+ isDisabled: false,
72
+ isRequired: false,
73
+ isFullWidth: false,
74
+ selectedFiles: [],
75
+ title: "Choose file",
76
+ description: "or drag and drop here",
77
+ }
78
+
79
+ export const Selected = {}
80
+ Selected.args = {
81
+ ...Default.args,
82
+ label: "Attachments",
83
+ isMultiple: true,
84
+ selectedFiles: ["brief.pdf", "notes.md"],
85
+ }
86
+
87
+ export const Error = {}
88
+ Error.args = {
89
+ ...Default.args,
90
+ label: "Invoice",
91
+ error: "Only PDF files under 5MB are allowed.",
92
+ selectedFiles: ["invoice.png"],
93
+ }
@@ -0,0 +1,3 @@
1
+ import * as renderers from "./template.js"
2
+
3
+ export const FileUpload = { ...renderers }
@@ -0,0 +1,99 @@
1
+ .iw-upload {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--iw-space-1);
5
+ font-family: var(--iw-font-family-sans);
6
+
7
+ &.iw-upload-full-width .iw-upload-field-box {
8
+ width: 100%;
9
+ }
10
+
11
+ .iw-upload-label {
12
+ font-size: var(--iw-font-size-sm);
13
+ font-weight: var(--iw-font-weight-normal);
14
+ color: var(--iw-color-text);
15
+ }
16
+
17
+ .iw-upload-required {
18
+ color: var(--iw-color-error);
19
+ margin-left: var(--iw-space-1);
20
+ }
21
+
22
+ .iw-upload-field-box {
23
+ position: relative;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ min-height: 7rem;
28
+ padding: var(--iw-space-4);
29
+ border: 1px dashed var(--iw-input-border);
30
+ border-radius: var(--iw-input-radius);
31
+ background: var(--iw-input-bg);
32
+ color: var(--iw-color-text);
33
+ transition: all var(--iw-transition-fast);
34
+ cursor: pointer;
35
+
36
+ &:hover:not(:disabled) {
37
+ background: var(--iw-input-bg-hover);
38
+ border-color: var(--iw-input-border-hover);
39
+ }
40
+
41
+ &:focus-within {
42
+ border-color: var(--iw-input-border-focus);
43
+ box-shadow: var(--iw-input-shadow-focus);
44
+ }
45
+
46
+ &.iw-upload-field-error {
47
+ border-color: var(--iw-color-error);
48
+
49
+ &:focus-within {
50
+ border-color: var(--iw-color-error);
51
+ box-shadow: 0 0 0 1px var(--iw-color-error);
52
+ }
53
+ }
54
+ }
55
+
56
+ .iw-upload-input {
57
+ position: absolute;
58
+ inset: 0;
59
+ opacity: 0;
60
+ cursor: pointer;
61
+ }
62
+
63
+ .iw-upload-content {
64
+ display: flex;
65
+ flex-direction: column;
66
+ align-items: center;
67
+ gap: var(--iw-space-1);
68
+ pointer-events: none;
69
+ text-align: center;
70
+ }
71
+
72
+ .iw-upload-title {
73
+ font-weight: var(--iw-font-weight-medium);
74
+ }
75
+
76
+ .iw-upload-description {
77
+ color: var(--iw-color-text-muted);
78
+ font-size: var(--iw-font-size-sm);
79
+ }
80
+
81
+ .iw-upload-field-summary {
82
+ font-size: var(--iw-font-size-sm);
83
+ color: var(--iw-color-text-muted);
84
+ }
85
+
86
+ .iw-upload-hint,
87
+ .iw-upload-error-message {
88
+ font-size: var(--iw-font-size-sm);
89
+ line-height: var(--iw-line-height-normal);
90
+ }
91
+
92
+ .iw-upload-hint {
93
+ color: var(--iw-color-text-muted);
94
+ }
95
+
96
+ .iw-upload-error-message {
97
+ color: var(--iw-color-error);
98
+ }
99
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @typedef {import('../../../types/controls/file-upload').FileUploadProps} FileUploadProps
3
+ * @typedef {import('@inglorious/web').TemplateResult} TemplateResult
4
+ */
5
+
6
+ import { html } from "@inglorious/web"
7
+ import { classMap } from "@inglorious/web/directives/class-map"
8
+ import { ref } from "@inglorious/web/directives/ref"
9
+
10
+ import { applyElementProps } from "../../shared/applyElementProps.js"
11
+
12
+ /**
13
+ * Renders a labeled file upload area with optional summary, hint, and error text.
14
+ * Supports drag-and-drop handling through file input semantics.
15
+ * @param {FileUploadProps} props
16
+ * @returns {TemplateResult}
17
+ */
18
+ export function render(props) {
19
+ const {
20
+ id,
21
+ name = "",
22
+ label,
23
+ hint,
24
+ error,
25
+ accept,
26
+ isMultiple = false,
27
+ isDisabled = false,
28
+ isRequired = false,
29
+ isFullWidth = false,
30
+ selectedFiles = [],
31
+ title = "Choose files",
32
+ description = "or drag and drop here",
33
+ onChange,
34
+ onBlur,
35
+ onFocus,
36
+ ...rest
37
+ } = props
38
+
39
+ const uploadId = id || name || "file-upload"
40
+
41
+ const wrapperClasses = {
42
+ "iw-upload": true,
43
+ "iw-upload-full-width": isFullWidth,
44
+ "iw-upload-disabled": isDisabled,
45
+ "iw-upload-has-error": !!error,
46
+ }
47
+
48
+ const fieldClasses = {
49
+ "iw-upload-field-box": true,
50
+ "iw-upload-field-error": !!error,
51
+ }
52
+
53
+ const summaryText =
54
+ selectedFiles.length > 0 ? selectedFiles.join(", ") : "No file selected"
55
+
56
+ return html`
57
+ <div class=${classMap(wrapperClasses)}>
58
+ ${label
59
+ ? html`
60
+ <label for=${uploadId} class="iw-upload-label">
61
+ ${label}
62
+ ${isRequired
63
+ ? html`<span class="iw-upload-required">*</span>`
64
+ : null}
65
+ </label>
66
+ `
67
+ : null}
68
+
69
+ <div class=${classMap(fieldClasses)}>
70
+ <input
71
+ id=${uploadId}
72
+ name=${name}
73
+ type="file"
74
+ accept=${accept ?? ""}
75
+ ?multiple=${isMultiple}
76
+ ?disabled=${isDisabled}
77
+ ?required=${isRequired}
78
+ class="iw-upload-input"
79
+ @change=${(event) => onChange?.(event.target.files)}
80
+ @blur=${onBlur}
81
+ @focus=${onFocus}
82
+ ${ref((element) => applyElementProps(element, rest))}
83
+ />
84
+
85
+ <div class="iw-upload-content">
86
+ <span class="iw-upload-title">${title}</span>
87
+ <span class="iw-upload-description">${description}</span>
88
+ </div>
89
+ </div>
90
+
91
+ <div class="iw-upload-field-summary">${summaryText}</div>
92
+
93
+ ${error
94
+ ? html`<span class="iw-upload-error-message">${error}</span>`
95
+ : hint
96
+ ? html`<span class="iw-upload-hint">${hint}</span>`
97
+ : null}
98
+ </div>
99
+ `
100
+ }
@@ -1,12 +1,45 @@
1
+ import { html } from "@inglorious/web"
2
+
1
3
  import { createRender } from "../../stories/notifyStory.js"
2
4
  import { Input } from "."
3
5
 
6
+ const nativeInputTypes = [
7
+ "text",
8
+ "password",
9
+ "email",
10
+ "number",
11
+ "tel",
12
+ "url",
13
+ "search",
14
+ "date",
15
+ "time",
16
+ "datetime-local",
17
+ "month",
18
+ "week",
19
+ "color",
20
+ ]
21
+
22
+ const nativeInputDefaults = {
23
+ text: { label: "Text", value: "Hello world" },
24
+ password: { label: "Password", value: "secret123" },
25
+ email: { label: "Email", value: "you@example.com" },
26
+ number: { label: "Number", value: "42" },
27
+ tel: { label: "Phone", value: "+1 555 123 4567" },
28
+ url: { label: "Website", value: "https://example.com" },
29
+ search: { label: "Search", value: "inglorious" },
30
+ date: { label: "Date", value: "2026-08-10" },
31
+ time: { label: "Time", value: "09:30" },
32
+ "datetime-local": { label: "Date and time", value: "2026-08-10T09:30" },
33
+ month: { label: "Month", value: "2026-08" },
34
+ week: { label: "Week", value: "2026-W32" },
35
+ color: { label: "Color", value: "#7c3aed" },
36
+ }
37
+
4
38
  export default {
5
39
  title: "Controls/Input",
6
40
  tags: ["autodocs"],
7
41
  render: createRender(Input),
8
42
  argTypes: {
9
- // ...notifyActionArgType,
10
43
  label: {
11
44
  control: "text",
12
45
  description: "Field label rendered above the input.",
@@ -19,9 +52,9 @@ export default {
19
52
  control: "text",
20
53
  description: "Native HTML input name attribute.",
21
54
  },
22
- type: {
55
+ inputType: {
23
56
  control: "select",
24
- options: ["text", "email", "password", "number", "tel", "url", "search"],
57
+ options: nativeInputTypes,
25
58
  description: "Native HTML input type.",
26
59
  },
27
60
  inputmode: {
@@ -101,6 +134,28 @@ Default.args = {
101
134
  isFullWidth: false,
102
135
  }
103
136
 
137
+ export const ManagedNativeTypes = {
138
+ render: (args) => html`
139
+ <div style="display: grid; gap: 1rem; max-width: 40rem;">
140
+ ${nativeInputTypes.map((inputType) =>
141
+ Input.render({
142
+ ...args,
143
+ ...nativeInputDefaults[inputType],
144
+ name: `${inputType}-field`,
145
+ label: nativeInputDefaults[inputType].label,
146
+ inputType,
147
+ value: nativeInputDefaults[inputType].value,
148
+ }),
149
+ )}
150
+ </div>
151
+ `,
152
+ }
153
+
154
+ ManagedNativeTypes.args = {
155
+ ...Default.args,
156
+ label: "Managed native types",
157
+ }
158
+
104
159
  export const WithHint = {}
105
160
  WithHint.args = {
106
161
  ...Default.args,
@@ -179,3 +234,55 @@ Number.args = {
179
234
  inputmode: "decimal",
180
235
  "data-testid": "amount-input",
181
236
  }
237
+
238
+ export const Date = {}
239
+ Date.args = {
240
+ ...Default.args,
241
+ label: "Date",
242
+ inputType: "date",
243
+ value: "2026-08-10",
244
+ min: "2024-01-01",
245
+ max: "2027-12-31",
246
+ }
247
+
248
+ export const Time = {}
249
+ Time.args = {
250
+ ...Default.args,
251
+ label: "Time",
252
+ inputType: "time",
253
+ value: "09:30",
254
+ min: "08:00",
255
+ max: "18:00",
256
+ }
257
+
258
+ export const DateTimeLocal = {}
259
+ DateTimeLocal.args = {
260
+ ...Default.args,
261
+ label: "Date and time",
262
+ inputType: "datetime-local",
263
+ value: "2026-08-10T09:30",
264
+ }
265
+
266
+ export const Month = {}
267
+ Month.args = {
268
+ ...Default.args,
269
+ label: "Month",
270
+ inputType: "month",
271
+ value: "2026-08",
272
+ }
273
+
274
+ export const Week = {}
275
+ Week.args = {
276
+ ...Default.args,
277
+ label: "Week",
278
+ inputType: "week",
279
+ value: "2026-W32",
280
+ }
281
+
282
+ export const Color = {}
283
+ Color.args = {
284
+ ...Default.args,
285
+ label: "Color",
286
+ inputType: "color",
287
+ value: "#7c3aed",
288
+ }
@@ -0,0 +1,3 @@
1
+ import * as renderers from "./template.js"
2
+
3
+ export const Textarea = { ...renderers }
@@ -0,0 +1,98 @@
1
+ .iw-textarea-field {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--iw-space-1);
5
+ font-family: var(--iw-font-family-sans);
6
+
7
+ &.iw-textarea-full-width .iw-textarea {
8
+ width: 100%;
9
+ }
10
+
11
+ .iw-textarea-label {
12
+ font-size: var(--iw-font-size-sm);
13
+ font-weight: var(--iw-font-weight-normal);
14
+ color: var(--iw-color-text);
15
+ }
16
+
17
+ .iw-textarea-required {
18
+ color: var(--iw-color-error);
19
+ margin-left: var(--iw-space-1);
20
+ }
21
+
22
+ .iw-textarea {
23
+ min-height: 3rem;
24
+ width: min(100%, 100%);
25
+ resize: none;
26
+ padding: var(--iw-space-2) var(--iw-space-3);
27
+ font-family: inherit;
28
+ font-size: var(--iw-font-size-base);
29
+ line-height: 1.5;
30
+ color: var(--iw-input-text);
31
+ background-color: var(--iw-input-bg);
32
+ border: 1px solid var(--iw-input-border);
33
+ border-radius: var(--iw-input-radius);
34
+ outline: none;
35
+ transition: all var(--iw-transition-fast);
36
+
37
+ &::placeholder {
38
+ color: var(--iw-input-text-placeholder);
39
+ }
40
+
41
+ &:hover:not(:disabled) {
42
+ background-color: var(--iw-input-bg-hover);
43
+ border-color: var(--iw-input-border-hover);
44
+ }
45
+
46
+ &:focus:not(:disabled) {
47
+ background-color: var(--iw-input-bg-focus);
48
+ border-color: var(--iw-input-border-focus);
49
+ box-shadow: var(--iw-input-shadow-focus);
50
+ }
51
+
52
+ &:disabled {
53
+ opacity: 0.5;
54
+ cursor: not-allowed;
55
+ }
56
+
57
+ &.iw-textarea-auto-size {
58
+ field-sizing: content;
59
+ }
60
+
61
+ &.iw-textarea-resizable {
62
+ resize: vertical;
63
+ }
64
+
65
+ &.iw-textarea-error {
66
+ border-color: var(--iw-color-error);
67
+
68
+ &:focus {
69
+ border-color: var(--iw-color-error);
70
+ box-shadow: 0 0 0 1px var(--iw-color-error);
71
+ }
72
+ }
73
+
74
+ &.iw-textarea-sm {
75
+ padding: var(--iw-space-1) var(--iw-space-2);
76
+ font-size: var(--iw-font-size-sm);
77
+ }
78
+
79
+ &.iw-textarea-lg {
80
+ padding: var(--iw-space-3) var(--iw-space-4);
81
+ font-size: var(--iw-font-size-lg);
82
+ }
83
+ }
84
+
85
+ .iw-textarea-hint,
86
+ .iw-textarea-error-message {
87
+ font-size: var(--iw-font-size-sm);
88
+ line-height: var(--iw-line-height-normal);
89
+ }
90
+
91
+ .iw-textarea-hint {
92
+ color: var(--iw-color-text-muted);
93
+ }
94
+
95
+ .iw-textarea-error-message {
96
+ color: var(--iw-color-error);
97
+ }
98
+ }