@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.
- package/LICENSE +21 -0
- package/README.md +940 -0
- package/api/_index.scss +5 -0
- package/dist/mastors-core.css +7419 -0
- package/dist/mastors-core.css.map +1 -0
- package/package.json +73 -0
- package/postinstall.js +41 -0
- package/scripts/generate-tokens.js +259 -0
- package/scss/abstracts/_index.scss +6 -0
- package/scss/abstracts/_maps.scss +9 -0
- package/scss/abstracts/_placeholders.scss +7 -0
- package/scss/accessibility/_focus.scss +21 -0
- package/scss/accessibility/_index.scss +7 -0
- package/scss/accessibility/_motion.scss +14 -0
- package/scss/accessibility/_print.scss +52 -0
- package/scss/accessibility/_screen-reader.scss +31 -0
- package/scss/api/_index.scss +14 -0
- package/scss/base/_box-sizing.scss +6 -0
- package/scss/base/_index.scss +7 -0
- package/scss/base/_reset.scss +59 -0
- package/scss/base/_root.scss +43 -0
- package/scss/base/_typography-base.scss +40 -0
- package/scss/config/_flags.scss +13 -0
- package/scss/config/_index.scss +12 -0
- package/scss/config/_settings.scss +18 -0
- package/scss/functions/_color.scss +66 -0
- package/scss/functions/_em.scss +28 -0
- package/scss/functions/_index.scss +15 -0
- package/scss/functions/_map-helpers.scss +29 -0
- package/scss/functions/_math.scss +40 -0
- package/scss/functions/_rem.scss +27 -0
- package/scss/functions/_string.scss +57 -0
- package/scss/functions/_vars.scss +49 -0
- package/scss/generators/_class-generator.scss +83 -0
- package/scss/generators/_custom-property-generator.scss +29 -0
- package/scss/generators/_index.scss +6 -0
- package/scss/generators/_responsive-generator.scss +28 -0
- package/scss/helpers/_clearfix.scss +9 -0
- package/scss/helpers/_index.scss +7 -0
- package/scss/helpers/_ratio.scss +22 -0
- package/scss/helpers/_truncate.scss +25 -0
- package/scss/helpers/_visually-hidden.scss +39 -0
- package/scss/index.scss +41 -0
- package/scss/mixins/_breakpoint.scss +33 -0
- package/scss/mixins/_container.scss +20 -0
- package/scss/mixins/_elevation.scss +12 -0
- package/scss/mixins/_index.scss +9 -0
- package/scss/mixins/_pseudo.scss +13 -0
- package/scss/mixins/_theme.scss +31 -0
- package/scss/mixins/_transition.scss +20 -0
- package/scss/responsive/_container-queries.scss +31 -0
- package/scss/responsive/_engine.scss +65 -0
- package/scss/responsive/_fluid-type.scss +40 -0
- package/scss/responsive/_index.scss +6 -0
- package/scss/semantic/_colors.scss +29 -0
- package/scss/semantic/_index.scss +6 -0
- package/scss/semantic/_spacing.scss +13 -0
- package/scss/semantic/_typography.scss +13 -0
- package/scss/themes/_base-theme.scss +28 -0
- package/scss/themes/_dark.scss +59 -0
- package/scss/themes/_index.scss +6 -0
- package/scss/themes/_light.scss +31 -0
- package/scss/tokens/_color.scss +100 -0
- package/scss/tokens/_index.scss +12 -0
- package/scss/tokens/_opacity.scss +28 -0
- package/scss/tokens/_radii.scss +21 -0
- package/scss/tokens/_shadows.scss +20 -0
- package/scss/tokens/_sizing.scss +47 -0
- package/scss/tokens/_spacing.scss +48 -0
- package/scss/tokens/_transitions.scss +27 -0
- package/scss/tokens/_typography.scss +63 -0
- package/scss/tokens/_z-index.scss +21 -0
- package/scss/utilities/_animation.scss +125 -0
- package/scss/utilities/_borders.scss +55 -0
- package/scss/utilities/_colors.scss +42 -0
- package/scss/utilities/_cursor.scss +28 -0
- package/scss/utilities/_display.scss +26 -0
- package/scss/utilities/_index.scss +20 -0
- package/scss/utilities/_interaction.scss +156 -0
- package/scss/utilities/_layout.scss +162 -0
- package/scss/utilities/_opacity.scss +9 -0
- package/scss/utilities/_overflow.scss +36 -0
- package/scss/utilities/_pointer-events.scss +6 -0
- package/scss/utilities/_position.scss +32 -0
- package/scss/utilities/_shadows.scss +11 -0
- package/scss/utilities/_sizing.scss +40 -0
- package/scss/utilities/_spacing.scss +42 -0
- package/scss/utilities/_transform.scss +43 -0
- package/scss/utilities/_typography.scss +163 -0
- package/scss/utilities/_z-index.scss +9 -0
- package/scss/variables/_breakpoints.scss +14 -0
- package/scss/variables/_container.scss +13 -0
- package/scss/variables/_global.scss +8 -0
- package/scss/variables/_grid.scss +7 -0
- package/scss/variables/_index.scss +7 -0
- 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,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,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
|
+
}
|