@noxlovette/material 0.9.3 → 0.10.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 (68) hide show
  1. package/dist/components/buttons/connected/theme.d.ts +15 -15
  2. package/dist/components/buttons/connected/theme.js +20 -5
  3. package/dist/components/buttons/split-button/theme.d.ts +15 -15
  4. package/dist/components/buttons/split-button/theme.js +21 -15
  5. package/dist/components/buttons/theme.d.ts +40 -40
  6. package/dist/components/buttons/theme.js +29 -29
  7. package/dist/components/cards/theme.js +1 -1
  8. package/dist/components/chips/Chip.svelte +1 -1
  9. package/dist/components/chips/theme.js +1 -1
  10. package/dist/components/containers/bottom-sheet/theme.js +1 -1
  11. package/dist/components/containers/carousel/theme.js +1 -1
  12. package/dist/components/containers/context-menu/theme.js +2 -2
  13. package/dist/components/containers/dialogue/theme.js +1 -1
  14. package/dist/components/containers/list/theme.d.ts +3 -3
  15. package/dist/components/containers/list/theme.js +8 -8
  16. package/dist/components/containers/menu/theme.js +3 -3
  17. package/dist/components/date/theme.js +2 -2
  18. package/dist/components/forms/checkbox/theme.js +1 -1
  19. package/dist/components/forms/command/theme.js +1 -1
  20. package/dist/components/forms/index.d.ts +1 -0
  21. package/dist/components/forms/index.js +1 -0
  22. package/dist/components/forms/search/theme.js +1 -1
  23. package/dist/components/forms/select/theme.js +2 -2
  24. package/dist/components/forms/slider/Slider.svelte +8 -0
  25. package/dist/components/forms/slider/theme.js +7 -7
  26. package/dist/components/forms/slider/types.d.ts +13 -0
  27. package/dist/components/forms/textarea/Textarea.mdx +63 -0
  28. package/dist/components/forms/textarea/Textarea.stories.svelte +99 -0
  29. package/dist/components/forms/textarea/Textarea.stories.svelte.d.ts +19 -0
  30. package/dist/components/forms/textarea/Textarea.svelte +142 -0
  31. package/dist/components/forms/textarea/Textarea.svelte.d.ts +13 -0
  32. package/dist/components/forms/textarea/index.d.ts +3 -0
  33. package/dist/components/forms/textarea/index.js +6 -0
  34. package/dist/components/forms/textarea/theme.d.ts +150 -0
  35. package/dist/components/forms/textarea/theme.js +155 -0
  36. package/dist/components/forms/textarea/types.d.ts +59 -0
  37. package/dist/components/forms/textarea/types.js +1 -0
  38. package/dist/components/forms/textfield/theme.js +4 -4
  39. package/dist/components/forms/toggle-group/theme.js +2 -2
  40. package/dist/components/misc/ThemeSettings.svelte +1 -1
  41. package/dist/components/misc/materialAvatarPalette.js +1 -1
  42. package/dist/components/nav/appbar/theme.js +22 -6
  43. package/dist/components/nav/navbar/theme.js +1 -1
  44. package/dist/components/nav/tabs/theme.js +1 -1
  45. package/dist/components/progress/CircularProgress.svelte +5 -3
  46. package/dist/components/progress/CircularProgress.svelte.d.ts +2 -1
  47. package/dist/components/progress/LinearProgress.svelte +5 -2
  48. package/dist/components/progress/LinearProgress.svelte.d.ts +2 -1
  49. package/dist/components/progress/WavyLinearProgress.svelte +5 -3
  50. package/dist/components/progress/WavyLinearProgress.svelte.d.ts +2 -1
  51. package/dist/components/progress/index.d.ts +1 -0
  52. package/dist/components/progress/index.js +1 -0
  53. package/dist/components/progress/types.d.ts +16 -0
  54. package/dist/components/progress/types.js +1 -0
  55. package/dist/components/snackbar/theme.js +1 -1
  56. package/dist/components/table/TableHeader.svelte +1 -1
  57. package/dist/components/toolbar/theme.js +2 -2
  58. package/dist/styles/components.css +7 -2
  59. package/dist/styles/icon.css +19 -0
  60. package/dist/styles/rounding.css +4 -0
  61. package/dist/utils/Theme.svelte +1 -1
  62. package/dist/utils/ThemeScript.svelte +1 -1
  63. package/dist/utils/icon/Icon.svelte +5 -5
  64. package/dist/utils/index.d.ts +2 -2
  65. package/dist/utils/index.js +1 -1
  66. package/package.json +1 -1
  67. /package/dist/utils/{theme.svelte.d.ts → themeState.svelte.d.ts} +0 -0
  68. /package/dist/utils/{theme.svelte.js → themeState.svelte.js} +0 -0
