@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,744 @@
1
+ @use "./functions" as cfg;
2
+ @use "./config" as config;
3
+ @use "./tokens" as tokens;
4
+
5
+ //
6
+ @use "sass:math";
7
+ @use "sass:color";
8
+ @use "sass:list";
9
+ @use "sass:map";
10
+ @use "sass:meta";
11
+ @use "sass:string";
12
+
13
+ @use "../interact/position" as position;
14
+
15
+ /**
16
+ * Unified CSS Custom Property Registration System
17
+ *
18
+ * This module consolidates property registration logic used across the library.
19
+ * It provides a single source of truth for @property declarations via the
20
+ * CSS Properties and Values API (CSS Houdini).
21
+ *
22
+ * Used by:
23
+ * - lib/core/_properties.scss (orientation, transform, layout properties)
24
+ * - lib/basic/_typed-properties.scss (UI component properties)
25
+ * - lib/advanced/design/ (MD3 design properties)
26
+ */
27
+
28
+ // ============================================================================
29
+ // Default initial values by CSS type
30
+ // ============================================================================
31
+
32
+ $_default-initial-values: (
33
+ "integer": 0,
34
+ "number": 0.0,
35
+ "color": #0000,
36
+ "boolean": false,
37
+ "string": "",
38
+ "length": 0px,
39
+ "length-percentage": 0px,
40
+ "angle": 0deg,
41
+ "percentage": 0%,
42
+ "time": 0ms,
43
+ "frequency": 0hz,
44
+ ) !default;
45
+
46
+ /* stylelint-disable scss/function-no-unknown */
47
+
48
+ // ============================================================================
49
+ // Mixin: Register a single CSS Custom Property
50
+ // ============================================================================
51
+
52
+ ///
53
+ /// Registers a single CSS Custom Property via the Properties & Values API.
54
+ ///
55
+ /// Accepts a map with keys:
56
+ /// - syntax: (string) CSS property syntax (e.g., "<color>", "<length>")
57
+ /// - initial or initial-value: (any) default value for the property
58
+ /// - inherits: (boolean) whether property inherits (defaults to true)
59
+ ///
60
+ /// @example
61
+ /// @include register-property("--my-color", ("syntax": "<color>", "initial": #fff, "inherits": false));
62
+ ///
63
+ @mixin register-property($name, $definition) {
64
+ $config: if(sass(meta.type-of($definition) == "map"): $definition; else: ());
65
+
66
+ $syntax: map.get($config, "syntax") or "<number>";
67
+ $initial: if(sass(map.has-key($config, "initial-value")): map.get($config, "initial-value"); else: map.get($config, "initial"))
68
+ or _option-or($_default-initial-values, $syntax, 0.0);
69
+ $inherits: if(sass(map.has-key($config, "inherits")): map.get($config, "inherits"); else: true);
70
+
71
+ @property #{$name} {
72
+ @if $syntax != null {
73
+ syntax: "#{$syntax}";
74
+ }
75
+
76
+ @if $inherits != null {
77
+ inherits: $inherits;
78
+ }
79
+
80
+ @if $initial != null {
81
+ initial-value: #{$initial};
82
+ }
83
+ }
84
+ }
85
+
86
+ // ============================================================================
87
+ // Mixin: Register multiple CSS Custom Properties at once
88
+ // ============================================================================
89
+
90
+ ///
91
+ /// Registers multiple CSS Custom Properties at once from one or more maps.
92
+ ///
93
+ /// Each map entry should follow the format used by `register-property`.
94
+ /// Multiple maps can be passed as arguments.
95
+ ///
96
+ /// @example
97
+ /// @include register-properties((
98
+ /// "--my-color": ("syntax": "<color>", "initial": #fff),
99
+ /// "--my-size": ("syntax": "<length>", "initial": 0px),
100
+ /// ));
101
+ ///
102
+ @mixin register-properties($bundles...) {
103
+ @each $bundle in $bundles {
104
+ @if meta.type-of($bundle)=="map" {
105
+ @each $name, $definition in $bundle {
106
+ @include register-property($name, $definition);
107
+ }
108
+ }
109
+
110
+ @else if $bundle !=null {
111
+ @warn "register-properties expects map entries, received #{meta.type-of($bundle)}.";
112
+ }
113
+ }
114
+ }
115
+
116
+ @mixin for-shell($shell-id) {
117
+ :is(html, body):has([data-shell="#{$shell-id}"]) {
118
+ @content;
119
+ }
120
+ }
121
+
122
+ @mixin for-view($view-id) {
123
+ :is(html, body):has([data-view="#{$view-id}"]) {
124
+ @content;
125
+ }
126
+ }
127
+
128
+ @mixin for-shell-view($shell-id, $view-id) {
129
+ :is(html, body):has([data-shell="#{$shell-id}"] [data-view="#{$view-id}"]) {
130
+ @content;
131
+ }
132
+ }
133
+
134
+ @mixin when-state($selector) {
135
+ :is(html, body):has(#{$selector}) {
136
+ @content;
137
+ }
138
+ }
139
+
140
+ @mixin component-styles($selector) {
141
+ :where(#{$selector}) {
142
+ @content;
143
+ }
144
+ }
145
+
146
+ @mixin respond-to($breakpoint) {
147
+ $breakpoints: (
148
+ "sm": 640px,
149
+ "md": 768px,
150
+ "lg": 1024px,
151
+ "xl": 1280px,
152
+ );
153
+
154
+ @if map-has-key($breakpoints, $breakpoint) {
155
+ @media (min-width: map-get($breakpoints, $breakpoint)) {
156
+ @content;
157
+ }
158
+ }
159
+
160
+ @else {
161
+ @warn "Breakpoint '#{$breakpoint}' not found";
162
+ }
163
+ }
164
+
165
+ @mixin container-query($size, $direction: min-width) {
166
+ @container (#{$direction}: #{cfg.config("container-sizes", $size)}) {
167
+ @content;
168
+ }
169
+ }
170
+
171
+ @mixin media-query($size, $direction: min-width) {
172
+ @media (#{$direction}: #{cfg.config("breakpoints", $size)}) {
173
+ @content;
174
+ }
175
+ }
176
+
177
+ @mixin responsive-spacing($property, $sizes) {
178
+ @each $breakpoint, $size in $sizes {
179
+ @if $breakpoint =="base" {
180
+ #{$property}: cfg.config("spacing", $size);
181
+ }
182
+
183
+ @else {
184
+ @include container-query($breakpoint) {
185
+ #{$property}: cfg.config("spacing", $size);
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ @mixin flex($direction: row, $align: stretch, $justify: flex-start, $wrap: nowrap) {
192
+ display: flex;
193
+ flex-direction: $direction;
194
+ align-items: $align;
195
+ justify-content: $justify;
196
+ flex-wrap: $wrap;
197
+ }
198
+
199
+ @mixin grid($columns: 1, $rows: auto, $gap: 0) {
200
+ display: grid;
201
+ grid-template-columns: $columns;
202
+ grid-template-rows: $rows;
203
+ gap: $gap;
204
+ }
205
+
206
+ @mixin center-flex {
207
+ @include flex(row, center, center);
208
+ }
209
+
210
+ @mixin flex-center {
211
+ display: flex;
212
+ align-items: center;
213
+ justify-content: center;
214
+ }
215
+
216
+ @mixin flex-between {
217
+ display: flex;
218
+ align-items: center;
219
+ justify-content: space-between;
220
+ }
221
+
222
+ @mixin flex-column {
223
+ display: flex;
224
+ flex-direction: column;
225
+ }
226
+
227
+ @mixin stack($direction: column, $gap: var(--space-md)) {
228
+ display: flex;
229
+ flex-direction: $direction;
230
+ gap: $gap;
231
+ }
232
+
233
+ @mixin logical-size($block-size: auto, $inline-size: auto, $max-block-size: none, $max-inline-size: none) {
234
+ @if $block-size !=auto {
235
+ block-size: $block-size;
236
+ }
237
+
238
+ @if $inline-size !=auto {
239
+ inline-size: $inline-size;
240
+ }
241
+
242
+ @if $max-block-size !=none {
243
+ max-block-size: $max-block-size;
244
+ }
245
+
246
+ @if $max-inline-size !=none {
247
+ max-inline-size: $max-inline-size;
248
+ }
249
+ }
250
+
251
+ @mixin logical-spacing($property,
252
+ $block: 0,
253
+ $inline: 0,
254
+ $block-start: null,
255
+ $block-end: null,
256
+ $inline-start: null,
257
+ $inline-end: null) {
258
+ @if $block-start !=null {
259
+ #{$property}-block-start: $block-start;
260
+ }
261
+
262
+ @if $block-end !=null {
263
+ #{$property}-block-end: $block-end;
264
+ }
265
+
266
+ @if $inline-start !=null {
267
+ #{$property}-inline-start: $inline-start;
268
+ }
269
+
270
+ @if $inline-end !=null {
271
+ #{$property}-inline-end: $inline-end;
272
+ }
273
+
274
+ @if $block-start ==null and $block-end ==null and $block !=0 {
275
+ #{$property}-block: $block;
276
+ }
277
+
278
+ @if $inline-start ==null and $inline-end ==null and $inline !=0 {
279
+ #{$property}-inline: $inline;
280
+ }
281
+ }
282
+
283
+ @mixin logical-border($width: 1px, $style: solid, $color: currentColor, $sides: all) {
284
+ @if $sides =="all" {
285
+ border: $width $style $color;
286
+ }
287
+
288
+ @else if $sides =="block" {
289
+ border-block: $width $style $color;
290
+ }
291
+
292
+ @else if $sides =="inline" {
293
+ border-inline: $width $style $color;
294
+ }
295
+
296
+ @else if $sides =="block-start" {
297
+ border-block-start: $width $style $color;
298
+ }
299
+
300
+ @else if $sides =="block-end" {
301
+ border-block-end: $width $style $color;
302
+ }
303
+
304
+ @else if $sides =="inline-start" {
305
+ border-inline-start: $width $style $color;
306
+ }
307
+
308
+ @else if $sides =="inline-end" {
309
+ border-inline-end: $width $style $color;
310
+ }
311
+ }
312
+
313
+ @mixin typography($size: base, $weight: normal, $line-height: normal, $letter-spacing: normal) {
314
+ font-size: cfg.config("typography", "font-size", $size);
315
+ font-weight: cfg.config("typography", "font-weight", $weight);
316
+ line-height: cfg.config("typography", "line-height", $line-height);
317
+ letter-spacing: cfg.config("typography", "letter-spacing", $letter-spacing);
318
+ }
319
+
320
+ @mixin font-family($family: sans) {
321
+ font-family: cfg.config("typography", "font-family", $family);
322
+ }
323
+
324
+ @mixin truncate($lines: 1) {
325
+ @if $lines ==1 {
326
+ overflow: hidden;
327
+ text-overflow: ellipsis;
328
+ white-space: nowrap;
329
+ }
330
+
331
+ @else {
332
+ display: -webkit-box;
333
+ -webkit-line-clamp: $lines;
334
+ -webkit-box-orient: vertical;
335
+ overflow: hidden;
336
+ }
337
+ }
338
+
339
+ @mixin text-truncate {
340
+ @include truncate(1);
341
+ }
342
+
343
+ @mixin text-clamp($lines: 2) {
344
+ @include truncate($lines);
345
+ }
346
+
347
+ @mixin heading($level: 1) {
348
+ font-weight: var(--font-weight-semibold);
349
+ line-height: var(--leading-tight);
350
+ margin-block-start: 0;
351
+ margin-block-end: 0;
352
+
353
+ @if $level ==1 {
354
+ font-size: var(--text-3xl);
355
+ }
356
+
357
+ @else if $level ==2 {
358
+ font-size: var(--text-2xl);
359
+ }
360
+
361
+ @else if $level ==3 {
362
+ font-size: var(--text-xl);
363
+ }
364
+
365
+ @else if $level ==4 {
366
+ font-size: var(--text-lg);
367
+ }
368
+
369
+ @else if $level ==5 {
370
+ font-size: var(--text-md);
371
+ }
372
+
373
+ @else {
374
+ font-size: var(--text-base);
375
+ }
376
+ }
377
+
378
+ @mixin interactive($cursor: pointer, $touch-action: manipulation, $focus-ring: true) {
379
+ cursor: $cursor;
380
+ touch-action: $touch-action;
381
+ user-select: none;
382
+ -webkit-tap-highlight-color: transparent;
383
+
384
+ @if $focus-ring {
385
+ &:focus-visible {
386
+ outline: 2px solid cfg.config("colors", "focus");
387
+ outline-offset: 2px;
388
+ }
389
+ }
390
+
391
+ &:disabled,
392
+ &[aria-disabled="true"] {
393
+ cursor: not-allowed;
394
+ opacity: 0.6;
395
+ pointer-events: none;
396
+ }
397
+ }
398
+
399
+ @mixin interactive-states($hover-bg: null, $active-bg: null, $scale: 1.02) {
400
+ transition: all cfg.config("effects", "motion-fast");
401
+
402
+ &:hover {
403
+ @if $hover-bg !=null {
404
+ background-color: $hover-bg;
405
+ }
406
+
407
+ @if $scale !=1 {
408
+ transform: scale($scale);
409
+ }
410
+ }
411
+
412
+ &:active {
413
+ @if $active-bg !=null {
414
+ background-color: $active-bg;
415
+ }
416
+
417
+ transform: scale(0.98);
418
+ }
419
+ }
420
+
421
+ @mixin focus-ring($color: cfg.config("colors", "focus"), $width: 2px, $offset: 2px) {
422
+ &:focus-visible {
423
+ outline: $width solid $color;
424
+ outline-offset: $offset;
425
+ }
426
+ }
427
+
428
+ @mixin hover-lift($amount: -2px) {
429
+ transition: transform var(--transition-normal);
430
+
431
+ &:hover {
432
+ transform: translateY($amount);
433
+ }
434
+ }
435
+
436
+ @mixin button-reset {
437
+ appearance: none;
438
+ border: none;
439
+ background: none;
440
+ padding: 0;
441
+ margin: 0;
442
+ font: inherit;
443
+ color: inherit;
444
+ cursor: pointer;
445
+
446
+ &:disabled {
447
+ cursor: not-allowed;
448
+ }
449
+ }
450
+
451
+ @mixin scrollbar-base($size, $thumb-color, $track-color, $radius) {
452
+ scrollbar-width: thin;
453
+ scrollbar-color: $thumb-color $track-color;
454
+
455
+ &::-webkit-scrollbar {
456
+ inline-size: $size;
457
+ block-size: $size;
458
+ }
459
+
460
+ &::-webkit-scrollbar-thumb {
461
+ background-color: $thumb-color;
462
+ border-radius: $radius;
463
+ }
464
+
465
+ &::-webkit-scrollbar-track {
466
+ background-color: $track-color;
467
+ }
468
+ }
469
+
470
+ @mixin scrollbar($size: 8px, $thumb-color: rgba(0, 0, 0, 0.3), $track-color: transparent) {
471
+ @include scrollbar-base($size, $thumb-color, $track-color, cfg.config("shape", "border-radius", "full"));
472
+ }
473
+
474
+ @mixin custom-scrollbar($width: 8px, $thumb: var(--color-border-strong), $track: transparent) {
475
+ @include scrollbar-base($width, $thumb, $track, math.div($width, 2));
476
+ }
477
+
478
+ @mixin hide-scrollbar {
479
+ scrollbar-width: none;
480
+ -ms-overflow-style: none;
481
+
482
+ &::-webkit-scrollbar {
483
+ display: none;
484
+ }
485
+ }
486
+
487
+ @mixin focus-ring-alias($color: cfg.config("colors", "focus"), $width: 2px, $offset: 2px) {
488
+ @include focus-ring($color, $width, $offset);
489
+ }
490
+
491
+ @mixin aspect-ratio($ratio) {
492
+ aspect-ratio: $ratio;
493
+ }
494
+
495
+ @mixin md-break($before: auto, $inside: auto, $after: auto) {
496
+ break-before: $before;
497
+ break-inside: $inside;
498
+ break-after: $after;
499
+ }
500
+
501
+ @mixin md-heading-print($scale, $padding: null) {
502
+ $resolved-padding: sass(if(sass($padding == null): cfg.config("heading", "padding"); else: $padding));
503
+ $line-height: cfg.config("layout", "line-height");
504
+ $h-size: calc(3 - clamp(1, sqrt($scale) * 0.9, 2));
505
+
506
+ font-weight: bold;
507
+ font-size: calc($h-size * 1em);
508
+ padding-inline: $resolved-padding;
509
+ margin-block-end: calc($h-size * 0.333em);
510
+ margin-block-start: calc($h-size * 0.5em);
511
+ display: block;
512
+ line-height: $line-height;
513
+ text-align: start;
514
+
515
+ @include md-break(auto, avoid-page, avoid-page);
516
+ }
517
+
518
+ @mixin md-table-cell($padding: null) {
519
+ $resolved-padding: sass(if(sass($padding == null): cfg.config("table", "cell-padding"); else: $padding));
520
+
521
+ padding: $resolved-padding;
522
+ white-space: normal;
523
+ }
524
+
525
+ @mixin md-font-smoothing($mode: always) {
526
+ font-smooth: $mode !important;
527
+ -webkit-font-smoothing: sass(if(sass($mode == always): subpixel-antialiased; else: antialiased)) !important;
528
+ -moz-osx-font-smoothing: sass(if(sass($mode == always): auto; else: grayscale)) !important;
529
+ }
530
+
531
+ @mixin md-interactive-area($align: null, $touch: manipulation) {
532
+ touch-action: $touch;
533
+ pointer-events: auto;
534
+ user-select: text;
535
+
536
+ @if $align !=null {
537
+ text-align: $align;
538
+ }
539
+ }
540
+
541
+ @mixin md-surface-root($align: start, $touch: manipulation) {
542
+ color-scheme: inherit;
543
+ font-size: inherit;
544
+ isolation: isolate;
545
+
546
+ @include md-interactive-area($align, $touch);
547
+ }
548
+
549
+ @mixin md-children-inherit($selector, $block-size: auto 1em) {
550
+ #{$selector} {
551
+ color-scheme: inherit;
552
+ }
553
+ }
554
+
555
+ @mixin md-scrollbars($size: null) {
556
+ $scroll-size: sass(if(sass($size == null): cfg.config("scrollbar", "size"); else: $size));
557
+ // border-radius is a token map; pick one scalar (matches @mixin scrollbar).
558
+ $radius: cfg.radius("full");
559
+
560
+ @include scrollbar-base($scroll-size, var(--color-scrollbar), transparent, $radius);
561
+ }
562
+
563
+ @mixin breakpoint($size) {
564
+ @if $size =="xs" {
565
+ @media (max-width: 480px) {
566
+ @content;
567
+ }
568
+ }
569
+
570
+ @else if $size =="sm" {
571
+ @media (max-width: 640px) {
572
+ @content;
573
+ }
574
+ }
575
+
576
+ @else if $size =="md" {
577
+ @media (max-width: 768px) {
578
+ @content;
579
+ }
580
+ }
581
+
582
+ @else if $size =="lg" {
583
+ @media (max-width: 1024px) {
584
+ @content;
585
+ }
586
+ }
587
+
588
+ @else if $size =="xl" {
589
+ @media (max-width: 1280px) {
590
+ @content;
591
+ }
592
+ }
593
+
594
+ @else if $size =="2xl" {
595
+ @media (max-width: 1536px) {
596
+ @content;
597
+ }
598
+ }
599
+
600
+ @else {
601
+ @warn "Unknown breakpoint: #{$size}";
602
+ }
603
+ }
604
+
605
+ @mixin breakpoint-up($size) {
606
+ @if $size =="sm" {
607
+ @media (min-width: 640px) {
608
+ @content;
609
+ }
610
+ }
611
+
612
+ @else if $size =="md" {
613
+ @media (min-width: 768px) {
614
+ @content;
615
+ }
616
+ }
617
+
618
+ @else if $size =="lg" {
619
+ @media (min-width: 1024px) {
620
+ @content;
621
+ }
622
+ }
623
+
624
+ @else if $size =="xl" {
625
+ @media (min-width: 1280px) {
626
+ @content;
627
+ }
628
+ }
629
+
630
+ @else if $size =="2xl" {
631
+ @media (min-width: 1536px) {
632
+ @content;
633
+ }
634
+ }
635
+
636
+ @else {
637
+ @warn "Unknown breakpoint: #{$size}";
638
+ }
639
+ }
640
+
641
+ @mixin print {
642
+ @media print {
643
+ @content;
644
+ }
645
+ }
646
+
647
+ @mixin reduced-motion {
648
+ @media (prefers-reduced-motion: reduce) {
649
+ @content;
650
+ }
651
+ }
652
+
653
+ @mixin dark-mode {
654
+ @media (prefers-color-scheme: dark) {
655
+ @content;
656
+ }
657
+ }
658
+
659
+ @mixin card {
660
+ background-color: var(--color-surface-elevated);
661
+ border-radius: var(--card-radius);
662
+ box-shadow: var(--card-shadow);
663
+ padding: var(--card-padding);
664
+ }
665
+
666
+ @mixin overlay($bg: var(--modal-backdrop-bg)) {
667
+ @include position.fixed-fill;
668
+ background-color: $bg;
669
+ z-index: var(--z-modal-backdrop);
670
+ }
671
+
672
+ @mixin fade-in($duration: var(--transition-normal)) {
673
+ animation: fade-in $duration ease-out;
674
+ }
675
+
676
+ @mixin slide-in($direction: bottom, $distance: 1rem, $duration: var(--transition-normal)) {
677
+ --slide-distance: #{$distance};
678
+ animation: slide-in-#{$direction} $duration ease-out;
679
+ }
680
+
681
+ //
682
+ @mixin when-hover($selector: "&") {
683
+ @media (hover: hover) and (pointer: fine) { #{$selector}:hover { @content; } }
684
+ @media (hover: none) and (pointer: coarse) { #{$selector}:active { @content; } }
685
+ }
686
+
687
+ //
688
+ @mixin when-active($selector: "&") {
689
+ @media (hover: hover) and (pointer: fine) { #{$selector}:active { @content; } }
690
+ }
691
+
692
+ //
693
+ @mixin when-focus($selector: "&") {
694
+ @media (hover: hover) and (pointer: fine) { #{$selector}:focus-visible { @content; } }
695
+ @media (hover: none) and (pointer: coarse) { #{$selector}:focus { @content; } }
696
+ }
697
+
698
+ //
699
+ @mixin when-focus-visible($selector: "&") {
700
+ @media (hover: hover) and (pointer: fine) { #{$selector}:focus-visible { @content; } }
701
+ @media (hover: none) and (pointer: coarse) { #{$selector}:focus-visible { @content; } }
702
+ }
703
+
704
+ //
705
+ @mixin when-disabled($selector: "&") {
706
+ @media (hover: hover) and (pointer: fine) { #{$selector}:disabled, #{$selector}[aria-disabled="true"] { @content; } }
707
+ @media (hover: none) and (pointer: coarse) { #{$selector}:disabled, #{$selector}[aria-disabled="true"] { @content; } }
708
+ }
709
+
710
+ //
711
+ @mixin when-selected($selector: "&") {
712
+ @media (hover: hover) and (pointer: fine) { #{$selector}::selection, #{$selector}:checked, #{$selector}[aria-selected="true"] { @content; } }
713
+ @media (hover: none) and (pointer: coarse) { #{$selector}::selection, #{$selector}:checked, #{$selector}[aria-selected="true"] { @content; } }
714
+ }
715
+
716
+ //
717
+ @mixin when-autofill($selector: "&") {
718
+ #{$selector}:-webkit-autofill { @content; }
719
+ #{$selector}:autofill { @content; }
720
+ #{$selector}:auto-fill { @content; }
721
+ }
722
+
723
+ @mixin hover($selector: "&") {
724
+ @include when-hover { #{$selector}:hover { @content; } }
725
+ @include when-active { #{$selector}:active { @content; } }
726
+ }
727
+
728
+ @mixin line-clamp($lines) {
729
+ display: -webkit-box;
730
+ -webkit-line-clamp: $lines;
731
+ -webkit-box-orient: vertical;
732
+ overflow: hidden;
733
+ }
734
+
735
+ $spaces: (
736
+ "0": 0,
737
+ "xs": cfg.config("spacing", "xs"),
738
+ "sm": cfg.config("spacing", "sm"),
739
+ "md": cfg.config("spacing", "md"),
740
+ "lg": cfg.config("spacing", "lg"),
741
+ "xl": cfg.config("spacing", "xl"),
742
+ "2xl": cfg.config("spacing", "2xl"),
743
+ "3xl": cfg.config("spacing", "3xl")
744
+ );