@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,9 @@
1
+ // abstracts/_maps.scss
2
+ // Shared SCSS maps used across the Mastors ecosystem.
3
+ // ─────────────────────────────────────────────────────────────
4
+ // INTENTIONAL STUB — this file is reserved for shared utility maps that
5
+ // do not belong in tokens/ or variables/. It is deliberately empty at v1.0.
6
+ // Add maps here when they are:
7
+ // - Consumed by 3+ unrelated files across packages
8
+ // - Not a design token (those live in tokens/)
9
+ // - Not a layout variable (those live in variables/)
@@ -0,0 +1,7 @@
1
+ // abstracts/_placeholders.scss
2
+ // Shared silent SCSS placeholder selectors (%placeholder).
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Package-scoped placeholders live in their own partials (e.g. helpers/_visually-hidden.scss).
6
+ // Add cross-cutting placeholders here when they are shared by 3+ unrelated files.
7
+
@@ -0,0 +1,21 @@
1
+ // accessibility/_focus.scss
2
+ // Focus ring and keyboard navigation styles.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Focus ring — respects browser defaults, enhances with custom ring.
6
+ // Custom property --mastors-color-primary-500 is emitted by base/_root.scss
7
+ // via the nested emit-nested-custom-properties() generator, which produces
8
+ // --mastors-color-primary-{shade} for every shade in $color-tokens.
9
+ // The hardcoded fallback #3b82f6 (primary-500) fires only in environments
10
+ // where @mastors/core's :root block has not been loaded (e.g. partial imports).
11
+
12
+ :focus-visible {
13
+ outline: 2px solid var(--mastors-color-primary-500, #3b82f6);
14
+ outline-offset: 2px;
15
+ border-radius: 2px;
16
+ }
17
+
18
+ // Remove focus ring for mouse users
19
+ :focus:not(:focus-visible) {
20
+ outline: none;
21
+ }
@@ -0,0 +1,7 @@
1
+ // accessibility/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "focus";
5
+ @forward "motion";
6
+ @forward "screen-reader";
7
+ @forward "print";
@@ -0,0 +1,14 @@
1
+ // accessibility/_motion.scss
2
+ // Reduced motion preferences and safe animation overrides.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Respect user motion preferences — disable animations for users who request it.
6
+
7
+ @media (prefers-reduced-motion: reduce) {
8
+ *, *::before, *::after {
9
+ animation-duration: 0.01ms !important;
10
+ animation-iteration-count: 1 !important;
11
+ transition-duration: 0.01ms !important;
12
+ scroll-behavior: auto !important;
13
+ }
14
+ }
@@ -0,0 +1,52 @@
1
+ // accessibility/_print.scss
2
+ // Print-specific utilities and media query helpers.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Hide from print
6
+ .print\:hidden {
7
+ @media print { display: none !important; }
8
+ }
9
+
10
+ // Show only in print
11
+ .screen\:hidden {
12
+ @media not print { display: none !important; }
13
+ }
14
+
15
+ @media print {
16
+ // Avoid page breaks inside these elements by default
17
+ .print\:break-inside-avoid {
18
+ break-inside: avoid;
19
+ page-break-inside: avoid;
20
+ }
21
+
22
+ // Force page break before
23
+ .print\:break-before {
24
+ break-before: page;
25
+ page-break-before: always;
26
+ }
27
+
28
+ // Force page break after
29
+ .print\:break-after {
30
+ break-after: page;
31
+ page-break-after: always;
32
+ }
33
+
34
+ // Print-safe color override (ensure text is black on white)
35
+ .print\:text-black { color: #000 !important; }
36
+ .print\:bg-white { background: #fff !important; }
37
+ .print\:border-none { border: none !important; }
38
+ .print\:shadow-none { box-shadow: none !important; }
39
+
40
+ // Expand truncated links for print readers
41
+ a[href]::after {
42
+ content: " (" attr(href) ")";
43
+ font-size: 0.75em;
44
+ color: #555;
45
+ }
46
+
47
+ // Don't expand hash or JS links
48
+ a[href^="#"]::after,
49
+ a[href^="javascript:"]::after {
50
+ content: "";
51
+ }
52
+ }
@@ -0,0 +1,31 @@
1
+ // accessibility/_screen-reader.scss
2
+ // Screen-reader-only utility — canonical single source of truth.
3
+ // ─────────────────────────────────────────────────────────────
4
+ // .sr-only / .not-sr-only are the primary class names (modern standard).
5
+ // Legacy aliases (.visually-hidden, .vh, .visually-hidden-focusable)
6
+ // are provided in helpers/_visually-hidden.scss and share these rules.
7
+
8
+ // Screen reader only — visually hidden but announced by screen readers
9
+ .sr-only {
10
+ position: absolute;
11
+ width: 1px;
12
+ height: 1px;
13
+ padding: 0;
14
+ margin: -1px;
15
+ overflow: hidden;
16
+ clip: rect(0, 0, 0, 0);
17
+ white-space: nowrap;
18
+ border-width: 0;
19
+ }
20
+
21
+ // Undo sr-only — make visible again
22
+ .not-sr-only {
23
+ position: static;
24
+ width: auto;
25
+ height: auto;
26
+ padding: 0;
27
+ margin: 0;
28
+ overflow: visible;
29
+ clip: auto;
30
+ white-space: normal;
31
+ }
@@ -0,0 +1,14 @@
1
+ // api/_index.scss
2
+ // Public SCSS API — the surface that downstream packages @use.
3
+ // ─────────────────────────────────────────────────────────────
4
+ // Consumers: @use "@mastors/core/api" as m;
5
+ // This file exposes only what is intended to be public API.
6
+ // Internal implementation files are NOT forwarded here.
7
+ // ─────────────────────────────────────────────────────────────
8
+
9
+ @forward "../functions/index";
10
+ @forward "../mixins/index";
11
+ @forward "../tokens/index";
12
+ @forward "../variables/index";
13
+ @forward "../config/index";
14
+ @forward "../responsive/container-queries";
@@ -0,0 +1,6 @@
1
+ // base/_box-sizing.scss
2
+ // INTENTIONALLY EMPTY — box-sizing: border-box is declared in _reset.scss.
3
+ // This file is retained as a named slot so downstream packages and build
4
+ // tooling that reference the path continue to resolve without error.
5
+ // Do not add declarations here.
6
+ // ─────────────────────────────────────────────────────────────
@@ -0,0 +1,7 @@
1
+ // base/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+
4
+ @forward "reset";
5
+ @forward "root";
6
+ @forward "box-sizing";
7
+ @forward "typography-base";
@@ -0,0 +1,59 @@
1
+ // base/_reset.scss
2
+ // Modern CSS reset / normalization layer.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // Modern CSS reset — opinionated, minimal, predictable.
6
+
7
+ *, *::before, *::after {
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ }
15
+
16
+ html {
17
+ text-size-adjust: 100%;
18
+ tab-size: 4;
19
+ scroll-behavior: smooth;
20
+ }
21
+
22
+ body {
23
+ line-height: inherit;
24
+ -webkit-font-smoothing: antialiased;
25
+ -moz-osx-font-smoothing: grayscale;
26
+ }
27
+
28
+ img, picture, video, canvas, svg {
29
+ display: block;
30
+ max-width: 100%;
31
+ }
32
+
33
+ input, button, textarea, select {
34
+ font: inherit;
35
+ }
36
+
37
+ p, h1, h2, h3, h4, h5, h6 {
38
+ overflow-wrap: break-word;
39
+ }
40
+
41
+ ol, ul {
42
+ list-style: none;
43
+ }
44
+
45
+ a {
46
+ color: inherit;
47
+ text-decoration: inherit;
48
+ }
49
+
50
+ table {
51
+ border-collapse: collapse;
52
+ border-spacing: 0;
53
+ }
54
+
55
+ button, [role="button"] {
56
+ cursor: pointer;
57
+ }
58
+
59
+ [hidden] { display: none !important; }
@@ -0,0 +1,43 @@
1
+ // base/_root.scss
2
+ // :root CSS custom property declarations.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "../tokens/color" as ct;
6
+ @use "../tokens/spacing" as sp;
7
+ @use "../tokens/typography" as ty;
8
+ @use "../tokens/shadows" as sh;
9
+ @use "../tokens/radii" as ra;
10
+ @use "../tokens/transitions" as tr;
11
+ @use "../tokens/z-index" as zi;
12
+ @use "../tokens/opacity" as op;
13
+ @use "../generators/custom-property-generator" as gen;
14
+
15
+ :root {
16
+ // Color tokens — nested emit (primary-50, primary-100 …)
17
+ @include gen.emit-nested-custom-properties(ct.$color-tokens, "mastors-color");
18
+
19
+ // Spacing
20
+ @include gen.emit-custom-properties(sp.$spacing-tokens, "mastors-spacing");
21
+
22
+ // Typography
23
+ @include gen.emit-custom-properties(ty.$font-size-tokens, "mastors-font-size");
24
+ @include gen.emit-custom-properties(ty.$font-weight-tokens, "mastors-font-weight");
25
+ @include gen.emit-custom-properties(ty.$line-height-tokens, "mastors-leading");
26
+ @include gen.emit-custom-properties(ty.$letter-spacing-tokens, "mastors-tracking");
27
+
28
+ // Radii
29
+ @include gen.emit-custom-properties(ra.$radius-tokens, "mastors-radius");
30
+
31
+ // Shadows
32
+ @include gen.emit-custom-properties(sh.$shadow-tokens, "mastors-shadow");
33
+
34
+ // Transitions
35
+ @include gen.emit-custom-properties(tr.$duration-tokens, "mastors-duration");
36
+ @include gen.emit-custom-properties(tr.$easing-tokens, "mastors-easing");
37
+
38
+ // Z-index
39
+ @include gen.emit-custom-properties(zi.$z-index-tokens, "mastors-z");
40
+
41
+ // Opacity
42
+ @include gen.emit-custom-properties(op.$opacity-tokens, "mastors-opacity");
43
+ }
@@ -0,0 +1,40 @@
1
+ // base/_typography-base.scss
2
+ // Base element typography (html, body, headings, p, a, etc.)
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "../variables/global" as vars;
6
+ @use "../tokens/typography" as ty;
7
+
8
+ html {
9
+ font-size: vars.$base-font-size;
10
+ line-height: vars.$base-line-height;
11
+ font-family: vars.$base-font-family;
12
+ color: var(--mastors-text);
13
+ background-color: var(--mastors-bg);
14
+ }
15
+
16
+ body {
17
+ font-size: ty.font-size("base");
18
+ font-weight: ty.font-weight("normal");
19
+ }
20
+
21
+ h1, h2, h3, h4, h5, h6 {
22
+ font-weight: ty.font-weight("semibold");
23
+ line-height: ty.line-height("tight");
24
+ }
25
+
26
+ h1 { font-size: ty.font-size("4xl"); }
27
+ h2 { font-size: ty.font-size("3xl"); }
28
+ h3 { font-size: ty.font-size("2xl"); }
29
+ h4 { font-size: ty.font-size("xl"); }
30
+ h5 { font-size: ty.font-size("lg"); }
31
+ h6 { font-size: ty.font-size("base"); }
32
+
33
+ p { line-height: ty.line-height("relaxed"); }
34
+
35
+ small { font-size: ty.font-size("sm"); }
36
+
37
+ code, kbd, samp, pre {
38
+ font-family: ty.font-family("mono");
39
+ font-size: ty.font-size("sm");
40
+ }
@@ -0,0 +1,13 @@
1
+ // config/_flags.scss
2
+ // Boolean feature flags to tree-shake generated output.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ $enable-flexer: true !default;
6
+ $enable-gridder: true !default;
7
+ $enable-typography: true !default;
8
+ $enable-themes: true !default;
9
+ $enable-animator: true !default;
10
+ $enable-responsive: true !default;
11
+ $enable-utilities: true !default;
12
+ $enable-helpers: true !default;
13
+ $enable-a11y: true !default;
@@ -0,0 +1,12 @@
1
+ // config/_index.scss
2
+ // Public config surface — forward both partials so downstream
3
+ // consumers can reach flags and settings via the public API.
4
+ // ─────────────────────────────────────────────────────────────
5
+ // Usage (downstream):
6
+ // @use "@mastors/core/api" as m;
7
+ // $dark: m.$enable-themes; // from flags
8
+ // $pfx: m.config("prefix"); // from settings
9
+ // ─────────────────────────────────────────────────────────────
10
+
11
+ @forward "settings";
12
+ @forward "flags";
@@ -0,0 +1,18 @@
1
+ // config/_settings.scss
2
+ // Master feature flags and global configuration map.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ // @use must come before everything else
6
+ @use "sass:map";
7
+
8
+ $mastors-config: (
9
+ "prefix": "",
10
+ "important": false,
11
+ "dark-mode": "class",
12
+ "rtl": false,
13
+ ) !default;
14
+
15
+ // Convenience accessors
16
+ @function config($key) {
17
+ @return map.get($mastors-config, $key);
18
+ }
@@ -0,0 +1,66 @@
1
+ // functions/_color.scss
2
+ // Color manipulation and derivation functions.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:color";
6
+ @use "sass:list";
7
+ @use "sass:math";
8
+ @use "../tokens/color" as ct;
9
+
10
+ /// Mix a color with white
11
+ @function tint($c, $pct: 10%) {
12
+ @return color.mix(white, $c, $pct);
13
+ }
14
+
15
+ /// Mix a color with black
16
+ @function shade($c, $pct: 10%) {
17
+ @return color.mix(black, $c, $pct);
18
+ }
19
+
20
+ /// Adjust a color's alpha channel
21
+ @function alpha($c, $a) {
22
+ @return color.adjust($c, $alpha: $a - 1);
23
+ }
24
+
25
+ /// Return black or white for maximum contrast against $bg.
26
+ @function contrast($bg, $light: white, $dark: black) {
27
+ $luminance: 0.2126 * color.channel($bg, "red", $space: rgb) / 255
28
+ + 0.7152 * color.channel($bg, "green", $space: rgb) / 255
29
+ + 0.0722 * color.channel($bg, "blue", $space: rgb) / 255;
30
+ @if $luminance > 0.35 {
31
+ @return $dark;
32
+ } @else {
33
+ @return $light;
34
+ }
35
+ }
36
+
37
+ /// Quick palette accessor — shorthand for ct.color()
38
+ @function palette($name, $shade: null) {
39
+ @return ct.color($name, $shade);
40
+ }
41
+
42
+ /// Emit a color as rgb() with optional opacity.
43
+ @function rgb-color($name, $shade, $opacity: 1) {
44
+ $c: ct.color($name, $shade);
45
+ @if $opacity == 1 { @return $c; }
46
+ $r: color.channel($c, "red", $space: rgb);
47
+ $g: color.channel($c, "green", $space: rgb);
48
+ $b: color.channel($c, "blue", $space: rgb);
49
+ @return rgb($r $g $b / $opacity);
50
+ }
51
+
52
+ /// Create a stepped tint/shade ramp on the fly.
53
+ @function color-ramp($base, $steps: 5, $dir: "tint") {
54
+ $result: ();
55
+ @for $i from 1 through $steps {
56
+ $pct: math.div($i * 100%, $steps + 1);
57
+ $step: null;
58
+ @if $dir == "tint" {
59
+ $step: tint($base, $pct);
60
+ } @else {
61
+ $step: shade($base, $pct);
62
+ }
63
+ $result: list.append($result, $step, comma);
64
+ }
65
+ @return $result;
66
+ }
@@ -0,0 +1,28 @@
1
+ // functions/_em.scss
2
+ // px → em conversion function.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:math";
6
+ @use "../variables/global" as vars;
7
+
8
+ /// Convert px to em relative to a given context
9
+ /// @param {Number} $px - pixel value
10
+ /// @param {Number} $context - context font size in px (default: base)
11
+ /// @return {Number} em value
12
+ @function em($px, $context: vars.$base-font-size) {
13
+ $base: null;
14
+ @if math.compatible($px, 1px) {
15
+ $base: math.div($px, 1px);
16
+ } @else {
17
+ $base: $px;
18
+ }
19
+
20
+ $ctx: null;
21
+ @if math.compatible($context, 1px) {
22
+ $ctx: math.div($context, 1px);
23
+ } @else {
24
+ $ctx: $context;
25
+ }
26
+
27
+ @return math.div($base, $ctx) * 1em;
28
+ }
@@ -0,0 +1,15 @@
1
+ // functions/_index.scss
2
+ // ─────────────────────────────────────────────────────────────
3
+ // NOTE: _vars.scss is intentionally NOT forwarded here.
4
+ // _string.scss already defines vars() and vars-or().
5
+ // _vars.scss defines a single-token vars($token, $fallback) variant
6
+ // under a different signature — forwarding both causes a "two modules
7
+ // define vars" conflict. Consumers who need the _vars.scss variant
8
+ // should @use it directly.
9
+
10
+ @forward "color";
11
+ @forward "math";
12
+ @forward "string";
13
+ @forward "map-helpers";
14
+ @forward "rem";
15
+ @forward "em";
@@ -0,0 +1,29 @@
1
+ // functions/_map-helpers.scss
2
+ // Deep map access, merge, and utility functions.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:map";
6
+ @use "sass:list";
7
+ @use "sass:meta";
8
+
9
+ /// Deep map get — map.get() for nested maps
10
+ /// Usage: map-deep-get($map, "key1", "key2")
11
+ @function map-deep-get($map, $keys...) {
12
+ $result: $map;
13
+ @each $key in $keys {
14
+ @if meta.type-of($result) != map {
15
+ @error "map-deep-get: expected a map at key '#{$key}', got #{meta.type-of($result)}";
16
+ }
17
+ $result: map.get($result, $key);
18
+ }
19
+ @return $result;
20
+ }
21
+
22
+ /// Merge multiple maps into one (shallow)
23
+ @function map-collect($maps...) {
24
+ $result: ();
25
+ @each $m in $maps {
26
+ $result: map.merge($result, $m);
27
+ }
28
+ @return $result;
29
+ }
@@ -0,0 +1,40 @@
1
+ // functions/_math.scss
2
+ // Math utility functions (clamp, fluid scaling, etc.)
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:math";
6
+
7
+ /// Clamp a value between min and max
8
+ @function clamp-value($min, $val, $max) {
9
+ @return clamp(#{$min}, #{$val}, #{$max});
10
+ }
11
+
12
+ /// Fluid value: scales linearly between two sizes across two viewport widths
13
+ /// @param {Number} $min-val - minimum output value (rem)
14
+ /// @param {Number} $max-val - maximum output value (rem)
15
+ /// @param {Number} $min-vw - viewport at which minimum applies (px)
16
+ /// @param {Number} $max-vw - viewport at which maximum applies (px)
17
+ @function fluid($min-val, $max-val, $min-vw: 320px, $max-vw: 1280px) {
18
+ $slope: math.div($max-val - $min-val, $max-vw - $min-vw);
19
+ $intercept: $min-val - $slope * $min-vw;
20
+ @return clamp(#{$min-val}, #{$slope * 100vw} + #{$intercept}, #{$max-val});
21
+ }
22
+
23
+ /// Strip the unit from a number: strip-unit(16px) → 16
24
+ @function strip-unit($number) {
25
+ @return math.div($number, ($number * 0 + 1));
26
+ }
27
+
28
+ /// Round to N decimal places: round-to(3.14159, 2) → 3.14
29
+ @function round-to($number, $decimals: 2) {
30
+ $n: math.pow(10, $decimals);
31
+ @return math.div(math.round($number * $n), $n);
32
+ }
33
+
34
+ /// Linear interpolation between two values
35
+ /// @param {Number} $a - start value
36
+ /// @param {Number} $b - end value
37
+ /// @param {Number} $t - interpolation factor (0–1)
38
+ @function lerp($a, $b, $t) {
39
+ @return $a + ($b - $a) * $t;
40
+ }
@@ -0,0 +1,27 @@
1
+ // functions/_rem.scss
2
+ // px → rem conversion function.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:math";
6
+ @use "../variables/global" as vars;
7
+
8
+ /// Convert px to rem using the base font size
9
+ /// @param {Number} $px - pixel value (unitless or px)
10
+ /// @return {Number} rem value
11
+ @function rem($px) {
12
+ $base: 0;
13
+ @if math.compatible($px, 1px) {
14
+ $base: math.div($px, 1px);
15
+ } @else {
16
+ $base: $px;
17
+ }
18
+
19
+ $root: 0;
20
+ @if math.compatible(vars.$base-font-size, 1px) {
21
+ $root: math.div(vars.$base-font-size, 1px);
22
+ } @else {
23
+ $root: vars.$base-font-size;
24
+ }
25
+
26
+ @return math.div($base, $root) * 1rem;
27
+ }
@@ -0,0 +1,57 @@
1
+ // functions/_string.scss
2
+ // String manipulation functions.
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ @use "sass:string";
6
+ @use "sass:list";
7
+
8
+ /// Replace all occurrences of $search in $string with $replace
9
+ @function str-replace($string, $search, $replace: "") {
10
+ $index: string.index($string, $search);
11
+ @if $index {
12
+ @return string.slice($string, 1, $index - 1)
13
+ + $replace
14
+ + str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
15
+ }
16
+ @return $string;
17
+ }
18
+
19
+ /// Convert any value to a string
20
+ @function to-string($value) {
21
+ @return #{$value};
22
+ }
23
+
24
+ /// Reference any design token as a CSS custom property (var()).
25
+ /// Builds the --mastors-{category}-{keys...} expression at zero runtime cost.
26
+ ///
27
+ /// Usage:
28
+ /// color: vars(color, primary, 500); → var(--mastors-color-primary-500)
29
+ /// padding: vars(spacing, 4); → var(--mastors-spacing-4)
30
+ /// border-radius: vars(radius, lg); → var(--mastors-radius-lg)
31
+ /// transition-duration:vars(duration, 200); → var(--mastors-duration-200)
32
+ /// z-index: vars(z, modal); → var(--mastors-z-modal)
33
+ /// box-shadow: vars(shadow, md); → var(--mastors-shadow-md)
34
+ ///
35
+ /// @param {String} $category - Token category prefix (color, spacing, radius…)
36
+ /// @param {ArgList} $keys - One or more path segments
37
+ /// @return {String} - CSS var() expression
38
+ @function vars($category, $keys...) {
39
+ $prop: "--mastors-#{$category}";
40
+ @each $key in $keys {
41
+ $prop: "#{$prop}-#{$key}";
42
+ }
43
+ @return var(#{$prop});
44
+ }
45
+
46
+ /// vars() with a fallback value.
47
+ /// Usage: color: vars-or(color, #3b82f6, primary, 500);
48
+ /// @param {String} $category - Token category prefix
49
+ /// @param {*} $fallback - Fallback value if custom property is not set
50
+ /// @param {ArgList} $keys - Path segments
51
+ @function vars-or($category, $fallback, $keys...) {
52
+ $prop: "--mastors-#{$category}";
53
+ @each $key in $keys {
54
+ $prop: "#{$prop}-#{$key}";
55
+ }
56
+ @return var(#{$prop}, #{$fallback});
57
+ }