@fest-lib/veela 0.1.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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +533 -0
  3. package/dist/veela.js +878 -0
  4. package/package.json +83 -0
  5. package/src/scss/_layers.scss +16 -0
  6. package/src/scss/advanced/_index.scss +0 -0
  7. package/src/scss/advanced/animation/_motion.scss +317 -0
  8. package/src/scss/advanced/color/_color.scss +328 -0
  9. package/src/scss/advanced/color/_colorize.scss +325 -0
  10. package/src/scss/advanced/design/_design-tokens.scss +118 -0
  11. package/src/scss/advanced/design/_effects.scss +275 -0
  12. package/src/scss/advanced/design/_shadow.scss +359 -0
  13. package/src/scss/advanced/design/_surfaces.scss +76 -0
  14. package/src/scss/advanced/effects/_animations.scss +124 -0
  15. package/src/scss/advanced/effects/_shadows.scss +50 -0
  16. package/src/scss/advanced/font/_typography.scss +600 -0
  17. package/src/scss/advanced/index.scss +11 -0
  18. package/src/scss/advanced/index.ts +35 -0
  19. package/src/scss/advanced/layout/_content.scss +170 -0
  20. package/src/scss/advanced/layout/_index.scss +5 -0
  21. package/src/scss/advanced/layout/_normalize.scss +541 -0
  22. package/src/scss/advanced/layout/_shared-overlays.scss +162 -0
  23. package/src/scss/advanced/md3/_md3.scss +596 -0
  24. package/src/scss/advanced/md3/_utils.scss +114 -0
  25. package/src/scss/advanced/misc/_config.scss +119 -0
  26. package/src/scss/advanced/misc/_initials.scss +298 -0
  27. package/src/scss/advanced/misc/_mixins.scss +179 -0
  28. package/src/scss/advanced/misc/_queries.scss +34 -0
  29. package/src/scss/advanced/misc/_rendering.scss +82 -0
  30. package/src/scss/advanced/misc/_tokens.scss +74 -0
  31. package/src/scss/advanced/theme/_shared.scss +232 -0
  32. package/src/scss/advanced/theme/_states.scss +332 -0
  33. package/src/scss/advanced/theme/_variants.scss +354 -0
  34. package/src/scss/advanced/tokens/_material-color.scss +120 -0
  35. package/src/scss/advanced/tokens/_variables.scss +171 -0
  36. package/src/scss/basic/_layers.scss +0 -0
  37. package/src/scss/basic/design/_index.scss +3 -0
  38. package/src/scss/basic/design/_keyframes.scss +163 -0
  39. package/src/scss/basic/design/_shapes.scss +266 -0
  40. package/src/scss/basic/design/_wavy-runtime.scss +50 -0
  41. package/src/scss/basic/index.scss +19 -0
  42. package/src/scss/basic/index.ts +29 -0
  43. package/src/scss/basic/misc/_core-layout.scss +272 -0
  44. package/src/scss/basic/misc/_index.scss +18 -0
  45. package/src/scss/basic/misc/_layout.scss +1040 -0
  46. package/src/scss/basic/misc/_mixins.scss +179 -0
  47. package/src/scss/basic/misc/_motion.scss +28 -0
  48. package/src/scss/basic/misc/_normalize.scss +765 -0
  49. package/src/scss/basic/misc/_queries.scss +34 -0
  50. package/src/scss/basic/misc/_shared.scss +232 -0
  51. package/src/scss/basic/misc/_states.scss +135 -0
  52. package/src/scss/basic/misc/_tokens.scss +78 -0
  53. package/src/scss/basic/misc/_veela.scss +12 -0
  54. package/src/scss/core/index.scss +1 -0
  55. package/src/scss/core/interact/_draggable.scss +32 -0
  56. package/src/scss/core/interact/_position.scss +45 -0
  57. package/src/scss/core/interact/_ps-anchor.scss +28 -0
  58. package/src/scss/core/interact/_ps-centered.scss +28 -0
  59. package/src/scss/core/interact/_ps-cursor.scss +18 -0
  60. package/src/scss/core/interact/_ps-draggable.scss +25 -0
  61. package/src/scss/core/interact/_ps-mechanic.scss +0 -0
  62. package/src/scss/core/interact/_ps-properties.scss +54 -0
  63. package/src/scss/core/interact/_ps-resizable.scss +61 -0
  64. package/src/scss/core/interact/_resizable.scss +69 -0
  65. package/src/scss/core/interact/_viewport.scss +469 -0
  66. package/src/scss/core/misc/_color-properties.scss +64 -0
  67. package/src/scss/core/misc/_config.scss +110 -0
  68. package/src/scss/core/misc/_functions.scss +530 -0
  69. package/src/scss/core/misc/_icons.scss +109 -0
  70. package/src/scss/core/misc/_index.scss +6 -0
  71. package/src/scss/core/misc/_layout.scss +49 -0
  72. package/src/scss/core/misc/_mixins.scss +744 -0
  73. package/src/scss/core/misc/_properties.scss +245 -0
  74. package/src/scss/core/misc/_tokens.scss +947 -0
  75. package/src/scss/core/misc/_utilities.scss +941 -0
  76. package/src/scss/core/misc/_utils.scss +17 -0
  77. package/src/scss/index.scss +18 -0
  78. package/src/scss/index.ts +105 -0
