meno-core 1.1.3 → 1.1.5
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/dist/chunks/{chunk-3JXK2QFU.js → chunk-H6EOTPJA.js} +2 -2
- package/dist/chunks/{chunk-LOZL5HOF.js → chunk-RLBV2R6J.js} +603 -17
- package/dist/chunks/chunk-RLBV2R6J.js.map +7 -0
- package/dist/chunks/{chunk-FQBIC2OB.js → chunk-YMBUSHII.js} +1 -1
- package/dist/chunks/{chunk-FQBIC2OB.js.map → chunk-YMBUSHII.js.map} +1 -1
- package/dist/lib/client/index.js +46 -28
- package/dist/lib/client/index.js.map +2 -2
- package/dist/lib/server/index.js +1304 -241
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +4 -2
- package/dist/lib/shared/index.js.map +1 -1
- package/lib/client/core/ComponentBuilder.test.ts +32 -0
- package/lib/client/core/ComponentBuilder.ts +30 -0
- package/lib/client/theme.test.ts +2 -2
- package/lib/client/theme.ts +28 -26
- package/lib/server/createServer.ts +5 -1
- package/lib/server/cssAudit.test.ts +270 -0
- package/lib/server/cssAudit.ts +815 -0
- package/lib/server/deMirror.test.ts +61 -0
- package/lib/server/deMirror.ts +317 -0
- package/lib/server/fileWatcher.test.ts +113 -0
- package/lib/server/fileWatcher.ts +42 -1
- package/lib/server/index.ts +19 -0
- package/lib/server/routes/api/core-routes.ts +18 -0
- package/lib/server/routes/api/cssAudit.test.ts +101 -0
- package/lib/server/routes/api/cssAudit.ts +138 -0
- package/lib/server/routes/api/deMirror.test.ts +105 -0
- package/lib/server/routes/api/deMirror.ts +127 -0
- package/lib/server/routes/api/pages.ts +2 -2
- package/lib/server/services/componentService.test.ts +43 -0
- package/lib/server/services/componentService.ts +49 -12
- package/lib/server/services/configService.ts +0 -5
- package/lib/server/services/pageService.test.ts +15 -0
- package/lib/server/services/pageService.ts +44 -22
- package/lib/server/ssr/htmlGenerator.test.ts +29 -1
- package/lib/server/ssr/htmlGenerator.ts +86 -14
- package/lib/server/themeCssCodec.test.ts +67 -0
- package/lib/server/themeCssCodec.ts +67 -5
- package/lib/server/webflow/templateWrapper.ts +54 -0
- package/lib/shared/cssGeneration.test.ts +64 -0
- package/lib/shared/cssGeneration.ts +6 -1
- package/lib/shared/interfaces/contentProvider.ts +9 -0
- package/lib/shared/tailwindThemeScale.ts +1 -0
- package/lib/shared/types/cms.ts +1 -0
- package/lib/shared/types/comment.ts +9 -3
- package/lib/shared/utilityClassConfig.ts +471 -10
- package/lib/shared/utilityClassMapper.test.ts +173 -2
- package/lib/shared/utilityClassMapper.ts +37 -0
- package/lib/shared/utilityClassNames.ts +164 -0
- package/lib/shared/utils/fileUtils.ts +11 -0
- package/lib/shared/validation/schemas.ts +1 -0
- package/lib/shared/viewportUnits.test.ts +34 -1
- package/lib/shared/viewportUnits.ts +43 -0
- package/package.json +3 -1
- package/vite.config.ts +4 -1
- package/dist/chunks/chunk-LOZL5HOF.js.map +0 -7
- /package/dist/chunks/{chunk-3JXK2QFU.js.map → chunk-H6EOTPJA.js.map} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Used by both client and server to ensure consistent CSS output
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { propertyOrder, staticUtilityReverse, presetClassReverse } from './utilityClassConfig';
|
|
7
|
+
import { propertyOrder, staticUtilityReverse, presetClassReverse, ROUNDED_SIDE_CORNERS } from './utilityClassConfig';
|
|
8
8
|
import {
|
|
9
9
|
parseUtilityClass,
|
|
10
10
|
splitVariantPrefix,
|
|
@@ -217,6 +217,11 @@ export function generateRuleForClass(className: string, knownTokens?: ReadonlySe
|
|
|
217
217
|
if (root === 'size') {
|
|
218
218
|
return `width: ${value}; height: ${value};`;
|
|
219
219
|
}
|
|
220
|
+
// Side border-radius: no CSS per-side shorthand — emit both corner longhands.
|
|
221
|
+
const sideCorners = root ? ROUNDED_SIDE_CORNERS[root] : undefined;
|
|
222
|
+
if (sideCorners) {
|
|
223
|
+
return `${sideCorners[0]}: ${value}; ${sideCorners[1]}: ${value};`;
|
|
224
|
+
}
|
|
220
225
|
if (root === 'px') {
|
|
221
226
|
return `padding-left: ${value}; padding-right: ${value};`;
|
|
222
227
|
}
|
|
@@ -56,6 +56,15 @@ export interface PageProvider {
|
|
|
56
56
|
* Optional — callers fall back to ".json" when not provided.
|
|
57
57
|
*/
|
|
58
58
|
extension?(): string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Absolute path to the source file backing a page path, or null if it doesn't
|
|
62
|
+
* exist. Unlike the naive `<pagesDir>/<path>.<ext>` mapping, this resolves cases
|
|
63
|
+
* where the logical editor path diverges from the on-disk file — notably CMS
|
|
64
|
+
* template pages (`/templates/<col>` → `src/pages/<routeDir>/[slug].astro`). Used
|
|
65
|
+
* to point external tools ("Open source file") at the real file. Optional.
|
|
66
|
+
*/
|
|
67
|
+
resolveSourcePath?(path: string): Promise<string | null>;
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
/**
|
|
@@ -137,6 +137,7 @@ const SPECS: ScaleSpec[] = [
|
|
|
137
137
|
['lg', '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)'],
|
|
138
138
|
['xl', '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)'],
|
|
139
139
|
['2xl', '0 25px 50px -12px rgb(0 0 0 / 0.25)'],
|
|
140
|
+
['inner', 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)'],
|
|
140
141
|
],
|
|
141
142
|
},
|
|
142
143
|
{
|
package/lib/shared/types/cms.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface CMSFieldDefinition {
|
|
|
27
27
|
accept?: string; // For 'file' type - MIME filter (e.g. "application/pdf", "*/*")
|
|
28
28
|
collection?: string; // For 'reference' type - target collection ID
|
|
29
29
|
multiple?: boolean; // For 'reference' type - allows array of IDs
|
|
30
|
+
editor?: 'basic' | 'extended'; // For 'rich-text' type: which editor + render helper (Basic → richText(); Extended → richTextWithComponents())
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/** Data delivery strategy for client-side CMS data */
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Comments are Figma-style pins placed on components in the studio canvas.
|
|
5
5
|
* One file per pin (thread embedded). Storage layout (status as top folder):
|
|
6
|
-
* {projectRoot}/comments/<status>/<pageSlug>--<seq>--<titleSlug>.json
|
|
7
|
-
* e.g. comments/open/blog__post--3--hero-is-too-dark.json
|
|
6
|
+
* {projectRoot}/comments/<status>/<pageSlug>--<seq>--<titleSlug>--<idFrag>.json
|
|
7
|
+
* e.g. comments/open/blog__post--3--hero-is-too-dark--550e8400.json
|
|
8
8
|
*
|
|
9
9
|
* Pins are an authoring-time concept — they live in studio only.
|
|
10
10
|
*/
|
|
@@ -119,7 +119,13 @@ export interface Comment {
|
|
|
119
119
|
_filename: string;
|
|
120
120
|
/** Page path the pin lives on (e.g. `"blog/post"`). */
|
|
121
121
|
_pagePath: string;
|
|
122
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Best-effort creation counter (server stamps `max+1` at create time), used
|
|
124
|
+
* as the human-scannable middle segment of the filename. NOT collision-proof
|
|
125
|
+
* under concurrent/offline creation and NOT the badge shown to users — the pin
|
|
126
|
+
* badge is derived client-side from the full set (see `assignDisplaySeq`), so a
|
|
127
|
+
* repeated `_seq` here is harmless.
|
|
128
|
+
*/
|
|
123
129
|
_seq: number;
|
|
124
130
|
/** ISO timestamps. */
|
|
125
131
|
_createdAt: string;
|
|
@@ -259,6 +259,35 @@ export const propertyMap: Record<string, string> = {
|
|
|
259
259
|
textShadow: 'text-shadow',
|
|
260
260
|
filter: 'filter',
|
|
261
261
|
backdropFilter: 'backdrop-filter',
|
|
262
|
+
mixBlendMode: 'mix-blend',
|
|
263
|
+
backgroundBlendMode: 'bg-blend',
|
|
264
|
+
willChange: 'will-change',
|
|
265
|
+
columns: 'columns',
|
|
266
|
+
overscrollBehavior: 'overscroll',
|
|
267
|
+
overscrollBehaviorX: 'overscroll-x',
|
|
268
|
+
overscrollBehaviorY: 'overscroll-y',
|
|
269
|
+
touchAction: 'touch',
|
|
270
|
+
breakAfter: 'break-after',
|
|
271
|
+
breakBefore: 'break-before',
|
|
272
|
+
breakInside: 'break-inside',
|
|
273
|
+
textUnderlineOffset: 'underline-offset',
|
|
274
|
+
textDecorationColor: 'decoration',
|
|
275
|
+
textDecorationThickness: 'decoration',
|
|
276
|
+
caretColor: 'caret',
|
|
277
|
+
fill: 'fill',
|
|
278
|
+
stroke: 'stroke',
|
|
279
|
+
strokeWidth: 'stroke',
|
|
280
|
+
borderSpacing: 'border-spacing',
|
|
281
|
+
scrollMargin: 'scroll-m',
|
|
282
|
+
scrollMarginTop: 'scroll-mt',
|
|
283
|
+
scrollMarginRight: 'scroll-mr',
|
|
284
|
+
scrollMarginBottom: 'scroll-mb',
|
|
285
|
+
scrollMarginLeft: 'scroll-ml',
|
|
286
|
+
scrollPadding: 'scroll-p',
|
|
287
|
+
scrollPaddingTop: 'scroll-pt',
|
|
288
|
+
scrollPaddingRight: 'scroll-pr',
|
|
289
|
+
scrollPaddingBottom: 'scroll-pb',
|
|
290
|
+
scrollPaddingLeft: 'scroll-pl',
|
|
262
291
|
|
|
263
292
|
// Positioning
|
|
264
293
|
top: 'top',
|
|
@@ -266,6 +295,8 @@ export const propertyMap: Record<string, string> = {
|
|
|
266
295
|
bottom: 'bottom',
|
|
267
296
|
left: 'left',
|
|
268
297
|
inset: 'inset',
|
|
298
|
+
insetInlineStart: 'start',
|
|
299
|
+
insetInlineEnd: 'end',
|
|
269
300
|
zIndex: 'z',
|
|
270
301
|
|
|
271
302
|
// Grid Layout
|
|
@@ -339,6 +370,8 @@ export const prefixToCSSProperty: Record<string, string> = {
|
|
|
339
370
|
'border-r': 'border-right',
|
|
340
371
|
'border-b': 'border-bottom',
|
|
341
372
|
'border-l': 'border-left',
|
|
373
|
+
'border-x': 'border-inline',
|
|
374
|
+
'border-y': 'border-block',
|
|
342
375
|
rounded: 'border-radius',
|
|
343
376
|
'rounded-tl': 'border-top-left-radius',
|
|
344
377
|
'rounded-tr': 'border-top-right-radius',
|
|
@@ -392,6 +425,71 @@ export const prefixToCSSProperty: Record<string, string> = {
|
|
|
392
425
|
'text-shadow': 'text-shadow',
|
|
393
426
|
filter: 'filter',
|
|
394
427
|
'backdrop-filter': 'backdrop-filter',
|
|
428
|
+
// Filter-function roots (value is wrapped in the function — see FILTER_FN_ROOTS +
|
|
429
|
+
// parseRootValue's filter branch). Kept here too so hash/dynamic property derivation
|
|
430
|
+
// and SORTED_ROOTS matching see them like any other root.
|
|
431
|
+
blur: 'filter',
|
|
432
|
+
brightness: 'filter',
|
|
433
|
+
contrast: 'filter',
|
|
434
|
+
saturate: 'filter',
|
|
435
|
+
grayscale: 'filter',
|
|
436
|
+
invert: 'filter',
|
|
437
|
+
sepia: 'filter',
|
|
438
|
+
'hue-rotate': 'filter',
|
|
439
|
+
'drop-shadow': 'filter',
|
|
440
|
+
'backdrop-blur': 'backdrop-filter',
|
|
441
|
+
'backdrop-brightness': 'backdrop-filter',
|
|
442
|
+
'backdrop-contrast': 'backdrop-filter',
|
|
443
|
+
'backdrop-saturate': 'backdrop-filter',
|
|
444
|
+
'backdrop-grayscale': 'backdrop-filter',
|
|
445
|
+
'backdrop-invert': 'backdrop-filter',
|
|
446
|
+
'backdrop-sepia': 'backdrop-filter',
|
|
447
|
+
'backdrop-hue-rotate': 'backdrop-filter',
|
|
448
|
+
'backdrop-opacity': 'backdrop-filter',
|
|
449
|
+
// Per-axis transforms (value composed into the axis slot — see parseRootValue)
|
|
450
|
+
'skew-x': 'transform',
|
|
451
|
+
'skew-y': 'transform',
|
|
452
|
+
'scale-x': 'scale',
|
|
453
|
+
'scale-y': 'scale',
|
|
454
|
+
// Side border-radius (two corners — expanded in generateRuleForClass / classesToStyles)
|
|
455
|
+
'rounded-t': 'border-top-left-radius',
|
|
456
|
+
'rounded-r': 'border-top-right-radius',
|
|
457
|
+
'rounded-b': 'border-bottom-left-radius',
|
|
458
|
+
'rounded-l': 'border-top-left-radius',
|
|
459
|
+
// Blend / misc keyword roots
|
|
460
|
+
'mix-blend': 'mix-blend-mode',
|
|
461
|
+
'bg-blend': 'background-blend-mode',
|
|
462
|
+
'will-change': 'will-change',
|
|
463
|
+
columns: 'columns',
|
|
464
|
+
overscroll: 'overscroll-behavior',
|
|
465
|
+
'overscroll-x': 'overscroll-behavior-x',
|
|
466
|
+
'overscroll-y': 'overscroll-behavior-y',
|
|
467
|
+
touch: 'touch-action',
|
|
468
|
+
'break-after': 'break-after',
|
|
469
|
+
'break-before': 'break-before',
|
|
470
|
+
'break-inside': 'break-inside',
|
|
471
|
+
|
|
472
|
+
// Text decoration & SVG (shared roots disambiguated by value type — see resolveRootProperty)
|
|
473
|
+
'underline-offset': 'text-underline-offset',
|
|
474
|
+
decoration: 'text-decoration-color',
|
|
475
|
+
caret: 'caret-color',
|
|
476
|
+
fill: 'fill',
|
|
477
|
+
stroke: 'stroke',
|
|
478
|
+
|
|
479
|
+
// Tables
|
|
480
|
+
'border-spacing': 'border-spacing',
|
|
481
|
+
|
|
482
|
+
// Scroll margin/padding (Tailwind spacing scale)
|
|
483
|
+
'scroll-m': 'scroll-margin',
|
|
484
|
+
'scroll-mt': 'scroll-margin-top',
|
|
485
|
+
'scroll-mr': 'scroll-margin-right',
|
|
486
|
+
'scroll-mb': 'scroll-margin-bottom',
|
|
487
|
+
'scroll-ml': 'scroll-margin-left',
|
|
488
|
+
'scroll-p': 'scroll-padding',
|
|
489
|
+
'scroll-pt': 'scroll-padding-top',
|
|
490
|
+
'scroll-pr': 'scroll-padding-right',
|
|
491
|
+
'scroll-pb': 'scroll-padding-bottom',
|
|
492
|
+
'scroll-pl': 'scroll-padding-left',
|
|
395
493
|
|
|
396
494
|
// Positioning
|
|
397
495
|
top: 'top',
|
|
@@ -401,6 +499,8 @@ export const prefixToCSSProperty: Record<string, string> = {
|
|
|
401
499
|
inset: 'inset',
|
|
402
500
|
'inset-x': 'inset-inline',
|
|
403
501
|
'inset-y': 'inset-block',
|
|
502
|
+
start: 'inset-inline-start',
|
|
503
|
+
end: 'inset-inline-end',
|
|
404
504
|
z: 'z-index',
|
|
405
505
|
|
|
406
506
|
// Outline
|
|
@@ -416,6 +516,75 @@ export const prefixToCSSProperty: Record<string, string> = {
|
|
|
416
516
|
object: 'object-position',
|
|
417
517
|
};
|
|
418
518
|
|
|
519
|
+
/**
|
|
520
|
+
* Tailwind filter-function utilities: the class value is an ARGUMENT to a CSS filter
|
|
521
|
+
* function, not the property value itself (`blur-[70px]` → `filter: blur(70px)`,
|
|
522
|
+
* `brightness-50` → `filter: brightness(0.5)`). `scale` describes how a bare numeric
|
|
523
|
+
* step converts to the argument (Tailwind's scale semantics): `ratio` = n/100
|
|
524
|
+
* (brightness-150 → 1.5), `percent` = n% (invert-25 → 25%), `deg` = ndeg
|
|
525
|
+
* (hue-rotate-90 → 90deg). Roots without `scale` (blur, drop-shadow) take only the
|
|
526
|
+
* arbitrary/var forms — their named steps are length/shadow theme values Meno
|
|
527
|
+
* deliberately doesn't bake in.
|
|
528
|
+
*/
|
|
529
|
+
export type FilterFnScale = 'ratio' | 'percent' | 'deg';
|
|
530
|
+
export const FILTER_FN_ROOTS: Record<string, { property: string; fn: string; scale?: FilterFnScale }> = {
|
|
531
|
+
blur: { property: 'filter', fn: 'blur' },
|
|
532
|
+
brightness: { property: 'filter', fn: 'brightness', scale: 'ratio' },
|
|
533
|
+
contrast: { property: 'filter', fn: 'contrast', scale: 'ratio' },
|
|
534
|
+
saturate: { property: 'filter', fn: 'saturate', scale: 'ratio' },
|
|
535
|
+
grayscale: { property: 'filter', fn: 'grayscale', scale: 'percent' },
|
|
536
|
+
invert: { property: 'filter', fn: 'invert', scale: 'percent' },
|
|
537
|
+
sepia: { property: 'filter', fn: 'sepia', scale: 'percent' },
|
|
538
|
+
'hue-rotate': { property: 'filter', fn: 'hue-rotate', scale: 'deg' },
|
|
539
|
+
'drop-shadow': { property: 'filter', fn: 'drop-shadow' },
|
|
540
|
+
'backdrop-blur': { property: 'backdrop-filter', fn: 'blur' },
|
|
541
|
+
'backdrop-brightness': { property: 'backdrop-filter', fn: 'brightness', scale: 'ratio' },
|
|
542
|
+
'backdrop-contrast': { property: 'backdrop-filter', fn: 'contrast', scale: 'ratio' },
|
|
543
|
+
'backdrop-saturate': { property: 'backdrop-filter', fn: 'saturate', scale: 'ratio' },
|
|
544
|
+
'backdrop-grayscale': { property: 'backdrop-filter', fn: 'grayscale', scale: 'percent' },
|
|
545
|
+
'backdrop-invert': { property: 'backdrop-filter', fn: 'invert', scale: 'percent' },
|
|
546
|
+
'backdrop-sepia': { property: 'backdrop-filter', fn: 'sepia', scale: 'percent' },
|
|
547
|
+
'backdrop-hue-rotate': { property: 'backdrop-filter', fn: 'hue-rotate', scale: 'deg' },
|
|
548
|
+
'backdrop-opacity': { property: 'backdrop-filter', fn: 'opacity', scale: 'ratio' },
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
/** `<kebab property>|<fn>` → filter root, for the inverse mapper (`filter: brightness(0.5)` → `brightness-50`). */
|
|
552
|
+
export const FILTER_ROOT_BY_PROP_FN: ReadonlyMap<string, string> = new Map(
|
|
553
|
+
Object.entries(FILTER_FN_ROOTS).map(([root, e]) => [`${e.property}|${e.fn}`, root]),
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
/** Convert a bare numeric step to the filter-function argument per the root's scale. */
|
|
557
|
+
export function filterStepToArg(scale: FilterFnScale, step: string): string {
|
|
558
|
+
if (scale === 'ratio') return String(Number(step) / 100);
|
|
559
|
+
if (scale === 'percent') return `${step}%`;
|
|
560
|
+
return `${step}deg`;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Inverse of {@link filterStepToArg}: recover the numeric step from an argument, or null. */
|
|
564
|
+
export function filterArgToStep(scale: FilterFnScale, arg: string): string | null {
|
|
565
|
+
if (scale === 'ratio') {
|
|
566
|
+
const m = arg.match(/^(\d+(?:\.\d+)?)$/);
|
|
567
|
+
if (!m) return null;
|
|
568
|
+
const step = Number(m[1]) * 100;
|
|
569
|
+
return Number.isInteger(step) ? String(step) : null;
|
|
570
|
+
}
|
|
571
|
+
const m = scale === 'percent' ? arg.match(/^(\d+)%$/) : arg.match(/^(\d+)deg$/);
|
|
572
|
+
return m ? (m[1] ?? null) : null;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Side border-radius roots (`rounded-t-lg`, `rounded-l-[8px]`) → their two corner
|
|
577
|
+
* longhands. CSS has no per-side radius shorthand, so the CSS generator emits both
|
|
578
|
+
* corners and `classesToStyles` mirrors the parsed first corner onto the second
|
|
579
|
+
* (like `size-*` does for width/height).
|
|
580
|
+
*/
|
|
581
|
+
export const ROUNDED_SIDE_CORNERS: Record<string, [string, string]> = {
|
|
582
|
+
'rounded-t': ['border-top-left-radius', 'border-top-right-radius'],
|
|
583
|
+
'rounded-r': ['border-top-right-radius', 'border-bottom-right-radius'],
|
|
584
|
+
'rounded-b': ['border-bottom-left-radius', 'border-bottom-right-radius'],
|
|
585
|
+
'rounded-l': ['border-top-left-radius', 'border-bottom-left-radius'],
|
|
586
|
+
};
|
|
587
|
+
|
|
419
588
|
/**
|
|
420
589
|
* Static utilities: property → value → Tailwind class name.
|
|
421
590
|
* These are emitted as-is (no brackets) and have fixed reverse mappings.
|
|
@@ -436,6 +605,14 @@ export const staticUtilities: Record<string, Record<string, string>> = {
|
|
|
436
605
|
contents: 'contents',
|
|
437
606
|
'flow-root': 'flow-root',
|
|
438
607
|
'list-item': 'list-item',
|
|
608
|
+
'table-row': 'table-row',
|
|
609
|
+
'table-cell': 'table-cell',
|
|
610
|
+
'table-caption': 'table-caption',
|
|
611
|
+
'table-row-group': 'table-row-group',
|
|
612
|
+
'table-header-group': 'table-header-group',
|
|
613
|
+
'table-footer-group': 'table-footer-group',
|
|
614
|
+
'table-column': 'table-column',
|
|
615
|
+
'table-column-group': 'table-column-group',
|
|
439
616
|
},
|
|
440
617
|
flexDirection: {
|
|
441
618
|
column: 'flex-col',
|
|
@@ -692,6 +869,7 @@ export const staticUtilities: Record<string, Record<string, string>> = {
|
|
|
692
869
|
},
|
|
693
870
|
transform: {
|
|
694
871
|
none: 'transform-none',
|
|
872
|
+
'translateZ(0)': 'transform-gpu',
|
|
695
873
|
},
|
|
696
874
|
boxShadow: {
|
|
697
875
|
none: 'shadow-none',
|
|
@@ -699,6 +877,176 @@ export const staticUtilities: Record<string, Record<string, string>> = {
|
|
|
699
877
|
outline: {
|
|
700
878
|
none: 'outline-none',
|
|
701
879
|
},
|
|
880
|
+
outlineStyle: {
|
|
881
|
+
solid: 'outline-solid',
|
|
882
|
+
dashed: 'outline-dashed',
|
|
883
|
+
dotted: 'outline-dotted',
|
|
884
|
+
double: 'outline-double',
|
|
885
|
+
},
|
|
886
|
+
fontStyle: {
|
|
887
|
+
italic: 'italic',
|
|
888
|
+
normal: 'not-italic',
|
|
889
|
+
},
|
|
890
|
+
isolation: {
|
|
891
|
+
isolate: 'isolate',
|
|
892
|
+
auto: 'isolation-auto',
|
|
893
|
+
},
|
|
894
|
+
borderCollapse: {
|
|
895
|
+
collapse: 'border-collapse',
|
|
896
|
+
separate: 'border-separate',
|
|
897
|
+
},
|
|
898
|
+
tableLayout: {
|
|
899
|
+
auto: 'table-auto',
|
|
900
|
+
fixed: 'table-fixed',
|
|
901
|
+
},
|
|
902
|
+
appearance: {
|
|
903
|
+
none: 'appearance-none',
|
|
904
|
+
auto: 'appearance-auto',
|
|
905
|
+
},
|
|
906
|
+
fontVariantNumeric: {
|
|
907
|
+
'tabular-nums': 'tabular-nums',
|
|
908
|
+
normal: 'normal-nums',
|
|
909
|
+
ordinal: 'ordinal',
|
|
910
|
+
'slashed-zero': 'slashed-zero',
|
|
911
|
+
'lining-nums': 'lining-nums',
|
|
912
|
+
'oldstyle-nums': 'oldstyle-nums',
|
|
913
|
+
'proportional-nums': 'proportional-nums',
|
|
914
|
+
'diagonal-fractions': 'diagonal-fractions',
|
|
915
|
+
'stacked-fractions': 'stacked-fractions',
|
|
916
|
+
},
|
|
917
|
+
// Tailwind pairs snap-x/y/both with a separate strictness class composed via a CSS
|
|
918
|
+
// var; without var composition the common `snap-x snap-mandatory` intent collapses
|
|
919
|
+
// into the type class itself. `snap-proximity`/`snap-mandatory` alone stay foreign.
|
|
920
|
+
scrollSnapType: {
|
|
921
|
+
'x mandatory': 'snap-x',
|
|
922
|
+
'y mandatory': 'snap-y',
|
|
923
|
+
'both mandatory': 'snap-both',
|
|
924
|
+
none: 'snap-none',
|
|
925
|
+
},
|
|
926
|
+
scrollSnapAlign: {
|
|
927
|
+
start: 'snap-start',
|
|
928
|
+
center: 'snap-center',
|
|
929
|
+
end: 'snap-end',
|
|
930
|
+
none: 'snap-align-none',
|
|
931
|
+
},
|
|
932
|
+
// Bare filter-function switches (the 100% forms); numeric/arbitrary forms flow
|
|
933
|
+
// through FILTER_FN_ROOTS (`grayscale-50`, `invert-[0.3]`).
|
|
934
|
+
filter: {
|
|
935
|
+
'grayscale(100%)': 'grayscale',
|
|
936
|
+
'invert(100%)': 'invert',
|
|
937
|
+
'sepia(100%)': 'sepia',
|
|
938
|
+
none: 'filter-none',
|
|
939
|
+
},
|
|
940
|
+
backdropFilter: {
|
|
941
|
+
'grayscale(100%)': 'backdrop-grayscale',
|
|
942
|
+
'invert(100%)': 'backdrop-invert',
|
|
943
|
+
'sepia(100%)': 'backdrop-sepia',
|
|
944
|
+
none: 'backdrop-filter-none',
|
|
945
|
+
},
|
|
946
|
+
float: {
|
|
947
|
+
left: 'float-left',
|
|
948
|
+
right: 'float-right',
|
|
949
|
+
none: 'float-none',
|
|
950
|
+
'inline-start': 'float-start',
|
|
951
|
+
'inline-end': 'float-end',
|
|
952
|
+
},
|
|
953
|
+
clear: {
|
|
954
|
+
both: 'clear-both',
|
|
955
|
+
left: 'clear-left',
|
|
956
|
+
right: 'clear-right',
|
|
957
|
+
none: 'clear-none',
|
|
958
|
+
},
|
|
959
|
+
backgroundSize: {
|
|
960
|
+
cover: 'bg-cover',
|
|
961
|
+
contain: 'bg-contain',
|
|
962
|
+
auto: 'bg-auto',
|
|
963
|
+
},
|
|
964
|
+
backgroundAttachment: {
|
|
965
|
+
fixed: 'bg-fixed',
|
|
966
|
+
local: 'bg-local',
|
|
967
|
+
scroll: 'bg-scroll',
|
|
968
|
+
},
|
|
969
|
+
backgroundRepeat: {
|
|
970
|
+
'no-repeat': 'bg-no-repeat',
|
|
971
|
+
repeat: 'bg-repeat',
|
|
972
|
+
'repeat-x': 'bg-repeat-x',
|
|
973
|
+
'repeat-y': 'bg-repeat-y',
|
|
974
|
+
round: 'bg-repeat-round',
|
|
975
|
+
space: 'bg-repeat-space',
|
|
976
|
+
},
|
|
977
|
+
backgroundPosition: {
|
|
978
|
+
center: 'bg-center',
|
|
979
|
+
top: 'bg-top',
|
|
980
|
+
bottom: 'bg-bottom',
|
|
981
|
+
left: 'bg-left',
|
|
982
|
+
right: 'bg-right',
|
|
983
|
+
'left top': 'bg-left-top',
|
|
984
|
+
'left bottom': 'bg-left-bottom',
|
|
985
|
+
'right top': 'bg-right-top',
|
|
986
|
+
'right bottom': 'bg-right-bottom',
|
|
987
|
+
},
|
|
988
|
+
backgroundClip: {
|
|
989
|
+
'border-box': 'bg-clip-border',
|
|
990
|
+
'padding-box': 'bg-clip-padding',
|
|
991
|
+
'content-box': 'bg-clip-content',
|
|
992
|
+
text: 'bg-clip-text',
|
|
993
|
+
},
|
|
994
|
+
backgroundOrigin: {
|
|
995
|
+
'border-box': 'bg-origin-border',
|
|
996
|
+
'padding-box': 'bg-origin-padding',
|
|
997
|
+
'content-box': 'bg-origin-content',
|
|
998
|
+
},
|
|
999
|
+
textOverflow: {
|
|
1000
|
+
ellipsis: 'text-ellipsis',
|
|
1001
|
+
clip: 'text-clip',
|
|
1002
|
+
},
|
|
1003
|
+
// `text-nowrap` deliberately stays a whiteSpace alias (same rendering) — see staticClassAliases.
|
|
1004
|
+
textWrap: {
|
|
1005
|
+
wrap: 'text-wrap',
|
|
1006
|
+
balance: 'text-balance',
|
|
1007
|
+
pretty: 'text-pretty',
|
|
1008
|
+
},
|
|
1009
|
+
textDecorationStyle: {
|
|
1010
|
+
solid: 'decoration-solid',
|
|
1011
|
+
dashed: 'decoration-dashed',
|
|
1012
|
+
dotted: 'decoration-dotted',
|
|
1013
|
+
double: 'decoration-double',
|
|
1014
|
+
wavy: 'decoration-wavy',
|
|
1015
|
+
},
|
|
1016
|
+
hyphens: {
|
|
1017
|
+
auto: 'hyphens-auto',
|
|
1018
|
+
none: 'hyphens-none',
|
|
1019
|
+
manual: 'hyphens-manual',
|
|
1020
|
+
},
|
|
1021
|
+
content: {
|
|
1022
|
+
none: 'content-none',
|
|
1023
|
+
},
|
|
1024
|
+
captionSide: {
|
|
1025
|
+
top: 'caption-top',
|
|
1026
|
+
bottom: 'caption-bottom',
|
|
1027
|
+
},
|
|
1028
|
+
animation: {
|
|
1029
|
+
none: 'animate-none',
|
|
1030
|
+
},
|
|
1031
|
+
// SVG paint statics; token/arbitrary colors flow through the fill/stroke roots.
|
|
1032
|
+
fill: {
|
|
1033
|
+
currentColor: 'fill-current',
|
|
1034
|
+
none: 'fill-none',
|
|
1035
|
+
},
|
|
1036
|
+
stroke: {
|
|
1037
|
+
currentColor: 'stroke-current',
|
|
1038
|
+
none: 'stroke-none',
|
|
1039
|
+
},
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Read-side aliases: Tailwind class names that map to a value whose CANONICAL Meno
|
|
1044
|
+
* class is spelled differently (the forward mapper keeps emitting the canonical
|
|
1045
|
+
* form). Merged into `staticUtilityReverse` below.
|
|
1046
|
+
*/
|
|
1047
|
+
const staticClassAliases: Record<string, { prop: string; value: string }> = {
|
|
1048
|
+
'text-nowrap': { prop: 'whiteSpace', value: 'nowrap' }, // canonical: whitespace-nowrap
|
|
1049
|
+
'break-words': { prop: 'overflowWrap', value: 'break-word' }, // canonical: wrap-break-word
|
|
702
1050
|
};
|
|
703
1051
|
|
|
704
1052
|
/**
|
|
@@ -789,6 +1137,20 @@ export const SPACING_SCALE_ROOTS: Set<string> = new Set([
|
|
|
789
1137
|
'inset',
|
|
790
1138
|
'inset-x',
|
|
791
1139
|
'inset-y',
|
|
1140
|
+
'start',
|
|
1141
|
+
'end',
|
|
1142
|
+
'indent',
|
|
1143
|
+
'border-spacing',
|
|
1144
|
+
'scroll-m',
|
|
1145
|
+
'scroll-mt',
|
|
1146
|
+
'scroll-mr',
|
|
1147
|
+
'scroll-mb',
|
|
1148
|
+
'scroll-ml',
|
|
1149
|
+
'scroll-p',
|
|
1150
|
+
'scroll-pt',
|
|
1151
|
+
'scroll-pr',
|
|
1152
|
+
'scroll-pb',
|
|
1153
|
+
'scroll-pl',
|
|
792
1154
|
'w',
|
|
793
1155
|
'h',
|
|
794
1156
|
'size',
|
|
@@ -805,11 +1167,21 @@ export const SPACING_SCALE_ROOTS: Set<string> = new Set([
|
|
|
805
1167
|
* keyed by camelCase CSS property). Used by the inverse parser to recognize
|
|
806
1168
|
* `bg-primary` / `text-text` / `border-border` etc.
|
|
807
1169
|
*/
|
|
808
|
-
export const COLOR_TOKEN_ROOTS: Set<string> = new Set([
|
|
1170
|
+
export const COLOR_TOKEN_ROOTS: Set<string> = new Set([
|
|
1171
|
+
'text',
|
|
1172
|
+
'bg',
|
|
1173
|
+
'border',
|
|
1174
|
+
'accent',
|
|
1175
|
+
'outline',
|
|
1176
|
+
'decoration',
|
|
1177
|
+
'caret',
|
|
1178
|
+
'fill',
|
|
1179
|
+
'stroke',
|
|
1180
|
+
]);
|
|
809
1181
|
|
|
810
1182
|
/** Reverse mapping for static utilities: class → { prop, value } (canonical value). */
|
|
811
1183
|
export const staticUtilityReverse: Record<string, { prop: string; value: string }> = (() => {
|
|
812
|
-
const reverse: Record<string, { prop: string; value: string }> = {};
|
|
1184
|
+
const reverse: Record<string, { prop: string; value: string }> = { ...staticClassAliases };
|
|
813
1185
|
for (const [prop, values] of Object.entries(staticUtilities)) {
|
|
814
1186
|
for (const [value, className] of Object.entries(values)) {
|
|
815
1187
|
if (!reverse[className]) {
|
|
@@ -825,13 +1197,72 @@ export const staticUtilityReverse: Record<string, { prop: string; value: string
|
|
|
825
1197
|
* Mirrors Tailwind's named sizes (`w-full`, `h-screen`, `m-auto`, `rounded-full`).
|
|
826
1198
|
*/
|
|
827
1199
|
export const keywordValues: Record<string, Record<string, string>> = {
|
|
828
|
-
w: {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1200
|
+
w: {
|
|
1201
|
+
auto: 'auto',
|
|
1202
|
+
full: '100%',
|
|
1203
|
+
screen: '100vw',
|
|
1204
|
+
svw: '100svw',
|
|
1205
|
+
dvw: '100dvw',
|
|
1206
|
+
lvw: '100lvw',
|
|
1207
|
+
fit: 'fit-content',
|
|
1208
|
+
min: 'min-content',
|
|
1209
|
+
max: 'max-content',
|
|
1210
|
+
},
|
|
1211
|
+
h: {
|
|
1212
|
+
auto: 'auto',
|
|
1213
|
+
full: '100%',
|
|
1214
|
+
screen: '100vh',
|
|
1215
|
+
svh: '100svh',
|
|
1216
|
+
dvh: '100dvh',
|
|
1217
|
+
lvh: '100lvh',
|
|
1218
|
+
fit: 'fit-content',
|
|
1219
|
+
min: 'min-content',
|
|
1220
|
+
max: 'max-content',
|
|
1221
|
+
},
|
|
1222
|
+
'max-w': {
|
|
1223
|
+
full: '100%',
|
|
1224
|
+
none: 'none',
|
|
1225
|
+
screen: '100vw',
|
|
1226
|
+
svw: '100svw',
|
|
1227
|
+
dvw: '100dvw',
|
|
1228
|
+
lvw: '100lvw',
|
|
1229
|
+
fit: 'fit-content',
|
|
1230
|
+
min: 'min-content',
|
|
1231
|
+
max: 'max-content',
|
|
1232
|
+
},
|
|
1233
|
+
'max-h': {
|
|
1234
|
+
full: '100%',
|
|
1235
|
+
none: 'none',
|
|
1236
|
+
screen: '100vh',
|
|
1237
|
+
svh: '100svh',
|
|
1238
|
+
dvh: '100dvh',
|
|
1239
|
+
lvh: '100lvh',
|
|
1240
|
+
fit: 'fit-content',
|
|
1241
|
+
min: 'min-content',
|
|
1242
|
+
max: 'max-content',
|
|
1243
|
+
},
|
|
832
1244
|
size: { auto: 'auto', full: '100%', fit: 'fit-content', min: 'min-content', max: 'max-content' },
|
|
833
|
-
'min-w': {
|
|
834
|
-
|
|
1245
|
+
'min-w': {
|
|
1246
|
+
auto: 'auto',
|
|
1247
|
+
full: '100%',
|
|
1248
|
+
svw: '100svw',
|
|
1249
|
+
dvw: '100dvw',
|
|
1250
|
+
lvw: '100lvw',
|
|
1251
|
+
fit: 'fit-content',
|
|
1252
|
+
min: 'min-content',
|
|
1253
|
+
max: 'max-content',
|
|
1254
|
+
},
|
|
1255
|
+
'min-h': {
|
|
1256
|
+
auto: 'auto',
|
|
1257
|
+
full: '100%',
|
|
1258
|
+
screen: '100vh',
|
|
1259
|
+
svh: '100svh',
|
|
1260
|
+
dvh: '100dvh',
|
|
1261
|
+
lvh: '100lvh',
|
|
1262
|
+
fit: 'fit-content',
|
|
1263
|
+
min: 'min-content',
|
|
1264
|
+
max: 'max-content',
|
|
1265
|
+
},
|
|
835
1266
|
m: { auto: 'auto' },
|
|
836
1267
|
mt: { auto: 'auto' },
|
|
837
1268
|
mr: { auto: 'auto' },
|
|
@@ -857,19 +1288,45 @@ export const keywordValues: Record<string, Record<string, string>> = {
|
|
|
857
1288
|
'inset-y': { auto: 'auto', full: '100%' },
|
|
858
1289
|
aspect: { auto: 'auto', square: '1 / 1', video: '16 / 9' },
|
|
859
1290
|
order: { first: '-9999', last: '9999', none: '0' },
|
|
1291
|
+
'will-change': { scroll: 'scroll-position' }, // other values (transform, contents, auto) pass through generically
|
|
1292
|
+
columns: { auto: 'auto' },
|
|
1293
|
+
start: { auto: 'auto', full: '100%' },
|
|
1294
|
+
end: { auto: 'auto', full: '100%' },
|
|
1295
|
+
'underline-offset': { auto: 'auto' },
|
|
1296
|
+
'auto-cols': { auto: 'auto', min: 'min-content', max: 'max-content', fr: 'minmax(0, 1fr)' },
|
|
1297
|
+
'auto-rows': { auto: 'auto', min: 'min-content', max: 'max-content', fr: 'minmax(0, 1fr)' },
|
|
1298
|
+
col: { auto: 'auto' },
|
|
1299
|
+
row: { auto: 'auto' },
|
|
1300
|
+
decoration: { 'from-font': 'from-font' }, // thickness keyword; style keywords are statics, colors flow via value type
|
|
860
1301
|
};
|
|
861
1302
|
|
|
862
1303
|
/**
|
|
863
1304
|
* Roots whose plain lowercase keyword values pass through verbatim:
|
|
864
1305
|
* `cursor-pointer`, `align-middle`, `origin-center`, `object-center`, …
|
|
865
1306
|
*/
|
|
866
|
-
export const genericKeywordRoots: Set<string> = new Set([
|
|
1307
|
+
export const genericKeywordRoots: Set<string> = new Set([
|
|
1308
|
+
'cursor',
|
|
1309
|
+
'align',
|
|
1310
|
+
'origin',
|
|
1311
|
+
'object',
|
|
1312
|
+
'list',
|
|
1313
|
+
'mix-blend',
|
|
1314
|
+
'bg-blend',
|
|
1315
|
+
'will-change',
|
|
1316
|
+
'overscroll',
|
|
1317
|
+
'overscroll-x',
|
|
1318
|
+
'overscroll-y',
|
|
1319
|
+
'touch',
|
|
1320
|
+
'break-after',
|
|
1321
|
+
'break-before',
|
|
1322
|
+
'break-inside',
|
|
1323
|
+
]);
|
|
867
1324
|
|
|
868
1325
|
/**
|
|
869
1326
|
* Roots that accept bare numeric values Tailwind-style: `z-10`, `order-2`,
|
|
870
1327
|
* `flex-2`, `grow-2`. (`opacity` is handled separately — Tailwind's 0–100 scale.)
|
|
871
1328
|
*/
|
|
872
|
-
export const integerValueRoots: Set<string> = new Set(['z', 'order', 'flex', 'grow', 'shrink']);
|
|
1329
|
+
export const integerValueRoots: Set<string> = new Set(['z', 'order', 'flex', 'grow', 'shrink', 'columns', 'stroke']);
|
|
873
1330
|
|
|
874
1331
|
/**
|
|
875
1332
|
* Properties whose values are color tokens by Meno convention: a bare token
|
|
@@ -882,6 +1339,10 @@ export const colorTokenProps: Set<string> = new Set([
|
|
|
882
1339
|
'borderColor',
|
|
883
1340
|
'accentColor',
|
|
884
1341
|
'outlineColor',
|
|
1342
|
+
'textDecorationColor',
|
|
1343
|
+
'caretColor',
|
|
1344
|
+
'fill',
|
|
1345
|
+
'stroke',
|
|
885
1346
|
]);
|
|
886
1347
|
|
|
887
1348
|
/**
|