@mastors/core 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +940 -0
  3. package/api/_index.scss +5 -0
  4. package/dist/mastors-core.css +7419 -0
  5. package/dist/mastors-core.css.map +1 -0
  6. package/package.json +73 -0
  7. package/postinstall.js +41 -0
  8. package/scripts/generate-tokens.js +259 -0
  9. package/scss/abstracts/_index.scss +6 -0
  10. package/scss/abstracts/_maps.scss +9 -0
  11. package/scss/abstracts/_placeholders.scss +7 -0
  12. package/scss/accessibility/_focus.scss +21 -0
  13. package/scss/accessibility/_index.scss +7 -0
  14. package/scss/accessibility/_motion.scss +14 -0
  15. package/scss/accessibility/_print.scss +52 -0
  16. package/scss/accessibility/_screen-reader.scss +31 -0
  17. package/scss/api/_index.scss +14 -0
  18. package/scss/base/_box-sizing.scss +6 -0
  19. package/scss/base/_index.scss +7 -0
  20. package/scss/base/_reset.scss +59 -0
  21. package/scss/base/_root.scss +43 -0
  22. package/scss/base/_typography-base.scss +40 -0
  23. package/scss/config/_flags.scss +13 -0
  24. package/scss/config/_index.scss +12 -0
  25. package/scss/config/_settings.scss +18 -0
  26. package/scss/functions/_color.scss +66 -0
  27. package/scss/functions/_em.scss +28 -0
  28. package/scss/functions/_index.scss +15 -0
  29. package/scss/functions/_map-helpers.scss +29 -0
  30. package/scss/functions/_math.scss +40 -0
  31. package/scss/functions/_rem.scss +27 -0
  32. package/scss/functions/_string.scss +57 -0
  33. package/scss/functions/_vars.scss +49 -0
  34. package/scss/generators/_class-generator.scss +83 -0
  35. package/scss/generators/_custom-property-generator.scss +29 -0
  36. package/scss/generators/_index.scss +6 -0
  37. package/scss/generators/_responsive-generator.scss +28 -0
  38. package/scss/helpers/_clearfix.scss +9 -0
  39. package/scss/helpers/_index.scss +7 -0
  40. package/scss/helpers/_ratio.scss +22 -0
  41. package/scss/helpers/_truncate.scss +25 -0
  42. package/scss/helpers/_visually-hidden.scss +39 -0
  43. package/scss/index.scss +41 -0
  44. package/scss/mixins/_breakpoint.scss +33 -0
  45. package/scss/mixins/_container.scss +20 -0
  46. package/scss/mixins/_elevation.scss +12 -0
  47. package/scss/mixins/_index.scss +9 -0
  48. package/scss/mixins/_pseudo.scss +13 -0
  49. package/scss/mixins/_theme.scss +31 -0
  50. package/scss/mixins/_transition.scss +20 -0
  51. package/scss/responsive/_container-queries.scss +31 -0
  52. package/scss/responsive/_engine.scss +65 -0
  53. package/scss/responsive/_fluid-type.scss +40 -0
  54. package/scss/responsive/_index.scss +6 -0
  55. package/scss/semantic/_colors.scss +29 -0
  56. package/scss/semantic/_index.scss +6 -0
  57. package/scss/semantic/_spacing.scss +13 -0
  58. package/scss/semantic/_typography.scss +13 -0
  59. package/scss/themes/_base-theme.scss +28 -0
  60. package/scss/themes/_dark.scss +59 -0
  61. package/scss/themes/_index.scss +6 -0
  62. package/scss/themes/_light.scss +31 -0
  63. package/scss/tokens/_color.scss +100 -0
  64. package/scss/tokens/_index.scss +12 -0
  65. package/scss/tokens/_opacity.scss +28 -0
  66. package/scss/tokens/_radii.scss +21 -0
  67. package/scss/tokens/_shadows.scss +20 -0
  68. package/scss/tokens/_sizing.scss +47 -0
  69. package/scss/tokens/_spacing.scss +48 -0
  70. package/scss/tokens/_transitions.scss +27 -0
  71. package/scss/tokens/_typography.scss +63 -0
  72. package/scss/tokens/_z-index.scss +21 -0
  73. package/scss/utilities/_animation.scss +125 -0
  74. package/scss/utilities/_borders.scss +55 -0
  75. package/scss/utilities/_colors.scss +42 -0
  76. package/scss/utilities/_cursor.scss +28 -0
  77. package/scss/utilities/_display.scss +26 -0
  78. package/scss/utilities/_index.scss +20 -0
  79. package/scss/utilities/_interaction.scss +156 -0
  80. package/scss/utilities/_layout.scss +162 -0
  81. package/scss/utilities/_opacity.scss +9 -0
  82. package/scss/utilities/_overflow.scss +36 -0
  83. package/scss/utilities/_pointer-events.scss +6 -0
  84. package/scss/utilities/_position.scss +32 -0
  85. package/scss/utilities/_shadows.scss +11 -0
  86. package/scss/utilities/_sizing.scss +40 -0
  87. package/scss/utilities/_spacing.scss +42 -0
  88. package/scss/utilities/_transform.scss +43 -0
  89. package/scss/utilities/_typography.scss +163 -0
  90. package/scss/utilities/_z-index.scss +9 -0
  91. package/scss/variables/_breakpoints.scss +14 -0
  92. package/scss/variables/_container.scss +13 -0
  93. package/scss/variables/_global.scss +8 -0
  94. package/scss/variables/_grid.scss +7 -0
  95. package/scss/variables/_index.scss +7 -0
  96. package/scss/vendors/_index.scss +15 -0
