meno-core 1.1.4 → 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.
@@ -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
@@ -394,6 +425,71 @@ export const prefixToCSSProperty: Record<string, string> = {
394
425
  'text-shadow': 'text-shadow',
395
426
  filter: 'filter',
396
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',
397
493
 
398
494
  // Positioning
399
495
  top: 'top',
@@ -403,6 +499,8 @@ export const prefixToCSSProperty: Record<string, string> = {
403
499
  inset: 'inset',
404
500
  'inset-x': 'inset-inline',
405
501
  'inset-y': 'inset-block',
502
+ start: 'inset-inline-start',
503
+ end: 'inset-inline-end',
406
504
  z: 'z-index',
407
505
 
408
506
  // Outline
@@ -418,6 +516,75 @@ export const prefixToCSSProperty: Record<string, string> = {
418
516
  object: 'object-position',
419
517
  };
420
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
+
421
588
  /**
422
589
  * Static utilities: property → value → Tailwind class name.
423
590
  * These are emitted as-is (no brackets) and have fixed reverse mappings.
@@ -438,6 +605,14 @@ export const staticUtilities: Record<string, Record<string, string>> = {
438
605
  contents: 'contents',
439
606
  'flow-root': 'flow-root',
440
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',
441
616
  },
442
617
  flexDirection: {
443
618
  column: 'flex-col',
@@ -694,6 +869,7 @@ export const staticUtilities: Record<string, Record<string, string>> = {
694
869
  },
695
870
  transform: {
696
871
  none: 'transform-none',
872
+ 'translateZ(0)': 'transform-gpu',
697
873
  },
698
874
  boxShadow: {
699
875
  none: 'shadow-none',
@@ -701,6 +877,176 @@ export const staticUtilities: Record<string, Record<string, string>> = {
701
877
  outline: {
702
878
  none: 'outline-none',
703
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
704
1050
  };
705
1051
 
706
1052
  /**
@@ -791,6 +1137,20 @@ export const SPACING_SCALE_ROOTS: Set<string> = new Set([
791
1137
  'inset',
792
1138
  'inset-x',
793
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',
794
1154
  'w',
795
1155
  'h',
796
1156
  'size',
@@ -807,11 +1167,21 @@ export const SPACING_SCALE_ROOTS: Set<string> = new Set([
807
1167
  * keyed by camelCase CSS property). Used by the inverse parser to recognize
808
1168
  * `bg-primary` / `text-text` / `border-border` etc.
809
1169
  */
810
- export const COLOR_TOKEN_ROOTS: Set<string> = new Set(['text', 'bg', 'border', 'accent', 'outline']);
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
+ ]);
811
1181
 
812
1182
  /** Reverse mapping for static utilities: class → { prop, value } (canonical value). */
813
1183
  export const staticUtilityReverse: Record<string, { prop: string; value: string }> = (() => {
814
- const reverse: Record<string, { prop: string; value: string }> = {};
1184
+ const reverse: Record<string, { prop: string; value: string }> = { ...staticClassAliases };
815
1185
  for (const [prop, values] of Object.entries(staticUtilities)) {
816
1186
  for (const [value, className] of Object.entries(values)) {
817
1187
  if (!reverse[className]) {
@@ -827,13 +1197,72 @@ export const staticUtilityReverse: Record<string, { prop: string; value: string
827
1197
  * Mirrors Tailwind's named sizes (`w-full`, `h-screen`, `m-auto`, `rounded-full`).
828
1198
  */
829
1199
  export const keywordValues: Record<string, Record<string, string>> = {
830
- w: { auto: 'auto', full: '100%', screen: '100vw', fit: 'fit-content', min: 'min-content', max: 'max-content' },
831
- h: { auto: 'auto', full: '100%', screen: '100vh', fit: 'fit-content', min: 'min-content', max: 'max-content' },
832
- 'max-w': { full: '100%', none: 'none', screen: '100vw', fit: 'fit-content', min: 'min-content', max: 'max-content' },
833
- 'max-h': { full: '100%', none: 'none', screen: '100vh', fit: 'fit-content', min: 'min-content', max: 'max-content' },
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
+ },
834
1244
  size: { auto: 'auto', full: '100%', fit: 'fit-content', min: 'min-content', max: 'max-content' },
835
- 'min-w': { auto: 'auto', full: '100%', fit: 'fit-content', min: 'min-content', max: 'max-content' },
836
- 'min-h': { auto: 'auto', full: '100%', screen: '100vh', fit: 'fit-content', min: 'min-content', max: 'max-content' },
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
+ },
837
1266
  m: { auto: 'auto' },
838
1267
  mt: { auto: 'auto' },
839
1268
  mr: { auto: 'auto' },
@@ -859,19 +1288,45 @@ export const keywordValues: Record<string, Record<string, string>> = {
859
1288
  'inset-y': { auto: 'auto', full: '100%' },
860
1289
  aspect: { auto: 'auto', square: '1 / 1', video: '16 / 9' },
861
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
862
1301
  };
863
1302
 
864
1303
  /**
865
1304
  * Roots whose plain lowercase keyword values pass through verbatim:
866
1305
  * `cursor-pointer`, `align-middle`, `origin-center`, `object-center`, …
867
1306
  */
868
- export const genericKeywordRoots: Set<string> = new Set(['cursor', 'align', 'origin', 'object', 'list']);
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
+ ]);
869
1324
 
870
1325
  /**
871
1326
  * Roots that accept bare numeric values Tailwind-style: `z-10`, `order-2`,
872
1327
  * `flex-2`, `grow-2`. (`opacity` is handled separately — Tailwind's 0–100 scale.)
873
1328
  */
874
- 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']);
875
1330
 
876
1331
  /**
877
1332
  * Properties whose values are color tokens by Meno convention: a bare token
@@ -884,6 +1339,10 @@ export const colorTokenProps: Set<string> = new Set([
884
1339
  'borderColor',
885
1340
  'accentColor',
886
1341
  'outlineColor',
1342
+ 'textDecorationColor',
1343
+ 'caretColor',
1344
+ 'fill',
1345
+ 'stroke',
887
1346
  ]);
888
1347
 
889
1348
  /**