@@ -0,0 +1,119 @@
1
+ @use "sass:map";
2
+ @use "sass:list";
3
+
4
+ $md-config: (
5
+ "effects": (
6
+ "active-brightness": 0.85,
7
+ "hover-brightness": 1.2,
8
+ "disabled-opacity": 0.5
9
+ ),
10
+ "shape": (
11
+ "border-radius": 0.75rem,
12
+ "box-shadow": 0 4px 6px -1px rgb(0 0 0 / 0.1),
13
+ "box-shadow-hover": 0 10px 15px -3px rgb(0 0 0 / 0.1)
14
+ ),
15
+ "colors": (
16
+ "accent": (#118bee15, #0097fc4f),
17
+ "bg": (#ffffff, #0d1117),
18
+ "bg-secondary": (#f6f8fa, #151b23),
19
+ "link": (#0969da, #2f81f7),
20
+ "secondary": (#6e7781, #8b949e),
21
+ "secondary-accent": (#eff1f3, #1f2428),
22
+ "shadow": (#d1d9e0, #30363d),
23
+ "table": (#f6f8fa, #161b22),
24
+ "text": (#1f2328, #e6edf3),
25
+ "text-secondary": (#656d76, #7d8590),
26
+ "scrollbar": (#d0d7de, #484f58),
27
+ "border": (#d0d7de, #30363d)
28
+ ),
29
+ "font": (
30
+ "emoji": "\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"",
31
+ "body": "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif, var(--font-family-emoji-flag-capable)",
32
+ "mono": "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
33
+ "size-base": 1rem
34
+ ),
35
+ "layout": (
36
+ "line-height": 1.5,
37
+ "justify-important": center,
38
+ "justify-normal": start,
39
+ "widths": (
40
+ "card": 320px,
41
+ "card-medium": 480px,
42
+ "card-wide": 768px,
43
+ "content": 1200px
44
+ )
45
+ ),
46
+ "z-index": (
47
+ "negative": -1,
48
+ "base": 0,
49
+ "dropdown": 1000,
50
+ "sticky": 1020,
51
+ "fixed": 1030,
52
+ "modal-backdrop": 1040,
53
+ "modal": 1050,
54
+ "popover": 1060,
55
+ "tooltip": 1070
56
+ ),
57
+ "page": (
58
+ "margin": 1rem
59
+ ),
60
+ "heading": (
61
+ "padding": 0.5em,
62
+ "padding-small": 0.25em
63
+ ),
64
+ "blockquote": (
65
+ "margin-inline": 1.5em,
66
+ "padding-inline": 1em
67
+ ),
68
+ "table": (
69
+ "cell-padding": 0.5rem 1rem
70
+ ),
71
+ "media": (
72
+ "img-max-width": 100%
73
+ ),
74
+ "scrollbar": (
75
+ "size": 6px
76
+ )
77
+ );
78
+
79
+ @function md-config($keys...) {
80
+ $value: $md-config;
81
+
82
+ @each $key in $keys {
83
+ @if $value == null {
84
+ @return null;
85
+ }
86
+ $value: map.get($value, $key);
87
+ }
88
+
89
+ @return $value;
90
+ }
91
+
92
+ @function md-color($name, $mode: null) {
93
+ $palette: md-config("colors");
94
+ $value: map.get($palette, $name);
95
+
96
+ @if $value == null {
97
+ @return null;
98
+ }
99
+
100
+ @if $mode == "light" {
101
+ @return list.nth($value, 1);
102
+ }
103
+
104
+ @if $mode == "dark" {
105
+ @return list.nth($value, 2);
106
+ }
107
+
108
+ @return $value;
109
+ }
110
+
111
+ @function md-light-dark($name) {
112
+ $value: md-color($name);
113
+
114
+ @if $value == null {
115
+ @return null;
116
+ }
117
+
118
+ @return light-dark(#{list.nth($value, 1)}, #{list.nth($value, 2)});
119
+ }
@@ -0,0 +1,298 @@
1
+ @use "../core/color" as color;
2
+ @use "../core/colorize" as colorize;
3
+
4
+ @mixin structural-shell(
5
+ $prefix,
6
+ $gap: null,
7
+ $padding: null,
8
+ $radius: var(--radius-md),
9
+ $border-width: 1px,
10
+ $border-style: solid,
11
+ $border-color: transparent
12
+ ) {
13
+ @if $gap != null {
14
+ --#{$prefix}-gap: #{$gap};
15
+ }
16
+
17
+ @if $padding != null {
18
+ --#{$prefix}-padding: #{$padding};
19
+ }
20
+
21
+ --#{$prefix}-radius: #{$radius};
22
+ --#{$prefix}-border: #{$border-width} #{$border-style};
23
+ --#{$prefix}-border-color: #{$border-color};
24
+ --#{$prefix}-border-width: #{$border-width};
25
+ --#{$prefix}-border-style: #{$border-style};
26
+ --#{$prefix}-border-radius: #{$radius};
27
+ --#{$prefix}-border-radius-top-left: #{$radius};
28
+ --#{$prefix}-border-radius-top-right: #{$radius};
29
+ --#{$prefix}-border-radius-bottom-left: #{$radius};
30
+ --#{$prefix}-border-radius-bottom-right: #{$radius};
31
+ }
32
+
33
+ @mixin initial-component-tokens() {
34
+ // Component defaults
35
+ --card-padding: var(--padding-lg);
36
+ --card-gap: var(--gap-md);
37
+ --card-radius: #{md3-radius(lg)};
38
+ --card-avatar-size: var(--avatar-size);
39
+
40
+ --form-radius: #{md3-radius(md)};
41
+ --form-padding: var(--padding-md);
42
+ --form-gap: var(--gap-sm);
43
+
44
+ --button-radius: #{md3-radius(full)};
45
+ --button-padding-x: var(--padding-lg);
46
+ --button-padding-y: var(--padding-sm);
47
+
48
+ --nav-gap: var(--gap-sm);
49
+ --nav-padding: var(--padding-sm);
50
+ --nav-radius: #{md3-radius(sm)};
51
+
52
+ // -------------------------------------------------------------------------
53
+ // Component tokens
54
+ // -------------------------------------------------------------------------
55
+ --avatar-size: clamp(32px, 6cqi, 48px);
56
+ --avatar-size-lg: clamp(40px, 8cqi, 64px);
57
+
58
+ --icon-size-sm: clamp(0.9rem, 1.2cqi, 1.1rem);
59
+ --icon-size-md: clamp(1.1rem, 1.4cqi, 1.3rem);
60
+ --icon-size-lg: clamp(1.4rem, 1.8cqi, 1.7rem);
61
+ --icon-color: currentColor;
62
+
63
+ --card-avatar-size: var(--avatar-size);
64
+
65
+ --button-radius: var(--radius-full);
66
+ --button-padding-x: var(--padding-lg);
67
+ --button-padding-y: var(--padding-sm);
68
+
69
+ --nav-gap: var(--gap-md);
70
+ --nav-padding: var(--padding-md);
71
+ --nav-radius: var(--radius-md);
72
+ }
73
+
74
+ @mixin initial-input-properties() {
75
+ @include colorize.solid-colorize("&", ("shade": 0.05, "tint": 0.0, "scope": "selector", "global-targets": true));
76
+
77
+ // -------------------------------------------------------------------------
78
+ // Form controls · inputs
79
+ // -------------------------------------------------------------------------
80
+ --input-radius: var(--radius-full);
81
+ --input-gap: var(--gap-sm);
82
+
83
+ --input-padding: var(--padding-md);
84
+ --input-padding-block: var(--padding-sm);
85
+ --input-padding-inline: var(--padding-lg, 1rem);
86
+ --input-padding-inline-start: var(--padding-lg, 1rem);
87
+ --input-padding-inline-end: var(--padding-lg, 1rem);
88
+
89
+ --input-text-color: var(--on-surface-color, currentColor);
90
+ --input-placeholder-color: color-mix(in oklch, var(--input-text-color) 32%, transparent);
91
+ --input-helper-color: color-mix(in oklch, var(--input-text-color) 68%, transparent);
92
+
93
+ --input-border-width: 1px;
94
+ --input-border-color: color-mix(in oklch, var(--on-surface-color, currentColor) 20%, transparent);
95
+ --input-border-hover: color-mix(in oklch, var(--on-surface-color, currentColor) 30%, transparent);
96
+ --input-border-focus: color-mix(
97
+ in oklch,
98
+ var(--input-border-hover) 40%,
99
+ color-mix(in oklch, var(--current, currentColor) 30%, transparent)
100
+ );
101
+ --input-border-error: var(--error, currentColor);
102
+ --input-border-disabled: color-mix(in oklch, var(--input-border-color) 35%, transparent);
103
+ --input-border-readonly: color-mix(in oklch, var(--input-border-color) 55%, transparent);
104
+ --input-border-checked: color-mix(in oklch, var(--surface-color, currentColor) 80%, transparent);
105
+ --input-border-autofill: color-mix(in oklch, var(--input-border-color) 80%, transparent);
106
+
107
+ --input-surface-color: var(--surface-color, transparent);//color-mix(in oklch, var(--surface-color, transparent) 96%, var(--on-surface-color, transparent));
108
+ --input-surface-hover: color-mix(in oklch, var(--input-surface-color) 90%, var(--input-border-focus) 10%);
109
+ --input-surface-focus: color-mix(in oklch, var(--input-surface-color) 88%, var(--input-border-focus) 12%);
110
+ --input-surface-error: color-mix(in oklch, var(--input-surface-color) 88%, var(--input-border-error) 12%);
111
+ --input-surface-disabled: color-mix(in oklch, var(--input-surface-color) 96%, transparent 4%);
112
+ --input-surface-readonly: color-mix(in oklch, var(--input-surface-color) 96%, transparent 4%);
113
+ --input-surface-autofill: color-mix(in oklch, var(--input-surface-color) 94%, transparent 6%);
114
+ --input-surface: var(--input-surface-color, var(--surface-color, currentColor));
115
+ --input-color: var(--input-surface-color, var(--surface-color, currentColor));
116
+
117
+ --input-shadow: 0 1px 2px color-mix(in oklch, var(--md-shadow, #000) 12%, transparent);
118
+ --input-shadow-hover: 0 1px 3px color-mix(in oklch, var(--md-shadow, #000) 18%, transparent);
119
+ --input-shadow-focus: 0 0 0 1px color-mix(in oklch, var(--input-border-focus) 32%, transparent),
120
+ 0 0 0 4px color-mix(in oklch, var(--input-border-focus) 12%, transparent);
121
+ --input-shadow-error: 0 0 0 1px color-mix(in oklch, var(--input-border-error) 32%, transparent),
122
+ 0 0 0 4px color-mix(in oklch, var(--input-border-error) 12%, transparent);
123
+
124
+ --input-focus-ring-offset: 2px;
125
+
126
+ --input-selection-color: var(--on-surface-color, currentColor);
127
+ --input-selection-on-color: var(--surface-color, currentColor);
128
+
129
+ --input-icon-color: color-mix(in oklch, var(--input-text-color) 82%, transparent);
130
+ --input-icon-size: var(--icon-size-md);
131
+
132
+ --input-helper-spacing: var(--space-xs, 0.5rem);
133
+ --input-label-color: color-mix(in oklch, var(--input-text-color) 92%, transparent);
134
+ --input-min-block-size: fit-content;
135
+ --input-min-inline-size: 0px;
136
+ --input-max-inline-size: 100%;
137
+ --input-inline-size: fit-content;
138
+ --input-line-height: 1.4;
139
+ --input-font-weight: inherit;
140
+ --input-letter-spacing: 0.01em;
141
+ --input-cursor: text;
142
+
143
+ --input-text-disabled: color-mix(in oklch, var(--input-text-color) 55%, transparent);
144
+ --input-text-readonly: color-mix(in oklch, var(--input-text-color) 70%, transparent);
145
+ --input-text-autofill: color-mix(in oklch, var(--input-text-color) 65%, transparent);
146
+ }
147
+
148
+ @mixin initial-option-properties() {
149
+ // -------------------------------------------------------------------------
150
+ // Form controls · options
151
+ // -------------------------------------------------------------------------
152
+ --option-border-inline-size: 1px;
153
+ --option-padding-block: var(--padding-sm);
154
+ --option-padding-inline: calc(var(--padding-lg, 1rem) * 0.75);
155
+
156
+ --option-border-color: color-mix(in oklch, var(--input-border-color) 70%, transparent);
157
+ --option-border-hover: color-mix(in oklch, var(--option-border-color) 70%, var(--input-border-focus) 30%);
158
+ --option-border-focus: var(--input-border-focus);
159
+ --option-border-checked: var(--input-border-focus);
160
+
161
+ --option-text-color: var(--input-text-color, var(--on-surface-color, currentColor));
162
+ --option-text-hover: var(--option-text-color);
163
+ --option-text-active: var(--option-text-color);
164
+ --option-text-checked: var(--input-selection-on-color, var(--surface-color, currentColor));
165
+ --option-text-focus: var(--input-border-focus);
166
+
167
+ --option-surface-color: var(--input-surface-color, var(--surface-color, currentColor));
168
+ --option-surface-hover: color-mix(in oklch, var(--option-surface-color) 88%, var(--on-surface-color, currentColor) 12%);
169
+ --option-surface-active: color-mix(in oklch, var(--option-surface-color) 84%, var(--on-surface-color, currentColor) 16%);
170
+ --option-surface-checked: color-mix(in oklch, var(--option-surface-color) 10%, var(--on-surface-color, currentColor) 90%);
171
+
172
+ --option-outline-width: 2px;
173
+ --option-outline-offset: -2px;
174
+ --option-outline-color: color-mix(in oklch, var(--on-surface-color, currentColor) 80%, transparent);
175
+
176
+ --option-color: var(--option-surface-color);
177
+ --option-hover-color: var(--option-surface-hover);
178
+ --option-active-color: var(--option-surface-active);
179
+ --option-checked-color: var(--option-surface-checked);
180
+ }
181
+
182
+ @mixin initial-select-properties() {
183
+ // -------------------------------------------------------------------------
184
+ // Form controls · selects
185
+ // -------------------------------------------------------------------------
186
+ --select-gap: var(--gap-sm);
187
+ --select-indicator-size: var(--icon-size-sm, 1.125rem);
188
+
189
+ --select-indicator-color: var(--input-text-color, var(--option-text-color, currentColor));
190
+ --select-text-color: var(--input-text-color, var(--option-text-color, currentColor));
191
+
192
+ --select-color: var(--input-surface-color, var(--option-color, currentColor));
193
+ --select-hover-color: var(--input-hover-color, var(--option-hover-color, currentColor));
194
+
195
+ --select-surface-color: var(--input-surface-color, var(--option-color, currentColor));
196
+ --select-surface-hover: var(--input-hover-color, var(--option-hover-color, currentColor));
197
+ }
198
+
199
+ @mixin initial-checkbox-properties() {
200
+ // -------------------------------------------------------------------------
201
+ // Form controls · checkboxes
202
+ // -------------------------------------------------------------------------
203
+ --checkbox-size: 1.25rem;
204
+ --checkbox-radius: var(--radius-sm);
205
+ --checkbox-border-width: 1px;
206
+
207
+ --checkbox-surface: var(--input-surface, color-mix(in oklch, var(--surface-color, currentColor) 96%, var(--on-surface-color, currentColor)));
208
+ --checkbox-surface-hover: color-mix(in oklch, var(--checkbox-surface) 88%, var(--on-surface-color, currentColor) 12%);
209
+ --checkbox-surface-checked: color-mix(in oklch, var(--checkbox-surface) 10%, var(--on-surface-color, currentColor) 12%);
210
+ --checkbox-surface-disabled: color-mix(in oklch, var(--checkbox-surface) 96%, transparent 4%);
211
+
212
+ --checkbox-border-color: var(--input-border-color);
213
+ --checkbox-border-hover: var(--input-border-hover);
214
+ --checkbox-border-focus: var(--input-border-focus);
215
+ --checkbox-border-checked: var(--input-border-focus);
216
+ --checkbox-border-disabled: var(--input-border-disabled);
217
+
218
+ --checkbox-shadow: var(--input-shadow);
219
+ --checkbox-shadow-hover: var(--input-shadow-hover);
220
+ --checkbox-shadow-focus: var(--input-shadow-focus);
221
+
222
+ --checkbox-icon-color: var(--input-icon-color);
223
+ --checkbox-icon-checked: var(--input-selection-on-color);
224
+ }
225
+
226
+ @mixin initial-form-controls() {
227
+ // -------------------------------------------------------------------------
228
+ // Form controls
229
+ // -------------------------------------------------------------------------
230
+ --form-radius: var(--radius-full);
231
+ --form-padding: var(--padding-md);
232
+ --form-gap: var(--gap-sm);
233
+
234
+ @include initial-input-properties();
235
+ @include initial-option-properties();
236
+ @include initial-select-properties();
237
+ @include initial-checkbox-properties();
238
+ }
239
+
240
+ @mixin initial-structural-elements() {
241
+ // -------------------------------------------------------------------------
242
+ // Surfaces & structural elements
243
+ // -------------------------------------------------------------------------
244
+ --accordion-radius: var(--radius-lg);
245
+ --accordion-open-color-shade: var(--surface-opacity-emphasis);
246
+ --accordion-open-border: 1px solid;
247
+ --accordion-transition: var(--transition-colors);
248
+
249
+ --empty-state-padding: var(--padding-2xl);
250
+ --empty-state-radius: var(--radius-lg);
251
+ --empty-state-border: 1px dashed color-mix(
252
+ in oklch,
253
+ var(
254
+ --c2-on-surface(
255
+ var(--scrollbar-tint),
256
+ var(--current, var(--color-on-surface, var(--md-on-surface, #1c1b1f)))
257
+ ),
258
+ #{color.md3-var(outline-variant)}
259
+ ) l c h / var(--border-opacity-dashed)
260
+ );
261
+ --empty-state-min-block-size: var(--space-2xl);
262
+
263
+ @include structural-shell(
264
+ "surface",
265
+ null,
266
+ null,
267
+ var(--radius-md),
268
+ 1px,
269
+ solid,
270
+ transparent
271
+ );
272
+
273
+ @include structural-shell(
274
+ "card",
275
+ var(--gap-md),
276
+ var(--padding-md),
277
+ var(--radius-md),
278
+ var(--surface-border-width, 1px),
279
+ var(--surface-border-style, solid),
280
+ var(--surface-border-color, transparent)
281
+ );
282
+
283
+ @include structural-shell(
284
+ "panel",
285
+ var(--gap-md),
286
+ var(--padding-md),
287
+ var(--radius-md),
288
+ var(--surface-border-width, 1px),
289
+ var(--surface-border-style, solid),
290
+ var(--surface-border-color, transparent)
291
+ );
292
+ }
293
+
294
+ @mixin initial-properties() {
295
+ @include initial-component-tokens();
296
+ @include initial-form-controls();
297
+ @include initial-structural-elements();
298
+ }
@@ -0,0 +1,179 @@
1
+ // Shared mixins to unify common property blocks
2
+ @use "sass:map";
3
+ @use "sass:meta";
4
+ @use "veela-lib" as *;
5
+ @use "./tokens" as t;
6
+
7
+ // Layout stacks
8
+ @mixin stack($gap, $display: grid) {
9
+ display: $display;
10
+ gap: $gap;
11
+ }
12
+
13
+ @mixin hstack($gap) { @include stack($gap, inline-flex); }
14
+ @mixin vstack($gap) { @include stack($gap, grid); }
15
+
16
+ // Container helpers
17
+ @mixin container-inline { container-type: inline-size; }
18
+ @mixin container-size { container-type: size; contain: content; }
19
+
20
+ // Typography helpers based on MD3 tokens
21
+ @mixin text-heading($token: "title-large", $align: null) {
22
+ @if meta.mixin-exists("md3-typography") {
23
+ @include md3-typography($token);
24
+ }
25
+ font-family: t.$font-family-base;
26
+ @if $align != null { text-align: $align; }
27
+
28
+ &:where(:-webkit-autofill, :autofill, :-webkit-autofill:hover, :-webkit-autofill:focus, :-webkit-autofill:active) {
29
+ font-family: t.$font-family-base;
30
+ }
31
+ }
32
+
33
+ @mixin text-body($token: "body-medium") {
34
+ @if meta.mixin-exists("md3-typography") {
35
+ @include md3-typography($token);
36
+ }
37
+ font-family: t.$font-family-base;
38
+
39
+ &:where(:-webkit-autofill, :autofill, :-webkit-autofill:hover, :-webkit-autofill:focus, :-webkit-autofill:active) {
40
+ font-family: t.$font-family-base;
41
+ }
42
+ }
43
+
44
+ @mixin text-label($token: "label-large", $uppercase: false) {
45
+ @if meta.mixin-exists("md3-typography") {
46
+ @include md3-typography($token);
47
+ }
48
+ font-family: t.$font-family-base;
49
+ @if $uppercase { text-transform: uppercase; }
50
+
51
+ &:where(:-webkit-autofill, :autofill, :-webkit-autofill:hover, :-webkit-autofill:focus, :-webkit-autofill:active) {
52
+ font-family: t.$font-family-base;
53
+ }
54
+ }
55
+
56
+ @mixin font-nums-tabular { font-variant-numeric: tabular-nums; }
57
+
58
+ // Tonal surfaces & elevation helpers
59
+ @mixin tonal-surface(
60
+ $role: surface,
61
+ $tone: var(--surface-opacity-default),
62
+ $radius: null,
63
+ $padding: null,
64
+ $elevation: null,
65
+ $border: false
66
+ ) {
67
+ @if meta.mixin-exists("solid-colorize") {
68
+ @include solid-colorize("&", ("shade": $tone, "role": $role, "scope": "selector"));
69
+ }
70
+
71
+ @if $radius != null { border-radius: $radius; }
72
+ @if $padding != null { padding: $padding; }
73
+ @if $elevation != null {
74
+ --md3-elevation-level: #{$elevation};
75
+ }
76
+ @if $border {
77
+ border: 0.5px solid color-mix(in oklch, var(--md3-outline) 42%, transparent);
78
+ }
79
+ }
80
+
81
+ @mixin interactive-surface(
82
+ $role: surface,
83
+ $tone: var(--surface-opacity-default),
84
+ $state: hover,
85
+ $selector: "&::after"
86
+ ) {
87
+ @include tonal-surface($role, $tone);
88
+ @if meta.mixin-exists("md3-state-layer") {
89
+ @include md3-state-layer($role, $state, $selector);
90
+ }
91
+ }
92
+
93
+ @mixin card-surface(
94
+ $role: surface-container,
95
+ $tone: var(--surface-opacity-subtle),
96
+ $radius: var(--radius-lg),
97
+ $padding: var(--padding-lg),
98
+ $elevation: 2
99
+ ) {
100
+ @include tonal-surface($role, $tone, $radius, $padding, $elevation, true);
101
+ backdrop-filter: blur(10px) saturate(115%);
102
+ }
103
+
104
+ // Structured blocks
105
+ @mixin section-stack($gap: var(--gap-sm)) {
106
+ display: grid;
107
+ gap: $gap;
108
+ inline-size: stretch;
109
+ min-inline-size: 0;
110
+ }
111
+
112
+ @mixin inline-toolbar($gap: var(--gap-sm)) {
113
+ display: inline-flex;
114
+ align-items: center;
115
+ gap: $gap;
116
+ flex-wrap: wrap;
117
+ }
118
+
119
+ // Input helpers
120
+ @mixin input-padding-trailing($logical-size) {
121
+ padding-inline-end: calc(#{$logical-size} * 2);
122
+ }
123
+
124
+ @mixin field-stack($gap: var(--gap-xs)) {
125
+ display: grid;
126
+ gap: $gap;
127
+ inline-size: stretch;
128
+ min-inline-size: 0;
129
+ }
130
+
131
+ // List helpers
132
+ @mixin tonal-list(
133
+ $role: surface,
134
+ $tone: var(--surface-opacity-subtle),
135
+ $radius: var(--radius-sm),
136
+ $padding: var(--padding-xs)
137
+ ) {
138
+ display: flex;
139
+ flex-direction: column;
140
+ gap: 0;
141
+ list-style: none;
142
+ margin: 0;
143
+ padding: $padding;
144
+ @include tonal-surface($role, $tone, $radius);
145
+ }
146
+
147
+ // State blocks (flex row with gaps and radius)
148
+ @mixin state-inline($gap, $padding-y, $padding-x, $radius) {
149
+ display: flex;
150
+ align-items: center;
151
+ gap: $gap;
152
+ padding-block: $padding-y;
153
+ padding-inline: $padding-x;
154
+ border-radius: $radius;
155
+ }
156
+
157
+ // Scrollbar styling (modern and webkit)
158
+ @mixin scrollbars($size: 6px, $tone: var(--surface-opacity-emphasis)) {
159
+ scrollbar-width: thin;
160
+ & { scrollbar-color: color-mix(in oklch, var(--on-surface, currentColor) var(--scrollbar-tint, 86%), transparent) transparent; }
161
+
162
+ &::-webkit-scrollbar { inline-size: $size; block-size: $size; }
163
+ &::-webkit-scrollbar-thumb {
164
+ border-radius: 999px;
165
+ @include solid-colorize("&", ("shade": $tone, "scope": "selector"));
166
+ }
167
+ &::-webkit-scrollbar-track { background: transparent; }
168
+ }
169
+
170
+ // Overlay + elevation utilities
171
+ @mixin glass-backdrop($blur: 18px, $opacity: 0.22) {
172
+ background: color-mix(in oklch, var(--color-inverse-surface) #{$opacity * 100%}, transparent);
173
+ backdrop-filter: blur($blur) saturate(120%);
174
+ }
175
+
176
+ // Accessibility helpers
177
+ @mixin reduced-motion-zero { transition-duration: 0ms; }
178
+ @mixin high-contrast-border($color: var(--border-color)) { border: 2px solid $color; }
179
+
@@ -0,0 +1,34 @@
1
+ // Query utilities: container and media helpers with shared breakpoints
2
+
3
+ $breakpoints: (
4
+ "sm": 480px,
5
+ "md": 640px,
6
+ "lg": 768px,
7
+ "xl": 1024px,
8
+ "2xl": 1280px
9
+ );
10
+
11
+ @mixin mq($cond) {
12
+ @media #{$cond} { @content; }
13
+ }
14
+
15
+ @mixin mq-up($key) {
16
+ $val: map-get($breakpoints, $key);
17
+ @media (min-width: $val) { @content; }
18
+ }
19
+
20
+ @mixin mq-down($key) {
21
+ $val: map-get($breakpoints, $key);
22
+ @media (max-width: $val) { @content; }
23
+ }
24
+
25
+ @mixin cq($cond) {
26
+ @container #{$cond} { @content; }
27
+ }
28
+
29
+ @mixin cq-size($min: null, $max: null) {
30
+ $parts: ();
31
+ @if $min != null { $parts: append($parts, '(min-inline-size: ' + $min + ')'); }
32
+ @if $max != null { $parts: append($parts, '(max-inline-size: ' + $max + ')'); }
33
+ @container #{join($parts, ' and ')} { @content; }
34
+ }