@@ -0,0 +1,49 @@
1
+ // functions/_vars.scss
2
+ // vars() — reference any design token as a CSS custom property by name.
3
+ // ─────────────────────────────────────────────────────────────
4
+ // All Mastors tokens are emitted as --mastors-{name} custom properties
5
+ // by the token layer. This function wraps that convention so downstream
6
+ // consumers never have to hard-code the --mastors- prefix themselves,
7
+ // and so token references remain refactor-safe if the prefix ever changes.
8
+ // Usage:
9
+ // color: vars(accent); → var(--mastors-accent)
10
+ // background-color: vars(surface-raised); → var(--mastors-surface-raised)
11
+ // box-shadow: vars(shadow-lg); → var(--mastors-shadow-lg)
12
+ // With a CSS fallback (passed through verbatim):
13
+ // color: vars(accent, #3b82f6); → var(--mastors-accent, #3b82f6)
14
+ // gap: vars(spacing-4, 1rem); → var(--mastors-spacing-4, 1rem)
15
+ // Composing with other functions is fine — Sass evaluates eagerly:
16
+ // transition: opacity vars(duration-200) vars(ease-out);
17
+ // ─────────────────────────────────────────────────────────────
18
+
19
+ @use "sass:meta";
20
+ @use "sass:string";
21
+ @use "../variables/global" as g;
22
+
23
+ // Internal: the custom-property namespace prefix.
24
+ // Mirrors the --mastors- prefix used by the token emitter.
25
+ // Kept as a private variable so it only needs to change here.
26
+ $-namespace: "mastors" !default;
27
+
28
+ /// Return a CSS var() expression for a design token by name.
29
+ ///
30
+ /// @param {String} $token - token name, without the --mastors- prefix
31
+ /// @param {*} $fallback - optional CSS fallback value (default: null)
32
+ /// @return {String} var(--mastors-{$token}) or var(--mastors-{$token}, {$fallback})
33
+ ///
34
+ /// @example scss
35
+ /// .btn { color: vars(accent); }
36
+ /// // → .btn { color: var(--mastors-accent); }
37
+ ///
38
+ /// @example scss
39
+ /// .card { box-shadow: vars(shadow-md, 0 2px 8px rgb(0 0 0 / .1)); }
40
+ /// // → .card { box-shadow: var(--mastors-shadow-md, 0 2px 8px rgb(0 0 0 / .1)); }
41
+ @function vars($token, $fallback: null) {
42
+ $prop: "--#{$-namespace}-#{$token}";
43
+
44
+ @if not $fallback {
45
+ @return var(#{$prop});
46
+ } @else {
47
+ @return var(#{$prop}, #{$fallback});
48
+ }
49
+ }
@@ -0,0 +1,83 @@
1
+ // generators/_class-generator.scss
2
+ // Core mixin engine for generating utility class output.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "sass:meta";
7
+ @use "sass:string";
8
+ @use "../config/settings" as cfg;
9
+ @use "../config/flags";
10
+ @use "../variables/breakpoints" as bpvars;
11
+
12
+ /// Core utility class generator engine.
13
+ @mixin generate-utilities($utilities) {
14
+ $cls-prefix: cfg.config("prefix");
15
+ $use-important: cfg.config("important");
16
+
17
+ // ── Pass 1: base (unprefixed) classes ──────────────────────
18
+ @each $name, $config in $utilities {
19
+ $prop: map.get($config, property);
20
+ $values: map.get($config, values);
21
+ $prefix: map.get($config, prefix);
22
+
23
+ @each $suffix, $value in $values {
24
+ $class-name: "#{$cls-prefix}#{$suffix}";
25
+ @if $prefix {
26
+ $class-name: "#{$cls-prefix}#{$prefix}-#{$suffix}";
27
+ }
28
+ .#{$class-name} {
29
+ @if $use-important {
30
+ #{$prop}: $value !important;
31
+ } @else {
32
+ #{$prop}: $value;
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ // ── Pass 2: responsive variants (.sm\:, .md\:, …) ─────────
39
+ @if flags.$enable-responsive {
40
+ @each $bp-key, $bp-value in bpvars.$breakpoints {
41
+ @if $bp-value != 0 {
42
+ @media (min-width: #{$bp-value}) {
43
+ @each $name, $config in $utilities {
44
+ @if map.get($config, responsive) == true {
45
+ $prop: map.get($config, property);
46
+ $values: map.get($config, values);
47
+ $prefix: map.get($config, prefix);
48
+
49
+ @each $suffix, $value in $values {
50
+ $class: null;
51
+ @if $prefix {
52
+ $class: "#{$cls-prefix}#{$prefix}-#{$suffix}";
53
+ } @else {
54
+ $class: "#{$cls-prefix}#{$suffix}";
55
+ }
56
+
57
+ // Escape numeric-leading breakpoint keys (e.g. "2xl" → "\32 xl")
58
+ $first: string.slice("#{$bp-key}", 1, 1);
59
+ $rest: string.slice("#{$bp-key}", 2);
60
+ $safe-bp: null;
61
+ @if $first == "0" or $first == "1" or $first == "2" or $first == "3" or
62
+ $first == "4" or $first == "5" or $first == "6" or $first == "7" or
63
+ $first == "8" or $first == "9" {
64
+ $safe-bp: "\\3#{$first} #{$rest}";
65
+ } @else {
66
+ $safe-bp: "#{$bp-key}";
67
+ }
68
+
69
+ @at-root .#{$safe-bp}\:#{$class} {
70
+ @if $use-important {
71
+ #{$prop}: $value !important;
72
+ } @else {
73
+ #{$prop}: $value;
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,29 @@
1
+ // generators/_custom-property-generator.scss
2
+ // Emits CSS custom properties from SCSS token maps.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "sass:meta";
7
+ @use "sass:string";
8
+
9
+ /// Emit CSS custom properties from a token map onto a selector
10
+ /// @param {Map} $map - token map (key → value)
11
+ /// @param {String} $prefix - custom property prefix (e.g. "mastors-color-primary")
12
+ @mixin emit-custom-properties($map, $prefix) {
13
+ @each $key, $value in $map {
14
+ --#{$prefix}-#{$key}: #{$value};
15
+ }
16
+ }
17
+
18
+ /// Recursively emit nested token maps (e.g. color palette with scales)
19
+ /// @param {Map} $map - nested map
20
+ /// @param {String} $prefix - base prefix (e.g. "mastors-color")
21
+ @mixin emit-nested-custom-properties($map, $prefix) {
22
+ @each $key, $value in $map {
23
+ @if meta.type-of($value) == map {
24
+ @include emit-nested-custom-properties($value, "#{$prefix}-#{$key}");
25
+ } @else {
26
+ --#{$prefix}-#{$key}: #{$value};
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ // generators/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "class-generator";
5
+ @forward "custom-property-generator";
6
+ @forward "responsive-generator";
@@ -0,0 +1,28 @@
1
+ // generators/_responsive-generator.scss
2
+ // Responsive variant delegation — forwards to the canonical engine.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // NOTE: Responsive class generation is now handled directly inside
6
+ // generate-utilities() in _class-generator.scss (Pass 2).
7
+ // This file previously contained a generate-responsive() mixin that
8
+ // accepted @content blocks but never emitted any CSS itself, making it
9
+ // a silent no-op. That stub has been removed to prevent confusion.
10
+ // — If you need to run the responsive engine standalone (e.g. from a
11
+ // sub-package that builds its own $utilities map independently of
12
+ // generate-utilities), use the engine mixin directly:
13
+ // @use "@mastors/core/scss/responsive/engine" as engine;
14
+ // @include engine.run($my-utilities);
15
+ // — For the standard case, simply pass your $utilities map to
16
+ // generate-utilities() and set responsive: true on any entry that
17
+ // needs breakpoint variants — the responsive pass runs automatically.
18
+
19
+ @use "../responsive/engine" as engine;
20
+ @use "sass:map";
21
+
22
+ /// Thin wrapper that delegates to engine.run().
23
+ /// Prefer calling engine.run() directly for clarity.
24
+ /// Kept here only for backward compatibility with sub-packages that
25
+ /// previously @use'd this file.
26
+ @mixin generate-responsive($utilities) {
27
+ @include engine.run($utilities);
28
+ }
@@ -0,0 +1,9 @@
1
+ // helpers/_clearfix.scss
2
+ // Clearfix helper for legacy float layouts.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ .clearfix::after {
6
+ content: "";
7
+ display: table;
8
+ clear: both;
9
+ }
@@ -0,0 +1,7 @@
1
+ // helpers/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "clearfix";
5
+ @forward "visually-hidden";
6
+ @forward "truncate";
7
+ @forward "ratio";
@@ -0,0 +1,22 @@
1
+ // helpers/_ratio.scss
2
+ // Aspect ratio helpers.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:math";
6
+
7
+ // Aspect ratio helpers using the native aspect-ratio property
8
+
9
+ $-ratios: (
10
+ "auto": auto,
11
+ "square": math.div(1, 1),
12
+ "video": math.div(16, 9),
13
+ "portrait": math.div(3, 4),
14
+ "wide": math.div(21, 9),
15
+ "golden": math.div(1.618, 1),
16
+ ) !default;
17
+
18
+ @each $name, $ratio in $-ratios {
19
+ .ratio-#{$name} {
20
+ aspect-ratio: $ratio;
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ // helpers/_truncate.scss
2
+ // Text truncation and overflow helpers.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Single-line truncation
6
+ .truncate {
7
+ overflow: hidden;
8
+ text-overflow: ellipsis;
9
+ white-space: nowrap;
10
+ }
11
+
12
+ // Multi-line clamp helpers (.line-clamp-{n})
13
+ @each $n in 1, 2, 3, 4, 5, 6 {
14
+ .line-clamp-#{$n} {
15
+ display: -webkit-box;
16
+ -webkit-line-clamp: $n;
17
+ -webkit-box-orient: vertical;
18
+ overflow: hidden;
19
+ }
20
+ }
21
+
22
+ // Break long words
23
+ .break-words { overflow-wrap: break-word; word-break: break-word; }
24
+ .break-all { word-break: break-all; }
25
+ .break-keep { word-break: keep-all; }
@@ -0,0 +1,39 @@
1
+ // helpers/_visually-hidden.scss
2
+ // Visually hides content while keeping it accessible to screen readers.
3
+ // ─────────────────────────────────────────────────────────────
4
+ // The canonical implementation lives in accessibility/_screen-reader.scss
5
+ // (.sr-only / .not-sr-only — the modern standard class names).
6
+ // This file provides the legacy aliases (.visually-hidden, .vh,
7
+ // .visually-hidden-focusable) that map onto the same rules, so existing
8
+ // codebases using either naming convention continue to work without
9
+ // duplicating any declarations.
10
+
11
+ @use "../accessibility/screen-reader" as *;
12
+
13
+ // Legacy aliases — extend the canonical sr-only rules
14
+ // so no extra CSS is emitted; both class names share one rule block.
15
+ .visually-hidden,
16
+ .vh {
17
+ position: absolute;
18
+ width: 1px;
19
+ height: 1px;
20
+ padding: 0;
21
+ margin: -1px;
22
+ overflow: hidden;
23
+ clip: rect(0, 0, 0, 0);
24
+ white-space: nowrap;
25
+ border-width: 0;
26
+ }
27
+
28
+ // Undo visually-hidden when focused (e.g. skip links)
29
+ .visually-hidden-focusable:not(:focus):not(:focus-within) {
30
+ position: absolute;
31
+ width: 1px;
32
+ height: 1px;
33
+ padding: 0;
34
+ margin: -1px;
35
+ overflow: hidden;
36
+ clip: rect(0, 0, 0, 0);
37
+ white-space: nowrap;
38
+ border-width: 0;
39
+ }
@@ -0,0 +1,41 @@
1
+ // @mastors/core — scss/index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+ // Main entry point for @mastors/core.
4
+ // Import order is intentional — do not reorder without reason.
5
+ // ─────────────────────────────────────────────────────────────
6
+
7
+ // 1. Config & Settings (no output)
8
+ @use "config/settings" as *;
9
+ @use "config/flags" as *;
10
+
11
+ // 2. Abstracts (no output)
12
+ @use "abstracts/index" as *;
13
+
14
+ // 3. Variables & Tokens (no output)
15
+ @use "variables/index" as *;
16
+ @use "tokens/index" as *;
17
+
18
+ // 4. Functions (no output)
19
+ @use "functions/index" as *;
20
+
21
+ // 5. Mixins (no output)
22
+ @use "mixins/index" as *;
23
+
24
+ // 6. Base & Reset (outputs CSS)
25
+ @use "base/index" as base;
26
+
27
+ // 7. Themes (outputs CSS custom properties)
28
+ @use "themes/index" as themes;
29
+
30
+ // 8. Semantic layer (outputs CSS)
31
+ @use "semantic/index" as semantic;
32
+
33
+ // 9. Responsive engine (outputs CSS)
34
+ @use "responsive/index" as responsive;
35
+
36
+ // 10. Helpers & Utilities
37
+ @use "helpers/index" as helpers;
38
+ @use "utilities/index" as utilities;
39
+
40
+ // 11. Accessibility
41
+ @use "accessibility/index" as accessibility;
@@ -0,0 +1,33 @@
1
+ // mixins/_breakpoint.scss
2
+ // Responsive breakpoint mixin and variant helpers.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "../variables/breakpoints" as bpvars;
7
+
8
+ /// Emit styles at and above a named breakpoint (mobile-first)
9
+ /// @param {String} $bp - breakpoint key (sm, md, lg, xl, 2xl)
10
+ @mixin bp($bp) {
11
+ $value: map.get(bpvars.$breakpoints, $bp);
12
+ @if not $value {
13
+ @error "bp(): unknown breakpoint '#{$bp}'. Available: #{map.keys(bpvars.$breakpoints)}";
14
+ }
15
+ @if $value == 0 {
16
+ @content;
17
+ } @else {
18
+ @media (min-width: #{$value}) { @content; }
19
+ }
20
+ }
21
+
22
+ // Alias
23
+ @mixin respond-to($bp) { @include bp($bp) { @content; } }
24
+ @mixin breakpoint-up($bp) { @include bp($bp) { @content; } }
25
+
26
+ /// Emit styles below a named breakpoint
27
+ @mixin breakpoint-down($bp) {
28
+ $value: map.get(bpvars.$breakpoints, $bp);
29
+ @if not $value {
30
+ @error "breakpoint-down(): unknown breakpoint '#{$bp}'";
31
+ }
32
+ @media (max-width: #{$value - 0.02px}) { @content; }
33
+ }
@@ -0,0 +1,20 @@
1
+ // mixins/_container.scss
2
+ // Responsive container width / max-width / padding mixin.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "../variables/container" as cvars;
7
+ @use "./breakpoint" as bp;
8
+
9
+ /// Responsive container with max-width and horizontal padding
10
+ @mixin container {
11
+ width: 100%;
12
+ margin-inline: auto;
13
+ padding-inline: cvars.$container-padding-x;
14
+
15
+ @each $bp-key, $max-w in cvars.$container-max-widths {
16
+ @include bp.bp($bp-key) {
17
+ max-width: $max-w;
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,12 @@
1
+ // mixins/_elevation.scss
2
+ // Box shadow / elevation scale mixin.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "../tokens/shadows" as sh;
7
+
8
+ /// Apply a shadow elevation level
9
+ /// @param {String} $level - shadow key (xs, sm, md, lg, xl, 2xl, inner, none)
10
+ @mixin elevation($level: "md") {
11
+ box-shadow: sh.shadow($level);
12
+ }
@@ -0,0 +1,9 @@
1
+ // mixins/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "breakpoint";
5
+ @forward "theme";
6
+ @forward "elevation";
7
+ @forward "transition";
8
+ @forward "pseudo";
9
+ @forward "container";
@@ -0,0 +1,13 @@
1
+ // mixins/_pseudo.scss
2
+ // ::before / ::after pseudo-element helper mixins.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /// Generate a pseudo-element (::before / ::after)
6
+ /// @param {String} $display - display value (default: block)
7
+ /// @param {String} $pos - position value (default: absolute)
8
+ /// @param {String} $content - content value (default: "")
9
+ @mixin pseudo($display: block, $pos: absolute, $content: "") {
10
+ content: $content;
11
+ display: $display;
12
+ position: $pos;
13
+ }
@@ -0,0 +1,31 @@
1
+ // mixins/_theme.scss
2
+ // Theme-switching mixins (light/dark/custom).
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "../config/settings" as cfg;
6
+
7
+ /// Apply styles inside the dark-mode context (class or media strategy)
8
+ @mixin dark-mode {
9
+ @if cfg.config("dark-mode") == "class" {
10
+ .dark & { @content; }
11
+ [data-theme="dark"] & { @content; }
12
+ } @else {
13
+ @media (prefers-color-scheme: dark) { @content; }
14
+ }
15
+ }
16
+
17
+ /// Apply styles inside the light-mode context
18
+ @mixin light-mode {
19
+ @if cfg.config("dark-mode") == "class" {
20
+ .light & { @content; }
21
+ [data-theme="light"] & { @content; }
22
+ } @else {
23
+ @media (prefers-color-scheme: light) { @content; }
24
+ }
25
+ }
26
+
27
+ /// Apply styles under a named theme class on :root/html
28
+ /// Usage: @include theme("ocean") { color: ...; }
29
+ @mixin theme($name) {
30
+ [data-theme="#{$name}"] & { @content; }
31
+ }
@@ -0,0 +1,20 @@
1
+ // mixins/_transition.scss
2
+ // Transition helpers using token-driven durations and easings.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:list";
6
+ @use "../tokens/transitions" as tr;
7
+
8
+ /// Emit a transition using named token durations and easings
9
+ /// @param {List} $properties - CSS properties to transition (default: all)
10
+ /// @param {String} $duration - duration token key (default: "200")
11
+ /// @param {String} $easing - easing token key (default: "in-out")
12
+ @mixin transition($properties: (all), $duration: "200", $easing: "in-out") {
13
+ $dur: tr.duration($duration);
14
+ $ease: tr.easing($easing);
15
+ $transitions: ();
16
+ @each $prop in $properties {
17
+ $transitions: list.append($transitions, #{$prop} #{$dur} #{$ease}, comma);
18
+ }
19
+ transition: $transitions;
20
+ }
@@ -0,0 +1,31 @@
1
+ // responsive/_container-queries.scss
2
+ // CSS container query helpers (@container).
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Container query helpers
6
+ // Requires elements to have a containment context set:
7
+ // .cq-inline { container-type: inline-size; }
8
+ // .cq-size { container-type: size; }
9
+ // .cq-normal { container-type: normal; }
10
+
11
+ .cq-inline { container-type: inline-size; }
12
+ .cq-size { container-type: size; }
13
+ .cq-normal { container-type: normal; }
14
+
15
+ // Named container helper
16
+ // Usage: <div class="cq-inline" style="container-name: card">...
17
+ // or use data attribute: [data-container] { container-type: inline-size; }
18
+ [data-container] {
19
+ container-type: inline-size;
20
+ }
21
+
22
+ // Mixin for inline container queries in component SCSS
23
+ // @use "@mastors/core/api" as m;
24
+ // @include m.cq(40rem) { ... }
25
+ @mixin cq($min-width, $name: null) {
26
+ @if $name {
27
+ @container #{$name} (min-width: #{$min-width}) { @content; }
28
+ } @else {
29
+ @container (min-width: #{$min-width}) { @content; }
30
+ }
31
+ }
@@ -0,0 +1,65 @@
1
+ // responsive/_engine.scss
2
+ // Core responsive variant generation engine.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "../variables/breakpoints" as bpvars;
7
+ @use "../config/flags";
8
+
9
+ // Responsive engine — generates breakpoint-prefixed variants
10
+ // of any utility that declares responsive: true.
11
+ // Class pattern: .{bp}\:{utility}
12
+ // Example output: .sm\:hidden, .md\:flex, .lg\:gap-8
13
+ // Sub-packages pass their $utilities map here via @include engine.run()
14
+ // so the engine iterates breakpoints and re-emits the classes.
15
+
16
+ @use "sass:string";
17
+
18
+ @mixin run($utilities) {
19
+ @if flags.$enable-responsive {
20
+ @each $bp-key, $bp-value in bpvars.$breakpoints {
21
+ // Skip xs — no prefix, already emitted as base classes
22
+ @if $bp-value != 0 {
23
+ @media (min-width: #{$bp-value}) {
24
+ @each $name, $config in $utilities {
25
+ @if map.get($config, responsive) == true {
26
+ $prop: map.get($config, property);
27
+ $values: map.get($config, values);
28
+ $prefix: map.get($config, prefix);
29
+
30
+ @each $suffix, $value in $values {
31
+ $class: null;
32
+ @if $prefix {
33
+ $class: "#{$prefix}-#{$suffix}";
34
+ } @else {
35
+ $class: "#{$suffix}";
36
+ }
37
+
38
+ // CSS class names cannot start with a digit.
39
+ // When the breakpoint key begins with a number (e.g. "2xl"),
40
+ // escape it using the CSS identifier-escape syntax: \3X (space after hex).
41
+ $first: string.slice("#{$bp-key}", 1, 1);
42
+ $rest: string.slice("#{$bp-key}", 2);
43
+ $safe-bp: null;
44
+ @if $first == "0" or $first == "1" or $first == "2" or $first == "3" or
45
+ $first == "4" or $first == "5" or $first == "6" or $first == "7" or
46
+ $first == "8" or $first == "9" {
47
+ // \3X is the CSS escape for the digit (space terminates the escape)
48
+ $safe-bp: "\\3#{$first} #{$rest}";
49
+ } @else {
50
+ $safe-bp: "#{$bp-key}";
51
+ }
52
+
53
+ // Use #{} interpolation so Sass emits the selector verbatim
54
+ // without re-parsing the leading backslash as a Sass identifier.
55
+ @at-root .#{$safe-bp}\:#{$class} {
56
+ #{$prop}: $value;
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,40 @@
1
+ // responsive/_fluid-type.scss
2
+ // Fluid / clamp()-based responsive typography scale.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:math";
6
+ @use "../functions/math" as mathfn;
7
+
8
+ // Fluid type scale — font sizes that scale smoothly between two viewport widths.
9
+ // Uses clamp() so no media queries are needed.
10
+ // Usage in component SCSS:
11
+ // @use "@mastors/core/api" as m;
12
+ // font-size: m.fluid-type(1rem, 1.5rem);
13
+
14
+ /// Fluid type mixin: applies a clamp()-based fluid font-size
15
+ /// @param {Number} $min-size - minimum font size (rem)
16
+ /// @param {Number} $max-size - maximum font size (rem)
17
+ /// @param {Number} $min-vw - viewport at which min applies (px, default 320px)
18
+ /// @param {Number} $max-vw - viewport at which max applies (px, default 1280px)
19
+ @mixin apply-fluid-type($min-size, $max-size, $min-vw: 320px, $max-vw: 1280px) {
20
+ font-size: mathfn.fluid($min-size, $max-size, $min-vw, $max-vw);
21
+ }
22
+
23
+ /// Fluid type function — for direct use in property values
24
+ /// @return {String} clamp() expression
25
+ @function fluid-type($min-size, $max-size, $min-vw: 320px, $max-vw: 1280px) {
26
+ @return mathfn.fluid($min-size, $max-size, $min-vw, $max-vw);
27
+ }
28
+
29
+ // Predefined fluid heading scale (opt-in)
30
+ // Include with: @use "@mastors/core/scss/responsive/fluid-type" as ft;
31
+ // @include ft.fluid-scale();
32
+ @mixin fluid-scale {
33
+ h1 { @include apply-fluid-type(2rem, 3.75rem); }
34
+ h2 { @include apply-fluid-type(1.5rem, 3rem); }
35
+ h3 { @include apply-fluid-type(1.25rem, 2.25rem); }
36
+ h4 { @include apply-fluid-type(1.125rem, 1.875rem); }
37
+ h5 { @include apply-fluid-type(1rem, 1.5rem); }
38
+ h6 { @include apply-fluid-type(0.875rem, 1.25rem); }
39
+ p { @include apply-fluid-type(0.875rem, 1.125rem); }
40
+ }
@@ -0,0 +1,6 @@
1
+ // responsive/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "engine";
5
+ @forward "container-queries";
6
+ @forward "fluid-type";