@@ -0,0 +1,150 @@
1
+ import { type VariantProps } from '../../../utils/tv.js';
2
+ export type TextareaVariants = VariantProps<typeof textarea>;
3
+ /**
4
+ * M3 defines a multi-line text field but no separate textarea spec. This keeps the text field's
5
+ * containers, label, notch and indicator, and changes only what a growing field has to:
6
+ * the container has a 56dp minimum instead of a fixed height, and the label and icons line up
7
+ * with the first line instead of the vertical center.
8
+ */
9
+ export declare const textarea: import("tailwind-variants").TVReturnType<{
10
+ variant: {
11
+ filled: {
12
+ base: string;
13
+ inputWrapper: string;
14
+ leadingIcon: string;
15
+ trailingIcon: string;
16
+ label: string;
17
+ };
18
+ outlined: {
19
+ inputWrapper: string;
20
+ label: string;
21
+ };
22
+ };
23
+ error: {
24
+ true: {
25
+ base: string;
26
+ label: string;
27
+ supportingText: string;
28
+ leadingIcon: string;
29
+ trailingIcon: string;
30
+ fieldset: string;
31
+ };
32
+ };
33
+ leadingIcon: {
34
+ true: {};
35
+ };
36
+ disabled: {
37
+ true: {
38
+ base: string;
39
+ inputWrapper: string;
40
+ fieldset: string;
41
+ };
42
+ };
43
+ }, {
44
+ base: string;
45
+ inputWrapper: string;
46
+ input: string;
47
+ label: string;
48
+ requiredAsterisk: string;
49
+ leadingIcon: string;
50
+ trailingIcon: string;
51
+ supportingText: string;
52
+ counter: string;
53
+ fieldset: string;
54
+ legend: string;
55
+ legendLabel: string;
56
+ }, undefined, {
57
+ variant: {
58
+ filled: {
59
+ base: string;
60
+ inputWrapper: string;
61
+ leadingIcon: string;
62
+ trailingIcon: string;
63
+ label: string;
64
+ };
65
+ outlined: {
66
+ inputWrapper: string;
67
+ label: string;
68
+ };
69
+ };
70
+ error: {
71
+ true: {
72
+ base: string;
73
+ label: string;
74
+ supportingText: string;
75
+ leadingIcon: string;
76
+ trailingIcon: string;
77
+ fieldset: string;
78
+ };
79
+ };
80
+ leadingIcon: {
81
+ true: {};
82
+ };
83
+ disabled: {
84
+ true: {
85
+ base: string;
86
+ inputWrapper: string;
87
+ fieldset: string;
88
+ };
89
+ };
90
+ }, {
91
+ base: string;
92
+ inputWrapper: string;
93
+ input: string;
94
+ label: string;
95
+ requiredAsterisk: string;
96
+ leadingIcon: string;
97
+ trailingIcon: string;
98
+ supportingText: string;
99
+ counter: string;
100
+ fieldset: string;
101
+ legend: string;
102
+ legendLabel: string;
103
+ }, import("tailwind-variants").TVReturnTypeLike<{
104
+ variant: {
105
+ filled: {
106
+ base: string;
107
+ inputWrapper: string;
108
+ leadingIcon: string;
109
+ trailingIcon: string;
110
+ label: string;
111
+ };
112
+ outlined: {
113
+ inputWrapper: string;
114
+ label: string;
115
+ };
116
+ };
117
+ error: {
118
+ true: {
119
+ base: string;
120
+ label: string;
121
+ supportingText: string;
122
+ leadingIcon: string;
123
+ trailingIcon: string;
124
+ fieldset: string;
125
+ };
126
+ };
127
+ leadingIcon: {
128
+ true: {};
129
+ };
130
+ disabled: {
131
+ true: {
132
+ base: string;
133
+ inputWrapper: string;
134
+ fieldset: string;
135
+ };
136
+ };
137
+ }, {
138
+ base: string;
139
+ inputWrapper: string;
140
+ input: string;
141
+ label: string;
142
+ requiredAsterisk: string;
143
+ leadingIcon: string;
144
+ trailingIcon: string;
145
+ supportingText: string;
146
+ counter: string;
147
+ fieldset: string;
148
+ legend: string;
149
+ legendLabel: string;
150
+ }>>;
@@ -0,0 +1,155 @@
1
+ import { tv } from '../../../utils/tv.js';
2
+ /**
3
+ * M3 defines a multi-line text field but no separate textarea spec. This keeps the text field's
4
+ * containers, label, notch and indicator, and changes only what a growing field has to:
5
+ * the container has a 56dp minimum instead of a fixed height, and the label and icons line up
6
+ * with the first line instead of the vertical center.
7
+ */
8
+ export const textarea = tv({
9
+ slots: {
10
+ base: `
11
+ group relative w-full min-h-spacing-700 flex items-start
12
+ `,
13
+ /* The wrapper holds the vertical padding, not the textarea, so text scrolled past `maxRows`
14
+ is clipped at the textarea's edge instead of sliding under the floated label. */
15
+ inputWrapper: `
16
+ relative flex-1 self-stretch px-spacing-200 cursor-text
17
+ `,
18
+ input: `
19
+ peer block w-full bg-transparent outline-none resize-none field-sizing-content
20
+ md-sys-typescale-body-large text-md-sys-color-on-surface
21
+ disabled:text-md-sys-color-on-surface/38 disabled:cursor-not-allowed
22
+ `,
23
+ label: `
24
+ absolute left-spacing-200 top-spacing-200
25
+ md-sys-typescale-body-large
26
+ text-md-sys-color-on-surface-variant
27
+ pointer-events-none
28
+ transition-[top,left,font-size,line-height,color,transform] md-sys-motion-fast-spatial
29
+
30
+ peer-focus:text-md-sys-color-primary
31
+ `,
32
+ requiredAsterisk: `
33
+ ml-spacing-25
34
+ text-md-sys-color-error
35
+ group-focus-within:text-md-sys-color-primary
36
+ transition-colors md-sys-motion-effects
37
+ `,
38
+ /* On the first line of text: 16dp from the top when outlined, 24dp when filled. */
39
+ leadingIcon: `
40
+ text-md-sys-color-on-surface-variant size-(--text-icon-24)
41
+ group-focus-within:text-md-sys-color-primary
42
+ ml-spacing-150 mt-spacing-200 text-icon-24
43
+ `,
44
+ /* Sized to the 24dp glyph like Textfield's, so it takes the same offset as the leading icon. */
45
+ trailingIcon: `
46
+ mr-spacing-150 mt-spacing-200 text-md-sys-color-on-surface-variant size-(--text-icon-24)
47
+ group-focus-within:text-md-sys-color-primary
48
+ z-20 text-icon-24
49
+ `,
50
+ supportingText: `
51
+ px-spacing-200 pt-spacing-50 flex justify-between gap-spacing-200
52
+ md-sys-typescale-body-small
53
+ text-md-sys-color-on-surface-variant
54
+ `,
55
+ counter: `
56
+ ms-auto shrink-0
57
+ `,
58
+ fieldset: `
59
+ absolute -top-spacing-100 left-spacing-0 right-spacing-0 bottom-spacing-0 m-spacing-0 px-spacing-150
60
+ pointer-events-none rounded-xs border border-md-sys-color-outline
61
+ transition-colors md-sys-motion-fast-effects
62
+
63
+ group-hover:border-md-sys-color-on-surface
64
+ group-focus-within:border-2 group-focus-within:border-md-sys-color-primary
65
+ `,
66
+ legend: `
67
+ invisible float-none block h-auto max-w-[0.01px] overflow-hidden
68
+ whitespace-nowrap md-sys-typescale-body-small
69
+ transition-[max-width] md-sys-motion-fast-spatial
70
+
71
+ group-focus-within:max-w-full
72
+ group-has-[textarea:not(:placeholder-shown)]:max-w-full
73
+ `,
74
+ legendLabel: `
75
+ px-spacing-50
76
+ `
77
+ },
78
+ variants: {
79
+ variant: {
80
+ filled: {
81
+ base: `
82
+ px-spacing-0 bg-md-sys-color-surface-container-highest
83
+ rounded-t-xs state-layer before:rounded-xs hover:before:bg-md-sys-color-on-surface/8
84
+ after:absolute after:bottom-spacing-0 after:left-spacing-0 after:right-spacing-0 after:h-px after:bg-md-sys-color-on-surface-variant
85
+ after:transition-[height,background-color] after:md-sys-motion-fast-spatial
86
+ hover:after:bg-md-sys-color-on-surface
87
+ focus-within:after:bg-md-sys-color-primary
88
+ focus-within:after:h-[2px]
89
+ `,
90
+ /* 24dp above the first line leaves room for the label floated inside the container;
91
+ 24 + 24 + 8 = the 56dp single-line field. The resting label and the icons sit on that
92
+ first line too, so the icons stay beside the text once the label floats to 8dp. */
93
+ inputWrapper: 'pt-spacing-300 pb-spacing-100',
94
+ leadingIcon: 'mt-spacing-300',
95
+ trailingIcon: 'mt-spacing-300',
96
+ label: `
97
+ top-spacing-300
98
+ peer-focus:top-spacing-100 peer-focus:md-sys-typescale-body-small
99
+ peer-not-placeholder-shown:top-spacing-100 peer-not-placeholder-shown:md-sys-typescale-body-small
100
+ `
101
+ },
102
+ outlined: {
103
+ inputWrapper: 'py-spacing-200',
104
+ label: `
105
+ peer-focus:top-spacing-0 peer-focus:md-sys-typescale-body-small peer-focus:-translate-y-1/2
106
+ peer-not-placeholder-shown:top-spacing-0 peer-not-placeholder-shown:md-sys-typescale-body-small peer-not-placeholder-shown:-translate-y-1/2
107
+ `
108
+ }
109
+ },
110
+ error: {
111
+ true: {
112
+ base: 'after:bg-md-sys-color-error focus-within:after:bg-md-sys-color-error',
113
+ label: 'text-md-sys-color-error peer-focus:text-md-sys-color-error',
114
+ supportingText: 'text-md-sys-color-error',
115
+ leadingIcon: 'text-md-sys-color-error',
116
+ trailingIcon: 'text-md-sys-color-error',
117
+ fieldset: `
118
+ border-md-sys-color-error
119
+ group-hover:border-md-sys-color-error
120
+ group-focus-within:border-md-sys-color-error
121
+ `
122
+ }
123
+ },
124
+ leadingIcon: {
125
+ true: {}
126
+ },
127
+ disabled: {
128
+ true: {
129
+ base: 'cursor-not-allowed opacity-60',
130
+ inputWrapper: 'cursor-not-allowed',
131
+ fieldset: 'border-md-sys-color-on-surface/12 group-hover:border-md-sys-color-on-surface/12'
132
+ }
133
+ }
134
+ },
135
+ compoundVariants: [
136
+ {
137
+ /* Same as Textfield: the outlined label floats back over the leading icon into the notch. */
138
+ variant: 'outlined',
139
+ leadingIcon: true,
140
+ class: {
141
+ label: 'peer-focus:-left-spacing-250 peer-not-placeholder-shown:-left-spacing-250'
142
+ }
143
+ },
144
+ {
145
+ variant: 'filled',
146
+ disabled: true,
147
+ class: {
148
+ base: 'bg-md-sys-color-on-surface/4 after:bg-md-sys-color-on-surface/12'
149
+ }
150
+ }
151
+ ],
152
+ defaultVariants: {
153
+ variant: 'outlined'
154
+ }
155
+ });
@@ -0,0 +1,59 @@
1
+ import type { IconProps } from '../../../utils/index.js';
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLTextareaAttributes } from 'svelte/elements';
4
+ import type { TextareaVariants } from './theme.js';
5
+ /**
6
+ * Props for the Textarea component.
7
+ */
8
+ export type TextareaProps = TextareaVariants & Omit<HTMLTextareaAttributes, 'children' | 'value' | 'rows'> & {
9
+ /**
10
+ * The current value of the textarea.
11
+ */
12
+ value?: string | null;
13
+ /**
14
+ * The label text for the textarea.
15
+ */
16
+ label: string;
17
+ /**
18
+ * The ID for the textarea element. Auto-generated but can be replaced.
19
+ */
20
+ id?: string;
21
+ /**
22
+ * The placeholder text. Not used in M3: the label takes its place.
23
+ */
24
+ placeholder?: '';
25
+ /**
26
+ * Minimum height, in lines. The field grows with its content from here. Defaults to 3.
27
+ */
28
+ rows?: number;
29
+ /**
30
+ * Maximum height, in lines, before the content scrolls. Omit to grow without limit; set it
31
+ * to `rows` for a fixed-height field.
32
+ */
33
+ maxRows?: number;
34
+ /**
35
+ * Snippet for supporting text (helper or error text) displayed below the field.
36
+ */
37
+ supportingText?: Snippet;
38
+ /**
39
+ * Props for the leading icon, aligned with the first line.
40
+ */
41
+ leadingIconProps?: IconProps;
42
+ /**
43
+ * Props for the trailing icon button, aligned with the first line.
44
+ */
45
+ trailingIconProps?: IconProps;
46
+ /**
47
+ * Shows a character counter below the field. Going over it shows the error state; it does
48
+ * not stop typing (pass `maxlength` for a hard limit).
49
+ */
50
+ characterLimit?: number;
51
+ /**
52
+ * Callback function when the trailing icon is clicked.
53
+ */
54
+ trailingOnClick?: () => void;
55
+ /**
56
+ * Optional snippet for trailing icon override.
57
+ */
58
+ trailingIcon?: Snippet;
59
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -30,14 +30,14 @@ export const textfield = tv({
30
30
  transition-colors md-sys-motion-effects
31
31
  `,
32
32
  leadingIcon: `
33
- text-md-sys-color-on-surface-variant size-spacing-300
33
+ text-md-sys-color-on-surface-variant size-(--text-icon-24)
34
34
  group-focus-within:text-md-sys-color-primary
35
- ml-spacing-150 text-[24px]
35
+ ml-spacing-150 text-icon-24
36
36
  `,
37
37
  trailingIcon: `
38
- mr-spacing-150 text-md-sys-color-on-surface-variant size-spacing-300
38
+ mr-spacing-150 text-md-sys-color-on-surface-variant size-(--text-icon-24)
39
39
  group-focus-within:text-md-sys-color-primary
40
- z-20 text-[24px]
40
+ z-20 text-icon-24
41
41
  `,
42
42
  supportingText: `
43
43
  px-spacing-200 pt-spacing-50 flex justify-between
@@ -14,7 +14,7 @@ export const toggleGroup = tv({
14
14
  export const toggleGroupItem = tv({
15
15
  slots: {
16
16
  base: 'layer-container state-layer relative inline-flex min-w-spacing-600 flex-1 items-center justify-center gap-spacing-100 px-spacing-200 md-sys-typescale-label-large text-md-sys-color-on-surface outline-none transition-colors md-sys-motion-fast-effects disabled:cursor-not-allowed disabled:opacity-38 [&:not(:last-child)]:border-r [&:not(:last-child)]:border-md-sys-color-outline data-[state=on]:bg-md-sys-color-secondary-container data-[state=on]:text-md-sys-color-on-secondary-container',
17
- checkIcon: 'size-[18px] text-[18px]',
18
- icon: 'size-[18px] text-[18px]'
17
+ checkIcon: 'size-(--text-icon-18) text-icon-18',
18
+ icon: 'size-(--text-icon-18) text-icon-18'
19
19
  }
20
20
  });
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { RadioGroup } from '../forms/radio-group/index.js';
3
- import { themeState, extractColorFromImage } from '../../utils/theme.svelte.js';
3
+ import { themeState, extractColorFromImage } from '../../utils/themeState.svelte.js';
4
4
  import { Title } from '../typography/title/index.js';
5
5
  import { Body } from '../typography/body/index.js';
6
6
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Container-tier M3 color roles (see `styles/theme/*.css`) used as a generated avatar's
3
3
  * background. Deliberately NOT a fixed hex list: every consuming app picks its own source
4
- * color (`ThemeConfig.sourceColor` in `theme.svelte.ts`), which the M3 dynamic color
4
+ * color (`ThemeConfig.sourceColor` in `themeState.svelte.ts`), which the M3 dynamic color
5
5
  * algorithm expands into these tokens as real `--color-md-sys-color-*` custom properties on
6
6
  * `:root` — reading them live is what makes the avatar match that app's actual palette
7
7
  * instead of this library's own hardcoded pastel.
@@ -126,7 +126,7 @@ export const appbar = tv({
126
126
  row: 'grid w-full items-center px-spacing-50',
127
127
  childrenRow: 'w-full px-spacing-100 pb-spacing-100',
128
128
  ghost: 'w-full shrink-0 pointer-events-none',
129
- textContainer: 'flex min-w-spacing-0 flex-col gap-spacing-25 [--lead:0.25rem] [--trail:0.25rem]',
129
+ textContainer: 'flex min-w-spacing-0 flex-col gap-spacing-25 [--lead:var(--spacing-spacing-50)] [--trail:var(--spacing-spacing-50)]',
130
130
  title: 'text-md-sys-color-on-surface',
131
131
  subtitle: 'text-md-sys-color-on-surface-variant',
132
132
  leading: 'text-md-sys-color-on-surface col-start-1 row-start-1 flex shrink-0 items-center justify-self-start',
@@ -163,7 +163,7 @@ export const appbar = tv({
163
163
  searchContainer: {
164
164
  true: {
165
165
  row: 'grid-cols-[auto_1fr_auto]',
166
- textContainer: '[--lead:0.5rem] [--trail:0.5rem]'
166
+ textContainer: '[--lead:var(--spacing-spacing-100)] [--trail:var(--spacing-spacing-100)]'
167
167
  },
168
168
  false: ''
169
169
  },
@@ -173,10 +173,26 @@ export const appbar = tv({
173
173
  },
174
174
  compoundVariants: [
175
175
  // A title with no button beside it sits at the 16dp inset.
176
- { align: 'start', noLeading: true, class: { textContainer: '[--lead:1rem]' } },
177
- { align: 'start', noTrailing: true, class: { textContainer: '[--trail:1rem]' } },
178
- { searchContainer: true, noLeading: true, class: { textContainer: '[--lead:0.75rem]' } },
179
- { searchContainer: true, noTrailing: true, class: { textContainer: '[--trail:0.75rem]' } }
176
+ {
177
+ align: 'start',
178
+ noLeading: true,
179
+ class: { textContainer: '[--lead:var(--spacing-spacing-200)]' }
180
+ },
181
+ {
182
+ align: 'start',
183
+ noTrailing: true,
184
+ class: { textContainer: '[--trail:var(--spacing-spacing-200)]' }
185
+ },
186
+ {
187
+ searchContainer: true,
188
+ noLeading: true,
189
+ class: { textContainer: '[--lead:var(--spacing-spacing-150)]' }
190
+ },
191
+ {
192
+ searchContainer: true,
193
+ noTrailing: true,
194
+ class: { textContainer: '[--trail:var(--spacing-spacing-150)]' }
195
+ }
180
196
  ],
181
197
  defaultVariants: {
182
198
  align: 'start',
@@ -12,7 +12,7 @@ export const navitem = tv({
12
12
  base: 'group relative flex flex-1 flex-col items-center justify-center min-w-spacing-0 max-w-[168px] h-full transition-colors md-sys-motion-fast-effects',
13
13
  content: 'flex flex-col items-center justify-center gap-spacing-50 w-full',
14
14
  iconContainer: 'relative flex items-center justify-center h-spacing-400 w-spacing-800 rounded-full transition-colors md-sys-motion-effects',
15
- icon: 'text-[24px] size-spacing-300',
15
+ icon: 'text-icon-24 size-(--text-icon-24)',
16
16
  label: 'md-sys-typescale-label-medium truncate w-full text-center'
17
17
  },
18
18
  variants: {
@@ -19,7 +19,7 @@ export const tab = tv({
19
19
  'data-[state=inactive]:text-md-sys-color-on-surface-variant'
20
20
  ].join(' '),
21
21
  label: 'md-sys-typescale-title-small',
22
- icon: 'size-spacing-300 text-[24px]'
22
+ icon: 'size-(--text-icon-24) text-icon-24'
23
23
  },
24
24
  variants: {
25
25
  variant: {
@@ -14,12 +14,14 @@ travels around the circle.
14
14
  import { animate, type AnimationPlaybackControls } from 'motion';
15
15
  import { springTokens, springTransition } from '../../animation/spring.js';
16
16
  import { SpringValue } from '../../animation/springValue.svelte.js';
17
+ import type { ProgressA11yProps } from './types.js';
17
18
 
18
19
  let {
19
20
  percent,
20
21
  size = 48,
21
- thickness = 4
22
- }: {
22
+ thickness = 4,
23
+ ...a11y
24
+ }: ProgressA11yProps & {
23
25
  /** The current progress percentage (0–100). Omit or pass null for indeterminate. */
24
26
  percent?: number | null;
25
27
  /** Diameter of the indicator in pixels. Defaults to 48. */
@@ -93,7 +95,7 @@ travels around the circle.
93
95
  );
94
96
  </script>
95
97
 
96
- <Progress.Root value={percent ?? null} max={100} data-cy="m3-circular-progress">
98
+ <Progress.Root {...a11y} value={percent ?? null} max={100} data-cy="m3-circular-progress">
97
99
  {#snippet child({ props })}
98
100
  <svg
99
101
  {...props}
@@ -1,4 +1,5 @@
1
- type $$ComponentProps = {
1
+ import type { ProgressA11yProps } from './types.js';
2
+ type $$ComponentProps = ProgressA11yProps & {
2
3
  /** The current progress percentage (0–100). Omit or pass null for indeterminate. */
3
4
  percent?: number | null;
4
5
  /** Diameter of the indicator in pixels. Defaults to 48. */
@@ -16,12 +16,14 @@ The track always keeps a gap either side of the bar.
16
16
  import { animate, type AnimationPlaybackControls } from 'motion';
17
17
  import { springTokens, springTransition } from '../../animation/spring.js';
18
18
  import { SpringValue } from '../../animation/springValue.svelte.js';
19
+ import type { ProgressA11yProps } from './types.js';
19
20
 
20
21
  let {
21
22
  percent,
22
23
  height = 4,
23
- class: className
24
- }: {
24
+ class: className,
25
+ ...a11y
26
+ }: ProgressA11yProps & {
25
27
  /** The current progress percentage (0–100). Omit or pass null for indeterminate. */
26
28
  percent?: number | null;
27
29
  /** Height of the bar in pixels. Defaults to 4. */
@@ -84,6 +86,7 @@ The track always keeps a gap either side of the bar.
84
86
  </script>
85
87
 
86
88
  <Progress.Root
89
+ {...a11y}
87
90
  value={percent ?? null}
88
91
  max={100}
89
92
  class={container({ class: clsx(className) })}
@@ -1,4 +1,5 @@
1
- type $$ComponentProps = {
1
+ import type { ProgressA11yProps } from './types.js';
2
+ type $$ComponentProps = ProgressA11yProps & {
2
3
  /** The current progress percentage (0–100). Omit or pass null for indeterminate. */
3
4
  percent?: number | null;
4
5
  /** Height of the bar in pixels. Defaults to 4. */
@@ -13,14 +13,16 @@ effects spring (critically damped, so progress never visibly runs backwards).
13
13
  import { springTokens } from '../../animation/spring.js';
14
14
  import { SpringValue } from '../../animation/springValue.svelte.js';
15
15
  import { linear, trackOpacity, WAVE_PERIOD_MS } from './_wavy.js';
16
+ import type { ProgressA11yProps } from './types.js';
16
17
 
17
18
  let {
18
19
  width = 600,
19
20
  height = 10,
20
21
  thickness = 4,
21
22
  percent,
22
- class: className
23
- }: {
23
+ class: className,
24
+ ...a11y
25
+ }: ProgressA11yProps & {
24
26
  /** Width of the SVG viewBox. */
25
27
  width?: number;
26
28
  /** Height of the SVG viewBox. */
@@ -56,7 +58,7 @@ effects spring (critically damped, so progress never visibly runs backwards).
56
58
  let wavePath = $derived(linear(height / 2 - thickness / 2, height / 2, left, percentX, time));
57
59
  </script>
58
60
 
59
- <Progress.Root value={percent ?? null} max={100}>
61
+ <Progress.Root {...a11y} value={percent ?? null} max={100}>
60
62
  {#snippet child({ props })}
61
63
  <svg {...props} viewBox="0 0 {width} {height}" class={className}>
62
64
  <path
@@ -1,4 +1,5 @@
1
- type $$ComponentProps = {
1
+ import type { ProgressA11yProps } from './types.js';
2
+ type $$ComponentProps = ProgressA11yProps & {
2
3
  /** Width of the SVG viewBox. */
3
4
  width?: number;
4
5
  /** Height of the SVG viewBox. */
@@ -1,4 +1,5 @@
1
1
  export * from './_wavy.js';
2
+ export * from './types.js';
2
3
  export { default as CircularProgress } from './CircularProgress.svelte';
3
4
  export { default as LinearProgress } from './LinearProgress.svelte';
4
5
  export { default as WavyLinearProgress } from './WavyLinearProgress.svelte';
@@ -1,6 +1,7 @@
1
1
  // THIS FILE IS AUTO-GENERATED BY scripts/generate-components-index.ts - DO NOT EDIT MANUALLY
2
2
  // re-export TS/JS modules from this folder
3
3
  export * from './_wavy.js';
4
+ export * from './types.js';
4
5
  // default exports for components in this folder
5
6
  export { default as CircularProgress } from './CircularProgress.svelte';
6
7
  export { default as LinearProgress } from './LinearProgress.svelte';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Accessible-name attributes shared by every progress indicator, forwarded to the element with
3
+ * `role="progressbar"`. Give each indicator a name when more than one is on screen, or when the
4
+ * visible label is not already associated with it.
5
+ */
6
+ export type ProgressA11yProps = {
7
+ id?: string;
8
+ /** Accessible name, e.g. `"Reading comprehension"`. */
9
+ 'aria-label'?: string;
10
+ /** Id of the element whose text names the indicator. */
11
+ 'aria-labelledby'?: string;
12
+ /** Id of the element that describes the indicator. */
13
+ 'aria-describedby'?: string;
14
+ /** Human-readable value, e.g. `"3 of 5 lessons"`. Defaults to the percentage. */
15
+ 'aria-valuetext'?: string;
16
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -5,7 +5,7 @@ export const snackbar = tv({
5
5
  label: 'text-md-sys-color-inverse-primary md-sys-typescale-label-large px-spacing-150 cursor-pointer ',
6
6
  actionWrapper: 'flex items-center z-40',
7
7
  supportingText: 'text-md-sys-color-inverse-on-surface md-sys-typescale-body-medium max-w-[60ch] ',
8
- icon: 'size-spacing-300 text-[24px] text-md-sys-color-inverse-on-surface mr-spacing-50 ml-spacing-150'
8
+ icon: 'size-(--text-icon-24) text-icon-24 text-md-sys-color-inverse-on-surface mr-spacing-50 ml-spacing-150'
9
9
  },
10
10
  variants: {
11
11
  fixed: {
@@ -36,7 +36,7 @@ and `sortDirection` props. Defaults to `scope="col"`.
36
36
  ].join(' ')}
37
37
  aria-hidden="true"
38
38
  >
39
- <Icon name="arrow_upward" class="size-[18px] text-[18px]" />
39
+ <Icon name="arrow_upward" class="text-icon-18 size-(--text-icon-18)" />
40
40
  </span>
41
41
  {/if}
42
42
  </span>
@@ -52,7 +52,7 @@ export const toolbar = tv({
52
52
  export const toolbarButton = tv({
53
53
  slots: {
54
54
  base: 'layer-container state-layer before:rounded-full relative inline-flex size-spacing-500 items-center justify-center rounded-full outline-none transition-colors md-sys-motion-fast-effects disabled:cursor-not-allowed disabled:opacity-38',
55
- icon: 'size-spacing-250 text-[20px]'
55
+ icon: 'size-(--text-icon-20) text-icon-20'
56
56
  },
57
57
  variants: {
58
58
  color: {
@@ -65,7 +65,7 @@ export const toolbarButton = tv({
65
65
  export const toolbarGroupItem = tv({
66
66
  slots: {
67
67
  base: 'layer-container state-layer before:rounded-full relative inline-flex size-spacing-500 items-center justify-center rounded-full outline-none transition-colors md-sys-motion-fast-effects disabled:cursor-not-allowed disabled:opacity-38',
68
- icon: 'size-spacing-250 text-[20px]'
68
+ icon: 'size-(--text-icon-20) text-icon-20'
69
69
  },
70
70
  variants: {
71
71
  color: {