@mastors/core 1.1.0 → 2.0.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/README.md +12 -121
- package/dist/mastors-core.css +62 -1615
- package/dist/mastors-core.css.map +1 -1
- package/package.json +6 -8
- package/scss/abstracts/_maps.scss +9 -0
- package/scss/accessibility/_index.scss +0 -1
- package/scss/accessibility/_screen-reader.scss +1 -4
- package/scss/api/_index.scss +0 -1
- package/scss/base/_reset.scss +1 -1
- package/scss/config/_flags.scss +9 -9
- package/scss/functions/_color.scss +15 -32
- package/scss/functions/_em.scss +2 -2
- package/scss/functions/_index.scss +0 -6
- package/scss/functions/_math.scss +0 -19
- package/scss/functions/_string.scss +0 -35
- package/scss/generators/_class-generator.scss +42 -31
- package/scss/generators/_responsive-generator.scss +4 -0
- package/scss/helpers/_visually-hidden.scss +14 -27
- package/scss/mixins/_breakpoint.scss +3 -3
- package/scss/mixins/_transition.scss +1 -1
- package/scss/responsive/_engine.scss +5 -3
- package/scss/responsive/_fluid-type.scss +9 -8
- package/scss/semantic/_colors.scss +15 -15
- package/scss/semantic/_spacing.scss +5 -5
- package/scss/semantic/_typography.scss +5 -5
- package/scss/themes/_base-theme.scss +5 -0
- package/scss/themes/_dark.scss +7 -8
- package/scss/tokens/_color.scss +4 -8
- package/scss/tokens/_shadows.scss +9 -7
- package/scss/tokens/_sizing.scss +6 -3
- package/scss/tokens/_typography.scss +10 -9
- package/scss/utilities/_borders.scss +6 -4
- package/scss/utilities/_colors.scss +1 -1
- package/scss/utilities/_index.scss +0 -4
- package/scss/utilities/_sizing.scss +2 -2
- package/scss/variables/_global.scss +4 -4
- package/scss/variables/_grid.scss +3 -3
- package/scss/vendors/_index.scss +2 -0
- package/src/index.ts +11 -0
- package/src/tokens.ts +314 -0
- package/src/types.ts +52 -0
- package/postinstall.js +0 -41
- package/scripts/generate-tokens.js +0 -259
- package/scss/accessibility/_print.scss +0 -52
- package/scss/config/_index.scss +0 -12
- package/scss/functions/_vars.scss +0 -49
- package/scss/utilities/_animation.scss +0 -125
- package/scss/utilities/_interaction.scss +0 -156
- package/scss/utilities/_layout.scss +0 -162
- package/scss/utilities/_typography.scss +0 -163
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// scripts/generate-tokens.js
|
|
3
|
-
// ─────────────────────────────────────────────────────────────
|
|
4
|
-
// Reads SCSS token map files and regenerates src/tokens.ts so
|
|
5
|
-
// the TypeScript token mirror never drifts from the SCSS source.
|
|
6
|
-
//
|
|
7
|
-
// Run: node scripts/generate-tokens.js
|
|
8
|
-
// Auto: called by `node build.js` before tsc (see build.js)
|
|
9
|
-
// ─────────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
'use strict'
|
|
12
|
-
|
|
13
|
-
const fs = require('fs')
|
|
14
|
-
const path = require('path')
|
|
15
|
-
|
|
16
|
-
const TOKENS_DIR = path.join(__dirname, '..', 'scss', 'tokens')
|
|
17
|
-
const OUT_FILE = path.join(__dirname, '..', 'src', 'tokens.ts')
|
|
18
|
-
|
|
19
|
-
// ── Helpers ──────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
/** Extract all $map-name: ( ... ) blocks from a SCSS string */
|
|
22
|
-
function extractMaps(scss) {
|
|
23
|
-
const maps = {}
|
|
24
|
-
const mapRe = /\$([a-z][a-z0-9-]*)\s*:\s*\(/g
|
|
25
|
-
let match
|
|
26
|
-
while ((match = mapRe.exec(scss)) !== null) {
|
|
27
|
-
const varName = match[1]
|
|
28
|
-
let depth = 1
|
|
29
|
-
let i = match.index + match[0].length
|
|
30
|
-
let inner = ''
|
|
31
|
-
while (i < scss.length && depth > 0) {
|
|
32
|
-
if (scss[i] === '(') depth++
|
|
33
|
-
else if (scss[i] === ')') depth--
|
|
34
|
-
if (depth > 0) inner += scss[i]
|
|
35
|
-
i++
|
|
36
|
-
}
|
|
37
|
-
maps[varName] = parseMap(inner)
|
|
38
|
-
}
|
|
39
|
-
return maps
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Parse a flat SCSS map body into a JS object (string keys → string values) */
|
|
43
|
-
function parseMap(body) {
|
|
44
|
-
const result = {}
|
|
45
|
-
const lines = body.split('\n')
|
|
46
|
-
for (const raw of lines) {
|
|
47
|
-
const line = raw.trim().replace(/,$/, '').replace(/\/\/.*$/, '').trim()
|
|
48
|
-
if (!line || line.startsWith('(') || line.endsWith('(')) continue
|
|
49
|
-
const colonIdx = line.indexOf(':')
|
|
50
|
-
if (colonIdx === -1) continue
|
|
51
|
-
const rawKey = line.slice(0, colonIdx).trim().replace(/^["']|["']$/g, '')
|
|
52
|
-
const rawVal = line.slice(colonIdx + 1).trim()
|
|
53
|
-
if (!rawKey || !rawVal) continue
|
|
54
|
-
// Unescape SCSS key escapes: "0\\.5" → "0.5", "1\\/2" → "1/2"
|
|
55
|
-
const key = rawKey.replace(/\\\\?\./g, '.').replace(/\\\\?\//g, '/')
|
|
56
|
-
result[key] = rawVal
|
|
57
|
-
}
|
|
58
|
-
return result
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Parse nested color map ($color-tokens with sub-palettes) */
|
|
62
|
-
function extractNestedColorMap(scss) {
|
|
63
|
-
const palettes = {}
|
|
64
|
-
const paletteRe = /"([a-z]+)"\s*:\s*\(([\s\S]*?)\),/g
|
|
65
|
-
let m
|
|
66
|
-
while ((m = paletteRe.exec(scss)) !== null) {
|
|
67
|
-
const name = m[1]
|
|
68
|
-
const inner = m[2]
|
|
69
|
-
if (inner.includes(':')) {
|
|
70
|
-
palettes[name] = parseMap(inner)
|
|
71
|
-
} else {
|
|
72
|
-
palettes[name] = inner.trim()
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// flat top-level entries (white, black, transparent)
|
|
76
|
-
const flatRe = /"(white|black|transparent)"\s*:\s*([^,\n]+)/g
|
|
77
|
-
while ((m = flatRe.exec(scss)) !== null) {
|
|
78
|
-
palettes[m[1]] = m[2].trim().replace(/,$/, '')
|
|
79
|
-
}
|
|
80
|
-
return palettes
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ── Read token files ──────────────────────────────────────────
|
|
84
|
-
|
|
85
|
-
function readScss(filename) {
|
|
86
|
-
return fs.readFileSync(path.join(TOKENS_DIR, filename), 'utf8')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const colorScss = readScss('_color.scss')
|
|
90
|
-
const spacingScss = readScss('_spacing.scss')
|
|
91
|
-
const typographyScss = readScss('_typography.scss')
|
|
92
|
-
const shadowsScss = readScss('_shadows.scss')
|
|
93
|
-
const radiiScss = readScss('_radii.scss')
|
|
94
|
-
const transitionsScss = readScss('_transitions.scss')
|
|
95
|
-
const zIndexScss = readScss('_z-index.scss')
|
|
96
|
-
const opacityScss = readScss('_opacity.scss')
|
|
97
|
-
const sizingScss = readScss('_sizing.scss')
|
|
98
|
-
|
|
99
|
-
const colorMap = extractNestedColorMap(colorScss)
|
|
100
|
-
const spacingMap = extractMaps(spacingScss)['spacing-tokens'] || {}
|
|
101
|
-
const fontSizeMap = extractMaps(typographyScss)['font-size-tokens'] || {}
|
|
102
|
-
const fontFamilyMap = extractMaps(typographyScss)['font-family-tokens'] || {}
|
|
103
|
-
const fontWeightMap = extractMaps(typographyScss)['font-weight-tokens'] || {}
|
|
104
|
-
const lineHeightMap = extractMaps(typographyScss)['line-height-tokens'] || {}
|
|
105
|
-
const trackingMap = extractMaps(typographyScss)['letter-spacing-tokens'] || {}
|
|
106
|
-
const shadowMap = extractMaps(shadowsScss)['shadow-tokens'] || {}
|
|
107
|
-
const radiusMap = extractMaps(radiiScss)['radius-tokens'] || {}
|
|
108
|
-
const durationMap = extractMaps(transitionsScss)['duration-tokens'] || {}
|
|
109
|
-
const easingMap = extractMaps(transitionsScss)['easing-tokens'] || {}
|
|
110
|
-
const zIndexMap = extractMaps(zIndexScss)['z-index-tokens'] || {}
|
|
111
|
-
const opacityMap = extractMaps(opacityScss)['opacity-tokens'] || {}
|
|
112
|
-
const sizingMap = extractMaps(sizingScss)['sizing-tokens'] || {}
|
|
113
|
-
|
|
114
|
-
// ── Serialise to TypeScript ───────────────────────────────────
|
|
115
|
-
|
|
116
|
-
function toTsObj(map, indent = 2) {
|
|
117
|
-
const pad = ' '.repeat(indent)
|
|
118
|
-
const entries = Object.entries(map).map(([k, v]) => {
|
|
119
|
-
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : `'${k}'`
|
|
120
|
-
const val = typeof v === 'object'
|
|
121
|
-
? `{\n${toTsObj(v, indent + 2)}\n${pad}}`
|
|
122
|
-
: `'${String(v)}'`
|
|
123
|
-
return `${pad}${key}: ${val},`
|
|
124
|
-
})
|
|
125
|
-
return entries.join('\n')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ── Generate file ─────────────────────────────────────────────
|
|
129
|
-
|
|
130
|
-
const now = new Date().toISOString().slice(0, 10)
|
|
131
|
-
|
|
132
|
-
const out = `\
|
|
133
|
-
/**
|
|
134
|
-
* @mastors/core — src/tokens.ts
|
|
135
|
-
* AUTO-GENERATED by scripts/generate-tokens.js on ${now}.
|
|
136
|
-
* DO NOT EDIT MANUALLY — run \`node scripts/generate-tokens.js\` to regenerate.
|
|
137
|
-
*
|
|
138
|
-
* Source of truth: packages/core/scss/tokens/
|
|
139
|
-
*/
|
|
140
|
-
|
|
141
|
-
// ─── Color ───────────────────────────────────────────────────────────────────
|
|
142
|
-
|
|
143
|
-
const colorTokens = {
|
|
144
|
-
${toTsObj(colorMap)}
|
|
145
|
-
} as const
|
|
146
|
-
|
|
147
|
-
// ─── Spacing ─────────────────────────────────────────────────────────────────
|
|
148
|
-
|
|
149
|
-
const spacingTokens = {
|
|
150
|
-
${toTsObj(spacingMap)}
|
|
151
|
-
} as const
|
|
152
|
-
|
|
153
|
-
// ─── Typography ──────────────────────────────────────────────────────────────
|
|
154
|
-
|
|
155
|
-
const fontSizeTokens = {
|
|
156
|
-
${toTsObj(fontSizeMap)}
|
|
157
|
-
} as const
|
|
158
|
-
|
|
159
|
-
const fontFamilyTokens = {
|
|
160
|
-
${toTsObj(fontFamilyMap)}
|
|
161
|
-
} as const
|
|
162
|
-
|
|
163
|
-
const fontWeightTokens = {
|
|
164
|
-
${toTsObj(fontWeightMap)}
|
|
165
|
-
} as const
|
|
166
|
-
|
|
167
|
-
const lineHeightTokens = {
|
|
168
|
-
${toTsObj(lineHeightMap)}
|
|
169
|
-
} as const
|
|
170
|
-
|
|
171
|
-
const letterSpacingTokens = {
|
|
172
|
-
${toTsObj(trackingMap)}
|
|
173
|
-
} as const
|
|
174
|
-
|
|
175
|
-
// ─── Border radius ───────────────────────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
const radiusTokens = {
|
|
178
|
-
${toTsObj(radiusMap)}
|
|
179
|
-
} as const
|
|
180
|
-
|
|
181
|
-
// ─── Shadows ─────────────────────────────────────────────────────────────────
|
|
182
|
-
|
|
183
|
-
const shadowTokens = {
|
|
184
|
-
${toTsObj(shadowMap)}
|
|
185
|
-
} as const
|
|
186
|
-
|
|
187
|
-
// ─── Duration & easing ───────────────────────────────────────────────────────
|
|
188
|
-
|
|
189
|
-
const durationTokens = {
|
|
190
|
-
${toTsObj(durationMap)}
|
|
191
|
-
} as const
|
|
192
|
-
|
|
193
|
-
const easingTokens = {
|
|
194
|
-
${toTsObj(easingMap)}
|
|
195
|
-
} as const
|
|
196
|
-
|
|
197
|
-
// ─── Z-index ─────────────────────────────────────────────────────────────────
|
|
198
|
-
|
|
199
|
-
const zIndexTokens = {
|
|
200
|
-
${toTsObj(zIndexMap)}
|
|
201
|
-
} as const
|
|
202
|
-
|
|
203
|
-
// ─── Opacity ─────────────────────────────────────────────────────────────────
|
|
204
|
-
|
|
205
|
-
const opacityTokens = {
|
|
206
|
-
${toTsObj(opacityMap)}
|
|
207
|
-
} as const
|
|
208
|
-
|
|
209
|
-
// ─── Sizing ──────────────────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
const sizingTokens = {
|
|
212
|
-
${toTsObj(sizingMap)}
|
|
213
|
-
} as const
|
|
214
|
-
|
|
215
|
-
// ─── Exported tokens object ───────────────────────────────────────────────────
|
|
216
|
-
|
|
217
|
-
export const tokens = {
|
|
218
|
-
color: colorTokens,
|
|
219
|
-
spacing: spacingTokens,
|
|
220
|
-
fontSize: fontSizeTokens,
|
|
221
|
-
fontFamily: fontFamilyTokens,
|
|
222
|
-
fontWeight: fontWeightTokens,
|
|
223
|
-
lineHeight: lineHeightTokens,
|
|
224
|
-
letterSpacing: letterSpacingTokens,
|
|
225
|
-
radius: radiusTokens,
|
|
226
|
-
shadow: shadowTokens,
|
|
227
|
-
duration: durationTokens,
|
|
228
|
-
easing: easingTokens,
|
|
229
|
-
zIndex: zIndexTokens,
|
|
230
|
-
opacity: opacityTokens,
|
|
231
|
-
sizing: sizingTokens,
|
|
232
|
-
} as const
|
|
233
|
-
|
|
234
|
-
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
235
|
-
|
|
236
|
-
export type Tokens = typeof tokens
|
|
237
|
-
export type ColorPalette = keyof typeof colorTokens
|
|
238
|
-
export type SpacingKey = keyof typeof spacingTokens
|
|
239
|
-
export type FontSizeKey = keyof typeof fontSizeTokens
|
|
240
|
-
export type FontFamilyKey = keyof typeof fontFamilyTokens
|
|
241
|
-
export type FontWeightKey = keyof typeof fontWeightTokens
|
|
242
|
-
export type LineHeightKey = keyof typeof lineHeightTokens
|
|
243
|
-
export type LetterSpacingKey = keyof typeof letterSpacingTokens
|
|
244
|
-
export type RadiusKey = keyof typeof radiusTokens
|
|
245
|
-
export type ShadowKey = keyof typeof shadowTokens
|
|
246
|
-
export type DurationKey = keyof typeof durationTokens
|
|
247
|
-
export type EasingKey = keyof typeof easingTokens
|
|
248
|
-
export type ZIndexKey = keyof typeof zIndexTokens
|
|
249
|
-
export type OpacityKey = keyof typeof opacityTokens
|
|
250
|
-
export type SizingKey = keyof typeof sizingTokens
|
|
251
|
-
|
|
252
|
-
export type ColorShade<P extends ColorPalette> =
|
|
253
|
-
typeof colorTokens[P] extends Record<string, string>
|
|
254
|
-
? keyof typeof colorTokens[P]
|
|
255
|
-
: never
|
|
256
|
-
`
|
|
257
|
-
|
|
258
|
-
fs.writeFileSync(OUT_FILE, out, 'utf8')
|
|
259
|
-
console.log('[generate-tokens] Written → ' + path.relative(process.cwd(), OUT_FILE))
|
|
@@ -1,52 +0,0 @@
|
|
|
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
|
-
}
|
package/scss/config/_index.scss
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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";
|
|
@@ -1,49 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
// utilities/_animation.scss
|
|
2
|
-
// Transition and animation utility classes.
|
|
3
|
-
// ─────────────────────────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
@use "../tokens/transitions" as tr;
|
|
6
|
-
@use "../generators/class-generator" as gen;
|
|
7
|
-
|
|
8
|
-
// ── Transition property ───────────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
.transition-none { transition-property: none; }
|
|
11
|
-
.transition-all { transition-property: all; }
|
|
12
|
-
.transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; }
|
|
13
|
-
.transition-colors { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; }
|
|
14
|
-
.transition-opacity { transition-property: opacity; }
|
|
15
|
-
.transition-shadow { transition-property: box-shadow; }
|
|
16
|
-
.transition-transform { transition-property: transform; }
|
|
17
|
-
|
|
18
|
-
// ── Transition duration ───────────────────────────────────────────────────────
|
|
19
|
-
|
|
20
|
-
@each $key, $val in tr.$duration-tokens {
|
|
21
|
-
.duration-#{$key} { transition-duration: $val; }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// ── Transition timing function ────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
@each $key, $val in tr.$easing-tokens {
|
|
27
|
-
.ease-#{$key} { transition-timing-function: $val; }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── Transition delay ──────────────────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
@each $key, $val in tr.$duration-tokens {
|
|
33
|
-
.delay-#{$key} { transition-delay: $val; }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ── Animation ────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
.animate-none { animation: none; }
|
|
39
|
-
.animate-spin { animation: mastors-spin 1s linear infinite; }
|
|
40
|
-
.animate-ping { animation: mastors-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; }
|
|
41
|
-
.animate-pulse { animation: mastors-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
|
|
42
|
-
.animate-bounce { animation: mastors-bounce 1s infinite; }
|
|
43
|
-
.animate-fade-in { animation: mastors-fade-in 0.3s ease-out both; }
|
|
44
|
-
.animate-fade-out{ animation: mastors-fade-out 0.3s ease-in both; }
|
|
45
|
-
.animate-slide-up { animation: mastors-slide-up 0.3s ease-out both; }
|
|
46
|
-
.animate-slide-down { animation: mastors-slide-down 0.3s ease-out both; }
|
|
47
|
-
.animate-scale-in { animation: mastors-scale-in 0.2s ease-out both; }
|
|
48
|
-
|
|
49
|
-
// ── Keyframe definitions ─────────────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
@keyframes mastors-spin {
|
|
52
|
-
from { transform: rotate(0deg); }
|
|
53
|
-
to { transform: rotate(360deg); }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@keyframes mastors-ping {
|
|
57
|
-
75%, 100% { transform: scale(2); opacity: 0%; }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@keyframes mastors-pulse {
|
|
61
|
-
0%, 100% { opacity: 100%; }
|
|
62
|
-
50% { opacity: 50%; }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@keyframes mastors-bounce {
|
|
66
|
-
0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
|
|
67
|
-
50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@keyframes mastors-fade-in {
|
|
71
|
-
from { opacity: 0%; }
|
|
72
|
-
to { opacity: 100%; }
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@keyframes mastors-fade-out {
|
|
76
|
-
from { opacity: 100%; }
|
|
77
|
-
to { opacity: 0%; }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
@keyframes mastors-slide-up {
|
|
81
|
-
from { opacity: 0%; transform: translateY(0.5rem); }
|
|
82
|
-
to { opacity: 100%; transform: translateY(0); }
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@keyframes mastors-slide-down {
|
|
86
|
-
from { opacity: 0%; transform: translateY(-0.5rem); }
|
|
87
|
-
to { opacity: 100%; transform: translateY(0); }
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@keyframes mastors-scale-in {
|
|
91
|
-
from { opacity: 0%; transform: scale(0.95); }
|
|
92
|
-
to { opacity: 100%; transform: scale(1); }
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ── Animation control utilities ───────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
@include gen.generate-utilities((
|
|
98
|
-
"animation-fill-mode": (
|
|
99
|
-
property: animation-fill-mode,
|
|
100
|
-
prefix: "fill",
|
|
101
|
-
values: (
|
|
102
|
-
"none": none,
|
|
103
|
-
"forwards": forwards,
|
|
104
|
-
"backwards": backwards,
|
|
105
|
-
"both": both,
|
|
106
|
-
),
|
|
107
|
-
),
|
|
108
|
-
"animation-play-state": (
|
|
109
|
-
property: animation-play-state,
|
|
110
|
-
prefix: "animation",
|
|
111
|
-
values: (
|
|
112
|
-
"running": running,
|
|
113
|
-
"paused": paused,
|
|
114
|
-
),
|
|
115
|
-
),
|
|
116
|
-
"animation-iteration": (
|
|
117
|
-
property: animation-iteration-count,
|
|
118
|
-
prefix: "animate-repeat",
|
|
119
|
-
values: (
|
|
120
|
-
"0": 0,
|
|
121
|
-
"1": 1,
|
|
122
|
-
"infinite": infinite,
|
|
123
|
-
),
|
|
124
|
-
),
|
|
125
|
-
));
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
// utilities/_interaction.scss
|
|
2
|
-
// Interaction and user-experience utilities:
|
|
3
|
-
// user-select, resize, scroll-behavior, scroll-snap, touch-action,
|
|
4
|
-
// and state-variant prefixes (hover:, focus:, active:, disabled:).
|
|
5
|
-
// ─────────────────────────────────────────────────────────────
|
|
6
|
-
|
|
7
|
-
@use "../generators/class-generator" as gen;
|
|
8
|
-
|
|
9
|
-
// ── User select ───────────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
@include gen.generate-utilities((
|
|
12
|
-
"select": (
|
|
13
|
-
property: user-select,
|
|
14
|
-
prefix: "select",
|
|
15
|
-
values: (
|
|
16
|
-
"none": none,
|
|
17
|
-
"text": text,
|
|
18
|
-
"all": all,
|
|
19
|
-
"auto": auto,
|
|
20
|
-
),
|
|
21
|
-
),
|
|
22
|
-
));
|
|
23
|
-
|
|
24
|
-
// ── Resize ────────────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
@include gen.generate-utilities((
|
|
27
|
-
"resize": (
|
|
28
|
-
property: resize,
|
|
29
|
-
prefix: "resize",
|
|
30
|
-
values: (
|
|
31
|
-
"none": none,
|
|
32
|
-
"x": horizontal,
|
|
33
|
-
"y": vertical,
|
|
34
|
-
"": both, // .resize
|
|
35
|
-
),
|
|
36
|
-
),
|
|
37
|
-
));
|
|
38
|
-
|
|
39
|
-
// ── Scroll behavior ───────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
.scroll-auto { scroll-behavior: auto; }
|
|
42
|
-
.scroll-smooth { scroll-behavior: smooth; }
|
|
43
|
-
|
|
44
|
-
// ── Scroll snap ───────────────────────────────────────────────────────────────
|
|
45
|
-
|
|
46
|
-
// Container
|
|
47
|
-
@include gen.generate-utilities((
|
|
48
|
-
"snap-type": (
|
|
49
|
-
property: scroll-snap-type,
|
|
50
|
-
prefix: "snap",
|
|
51
|
-
values: (
|
|
52
|
-
"none": none,
|
|
53
|
-
"x": x var(--mastors-snap-strictness, mandatory),
|
|
54
|
-
"y": y var(--mastors-snap-strictness, mandatory),
|
|
55
|
-
"both": both var(--mastors-snap-strictness, mandatory),
|
|
56
|
-
"mandatory": x mandatory,
|
|
57
|
-
"proximity": x proximity,
|
|
58
|
-
),
|
|
59
|
-
),
|
|
60
|
-
));
|
|
61
|
-
|
|
62
|
-
// Item
|
|
63
|
-
@include gen.generate-utilities((
|
|
64
|
-
"snap-align": (
|
|
65
|
-
property: scroll-snap-align,
|
|
66
|
-
prefix: "snap",
|
|
67
|
-
values: (
|
|
68
|
-
"start": start,
|
|
69
|
-
"end": end,
|
|
70
|
-
"center": center,
|
|
71
|
-
"align-none": none,
|
|
72
|
-
),
|
|
73
|
-
),
|
|
74
|
-
));
|
|
75
|
-
|
|
76
|
-
.snap-stop-always { scroll-snap-stop: always; }
|
|
77
|
-
.snap-stop-normal { scroll-snap-stop: normal; }
|
|
78
|
-
|
|
79
|
-
// ── Scroll margin/padding ─────────────────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
$-scroll-values: ("0": 0px, "4": 1rem, "8": 2rem, "16": 4rem);
|
|
82
|
-
|
|
83
|
-
@each $key, $val in $-scroll-values {
|
|
84
|
-
.scroll-m-#{$key} { scroll-margin: $val; }
|
|
85
|
-
.scroll-mt-#{$key} { scroll-margin-top: $val; }
|
|
86
|
-
.scroll-mb-#{$key} { scroll-margin-bottom: $val; }
|
|
87
|
-
.scroll-p-#{$key} { scroll-padding: $val; }
|
|
88
|
-
.scroll-pt-#{$key} { scroll-padding-top: $val; }
|
|
89
|
-
.scroll-pb-#{$key} { scroll-padding-bottom: $val; }
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ── Touch action ──────────────────────────────────────────────────────────────
|
|
93
|
-
|
|
94
|
-
@include gen.generate-utilities((
|
|
95
|
-
"touch": (
|
|
96
|
-
property: touch-action,
|
|
97
|
-
prefix: "touch",
|
|
98
|
-
values: (
|
|
99
|
-
"auto": auto,
|
|
100
|
-
"none": none,
|
|
101
|
-
"pan-x": pan-x,
|
|
102
|
-
"pan-y": pan-y,
|
|
103
|
-
"pan-left": pan-left,
|
|
104
|
-
"pan-right": pan-right,
|
|
105
|
-
"pan-up": pan-up,
|
|
106
|
-
"pan-down": pan-down,
|
|
107
|
-
"pinch-zoom": pinch-zoom,
|
|
108
|
-
"manipulation": manipulation,
|
|
109
|
-
),
|
|
110
|
-
),
|
|
111
|
-
));
|
|
112
|
-
|
|
113
|
-
// ── State-variant pseudo-class utilities ─────────────────────────────────────
|
|
114
|
-
// Hover, focus, active, disabled, and group-hover variants.
|
|
115
|
-
// Pattern: .hover\:{utility}:hover { ... }
|
|
116
|
-
// These are the most commonly used interactive overrides. For full
|
|
117
|
-
// state-variant coverage, use a PostCSS/Vite plugin or the responsive engine.
|
|
118
|
-
|
|
119
|
-
// Hover: opacity
|
|
120
|
-
@each $key, $val in ("0": 0, "50": 0.5, "75": 0.75, "100": 1) {
|
|
121
|
-
.hover\:opacity-#{$key}:hover { opacity: $val; }
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Hover: background accent
|
|
125
|
-
.hover\:bg-accent:hover { background-color: var(--mastors-accent-hover); }
|
|
126
|
-
.hover\:text-accent:hover { color: var(--mastors-accent-hover); }
|
|
127
|
-
.hover\:underline:hover { text-decoration-line: underline; }
|
|
128
|
-
.hover\:no-underline:hover { text-decoration-line: none; }
|
|
129
|
-
.hover\:shadow-lg:hover { box-shadow: var(--mastors-shadow-lg); }
|
|
130
|
-
.hover\:scale-105:hover { transform: scale(1.05); }
|
|
131
|
-
.hover\:scale-110:hover { transform: scale(1.1); }
|
|
132
|
-
.hover\:-translate-y-1:hover { transform: translateY(-0.25rem); }
|
|
133
|
-
|
|
134
|
-
// Focus-visible: ring utilities
|
|
135
|
-
.focus\:ring:focus-visible {
|
|
136
|
-
outline: 2px solid var(--mastors-accent);
|
|
137
|
-
outline-offset: 2px;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.focus\:ring-2:focus-visible {
|
|
141
|
-
outline: 2px solid var(--mastors-accent);
|
|
142
|
-
outline-offset: 2px;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.focus\:ring-offset-2:focus-visible {
|
|
146
|
-
outline-offset: 4px;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.focus\:ring-none:focus-visible {
|
|
150
|
-
outline: none;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Disabled: dim + block interaction
|
|
154
|
-
.disabled\:opacity-50:disabled { opacity: 50%; }
|
|
155
|
-
.disabled\:cursor-not-allowed:disabled { cursor: not-allowed; }
|
|
156
|
-
.disabled\:pointer-events-none:disabled { pointer-events: none; }
|