meno-core 1.0.45 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/build-astro.ts +214 -63
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/build-static.js +7 -7
  4. package/dist/chunks/{chunk-NZTSJS5C.js → chunk-2QK6U5UK.js} +3 -2
  5. package/dist/chunks/{chunk-NZTSJS5C.js.map → chunk-2QK6U5UK.js.map} +2 -2
  6. package/dist/chunks/{chunk-BZQKEJQY.js → chunk-77ZB6353.js} +29 -18
  7. package/dist/chunks/chunk-77ZB6353.js.map +7 -0
  8. package/dist/chunks/{chunk-TVH3TC2T.js → chunk-C6U5T5S5.js} +6 -6
  9. package/dist/chunks/{chunk-5ZASE4IG.js → chunk-FED5MME6.js} +234 -11
  10. package/dist/chunks/{chunk-5ZASE4IG.js.map → chunk-FED5MME6.js.map} +3 -3
  11. package/dist/chunks/{chunk-5Z5VQRTJ.js → chunk-I7YIGZXT.js} +4 -4
  12. package/dist/chunks/{chunk-5Z5VQRTJ.js.map → chunk-I7YIGZXT.js.map} +2 -2
  13. package/dist/chunks/{chunk-OUNJ76QM.js → chunk-ORN7S4AP.js} +5 -5
  14. package/dist/chunks/{chunk-GYF3ABI3.js → chunk-UUA5LEWF.js} +3 -3
  15. package/dist/chunks/{chunk-GYF3ABI3.js.map → chunk-UUA5LEWF.js.map} +2 -2
  16. package/dist/chunks/{chunk-WQSG5WHC.js → chunk-ZTKHJQ2Z.js} +2 -2
  17. package/dist/chunks/{chunk-F7MA62WG.js → chunk-ZWYDT3QJ.js} +3 -3
  18. package/dist/chunks/{configService-6KTT6GRT.js → configService-DYCUEURL.js} +3 -3
  19. package/dist/chunks/{constants-L5IKLB6U.js → constants-GWBAD66U.js} +2 -2
  20. package/dist/entries/server-router.js +7 -7
  21. package/dist/lib/client/index.js +4 -4
  22. package/dist/lib/server/index.js +586 -142
  23. package/dist/lib/server/index.js.map +3 -3
  24. package/dist/lib/shared/index.js +7 -3
  25. package/dist/lib/shared/index.js.map +2 -2
  26. package/dist/lib/test-utils/index.js +1 -1
  27. package/lib/client/templateEngine.test.ts +64 -0
  28. package/lib/server/astro/astroEmitHelpers.ts +18 -0
  29. package/lib/server/astro/cmsPageEmitter.ts +31 -1
  30. package/lib/server/astro/componentEmitter.test.ts +59 -0
  31. package/lib/server/astro/componentEmitter.ts +43 -10
  32. package/lib/server/astro/cssCollector.ts +58 -11
  33. package/lib/server/astro/nodeToAstro.test.ts +397 -5
  34. package/lib/server/astro/nodeToAstro.ts +478 -63
  35. package/lib/server/astro/pageEmitter.ts +31 -1
  36. package/lib/server/astro/tailwindMapper.test.ts +119 -0
  37. package/lib/server/astro/tailwindMapper.ts +67 -1
  38. package/lib/server/runtime/httpServer.ts +12 -4
  39. package/lib/server/ssr/htmlGenerator.ts +1 -1
  40. package/lib/server/ssr/jsCollector.ts +2 -2
  41. package/lib/server/ssr/ssrRenderer.test.ts +32 -0
  42. package/lib/server/ssr/ssrRenderer.ts +26 -11
  43. package/lib/shared/constants.ts +1 -0
  44. package/lib/shared/cssGeneration.test.ts +109 -3
  45. package/lib/shared/cssGeneration.ts +98 -13
  46. package/lib/shared/cssNamedColors.ts +47 -0
  47. package/lib/shared/cssProperties.ts +2 -2
  48. package/lib/shared/index.ts +1 -0
  49. package/package.json +1 -1
  50. package/dist/chunks/chunk-BZQKEJQY.js.map +0 -7
  51. /package/dist/chunks/{chunk-TVH3TC2T.js.map → chunk-C6U5T5S5.js.map} +0 -0
  52. /package/dist/chunks/{chunk-OUNJ76QM.js.map → chunk-ORN7S4AP.js.map} +0 -0
  53. /package/dist/chunks/{chunk-WQSG5WHC.js.map → chunk-ZTKHJQ2Z.js.map} +0 -0
  54. /package/dist/chunks/{chunk-F7MA62WG.js.map → chunk-ZWYDT3QJ.js.map} +0 -0
  55. /package/dist/chunks/{configService-6KTT6GRT.js.map → configService-DYCUEURL.js.map} +0 -0
  56. /package/dist/chunks/{constants-L5IKLB6U.js.map → constants-GWBAD66U.js.map} +0 -0
@@ -6,10 +6,11 @@
6
6
 
7
7
  import { prefixToCSSProperty, propertyMap } from './utilityClassConfig';
8
8
  import { getStyleValue, getDynamicStyle, isDynamicClass } from './styleValueRegistry';
9
+ import { isCssNamedColor } from './cssNamedColors';
9
10
  import type { BreakpointConfig, LegacyBreakpointConfig } from './breakpoints';
10
11
  import { DEFAULT_BREAKPOINTS, getBreakpointValues } from './breakpoints';
11
- import type { ResponsiveScales } from './responsiveScaling';
12
- import { scalePropertyValue } from './responsiveScaling';
12
+ import type { ResponsiveScales, CSSPropertyType } from './responsiveScaling';
13
+ import { scalePropertyValue, getScaleMultiplier } from './responsiveScaling';
13
14
  import type { InteractiveStyles, StyleObject, ResponsiveStyleObject, StyleValue } from './types/styles';
14
15
  import type { RemConversionConfig } from './pxToRem';
15
16
  import { applyRemConversion, convertPxToRem, shouldConvertProperty } from './pxToRem';
@@ -395,7 +396,11 @@ export function generateRuleForClass(className: string): string | null {
395
396
  // unless it's a hex color (#...) or RGB value
396
397
  if ((prefix === 'bgc' || prefix === 'bg' || prefix === 'c' || prefix === 'bc')) {
397
398
  // If it's not a hex color, RGB value, or pixel value, treat it as a CSS variable name
399
+ // Unless it's a CSS named color (red, blue, transparent, etc.) — use directly
398
400
  if (!value.startsWith('#') && !value.includes('rgb') && !value.includes('px')) {
401
+ if (isCssNamedColor(value)) {
402
+ return `${cssProp}: ${value};`;
403
+ }
399
404
  return `${cssProp}: var(--${value});`;
400
405
  }
401
406
  }
@@ -849,12 +854,14 @@ export function generateInteractiveCSS(
849
854
  elementClass: string,
850
855
  interactiveStyles: InteractiveStyles,
851
856
  breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS,
852
- remConfig?: RemConversionConfig
857
+ remConfig?: RemConversionConfig,
858
+ responsiveScales?: ResponsiveScales
853
859
  ): string {
854
860
  const css: string[] = [];
855
861
 
856
862
  // Extract breakpoint values for CSS media queries
857
863
  const breakpointValues = getBreakpointValues(breakpoints);
864
+ const scalingEnabled = responsiveScales?.enabled === true;
858
865
 
859
866
  for (const rule of interactiveStyles) {
860
867
  const { prefix, postfix, style } = rule;
@@ -862,6 +869,11 @@ export function generateInteractiveCSS(
862
869
  // Build full selector: {prefix}.element{postfix}
863
870
  const fullSelector = `${prefix || ''}.${elementClass}${postfix || ''}`;
864
871
 
872
+ // Breakpoint styles (sorted by value descending)
873
+ const sortedBreakpoints = Object.entries(breakpointValues).sort(
874
+ ([, a], [, b]) => b - a
875
+ );
876
+
865
877
  if (isResponsiveStyle(style)) {
866
878
  // Generate responsive rules
867
879
  const responsive = style as ResponsiveStyleObject;
@@ -874,15 +886,30 @@ export function generateInteractiveCSS(
874
886
  }
875
887
  }
876
888
 
877
- // Breakpoint styles (sorted by value descending)
878
- const sortedBreakpoints = Object.entries(breakpointValues).sort(
879
- ([, a], [, b]) => b - a
880
- );
881
-
882
889
  for (const [breakpointName, breakpointValue] of sortedBreakpoints) {
883
- const breakpointStyles = responsive[breakpointName];
884
- if (breakpointStyles && Object.keys(breakpointStyles).length > 0) {
885
- const properties = applyRemConversion(styleObjectToCSS(breakpointStyles), remConfig);
890
+ const explicit = responsive[breakpointName];
891
+
892
+ // Merge explicit breakpoint styles with auto-scaled values derived
893
+ // from the base, skipping any property the author explicitly set.
894
+ let merged: StyleObject | null = null;
895
+ if (explicit && Object.keys(explicit).length > 0) {
896
+ merged = { ...explicit };
897
+ }
898
+
899
+ if (scalingEnabled && responsive.base) {
900
+ const scaled = scaleStyleForBreakpoint(
901
+ responsive.base,
902
+ responsiveScales!,
903
+ breakpointName,
904
+ new Set(Object.keys(explicit ?? {}))
905
+ );
906
+ if (Object.keys(scaled).length > 0) {
907
+ merged = { ...(merged ?? {}), ...scaled };
908
+ }
909
+ }
910
+
911
+ if (merged && Object.keys(merged).length > 0) {
912
+ const properties = applyRemConversion(styleObjectToCSS(merged), remConfig);
886
913
  if (properties) {
887
914
  css.push(
888
915
  `@media (max-width: ${breakpointValue}px) { ${fullSelector} { ${properties}; } }`
@@ -898,6 +925,24 @@ export function generateInteractiveCSS(
898
925
  if (properties) {
899
926
  css.push(`${fullSelector} { ${properties}; }`);
900
927
  }
928
+
929
+ // Auto-scale the flat style into each enabled breakpoint.
930
+ if (scalingEnabled) {
931
+ for (const [breakpointName, breakpointValue] of sortedBreakpoints) {
932
+ const scaled = scaleStyleForBreakpoint(
933
+ flatStyle,
934
+ responsiveScales!,
935
+ breakpointName,
936
+ new Set()
937
+ );
938
+ if (Object.keys(scaled).length === 0) continue;
939
+ const scaledProps = applyRemConversion(styleObjectToCSS(scaled), remConfig);
940
+ if (!scaledProps) continue;
941
+ css.push(
942
+ `@media (max-width: ${breakpointValue}px) { ${fullSelector} { ${scaledProps}; } }`
943
+ );
944
+ }
945
+ }
901
946
  }
902
947
  }
903
948
  }
@@ -905,6 +950,45 @@ export function generateInteractiveCSS(
905
950
  return css.join('\n');
906
951
  }
907
952
 
953
+ /**
954
+ * Build a new style object containing auto-scaled values for every property
955
+ * in a given base style that falls into a scale category at `breakpointName`.
956
+ * Properties listed in `skipProperties` are left out (the author has set an
957
+ * explicit override at that breakpoint).
958
+ */
959
+ function scaleStyleForBreakpoint(
960
+ baseStyle: StyleObject,
961
+ responsiveScales: ResponsiveScales,
962
+ breakpointName: string,
963
+ skipProperties: Set<string>
964
+ ): StyleObject {
965
+ const result: StyleObject = {};
966
+ const baseRef = responsiveScales.baseReference ?? 16;
967
+
968
+ for (const [property, value] of Object.entries(baseStyle)) {
969
+ if (skipProperties.has(property)) continue;
970
+ if (typeof value === 'object' && value !== null && '_mapping' in value) continue;
971
+ if (value == null) continue;
972
+
973
+ const strValue = String(value);
974
+ if (strValue === '') continue;
975
+
976
+ const scale = getScaleMultiplier(
977
+ responsiveScales,
978
+ property as CSSPropertyType,
979
+ breakpointName
980
+ );
981
+ if (scale == null) continue;
982
+
983
+ const scaledValue = scalePropertyValue(strValue, baseRef, scale);
984
+ if (scaledValue == null || scaledValue === strValue) continue;
985
+
986
+ result[property] = scaledValue;
987
+ }
988
+
989
+ return result;
990
+ }
991
+
908
992
  /**
909
993
  * Collect and generate CSS for all interactive styles in a page/component
910
994
  *
@@ -915,12 +999,13 @@ export function generateInteractiveCSS(
915
999
  export function generateAllInteractiveCSS(
916
1000
  interactiveStylesMap: Map<string, InteractiveStyles>,
917
1001
  breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS,
918
- remConfig?: RemConversionConfig
1002
+ remConfig?: RemConversionConfig,
1003
+ responsiveScales?: ResponsiveScales
919
1004
  ): string {
920
1005
  const cssBlocks: string[] = [];
921
1006
 
922
1007
  for (const [elementClass, styles] of interactiveStylesMap) {
923
- const css = generateInteractiveCSS(elementClass, styles, breakpoints, remConfig);
1008
+ const css = generateInteractiveCSS(elementClass, styles, breakpoints, remConfig, responsiveScales);
924
1009
  if (css) {
925
1010
  cssBlocks.push(css);
926
1011
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * CSS Named Colors
3
+ * Complete set of CSS Level 4 named colors + keywords
4
+ * Used to distinguish named colors from CSS variable references
5
+ */
6
+
7
+ export const CSS_NAMED_COLORS: ReadonlySet<string> = new Set([
8
+ // CSS Level 4 named colors
9
+ 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
10
+ 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood',
11
+ 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan',
12
+ 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki',
13
+ 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon',
14
+ 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet',
15
+ 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue',
16
+ 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia',
17
+ 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey',
18
+ 'honeydew', 'hotpink',
19
+ 'indianred', 'indigo', 'ivory',
20
+ 'khaki',
21
+ 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
22
+ 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon',
23
+ 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
24
+ 'lime', 'limegreen', 'linen',
25
+ 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
26
+ 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred',
27
+ 'midnightblue', 'mintcream', 'mistyrose', 'moccasin',
28
+ 'navajowhite', 'navy',
29
+ 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid',
30
+ 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff',
31
+ 'peru', 'pink', 'plum', 'powderblue', 'purple',
32
+ 'rebeccapurple', 'red', 'rosybrown', 'royalblue',
33
+ 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue',
34
+ 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue',
35
+ 'tan', 'teal', 'thistle', 'tomato', 'turquoise',
36
+ 'violet',
37
+ 'wheat', 'white', 'whitesmoke',
38
+ 'yellow', 'yellowgreen',
39
+ // CSS color keywords
40
+ 'transparent', 'currentcolor',
41
+ // CSS-wide keywords (should never be wrapped in var())
42
+ 'inherit', 'initial', 'unset', 'revert',
43
+ ]);
44
+
45
+ export function isCssNamedColor(value: string): boolean {
46
+ return CSS_NAMED_COLORS.has(value.toLowerCase());
47
+ }
@@ -495,7 +495,7 @@ function matchesAbbreviation(property: string, input: string): boolean {
495
495
  * Supports both startsWith matching and camelCase abbreviation matching
496
496
  */
497
497
  export function filterCSSProperties(input: string): string[] {
498
- const normalizedInput = input.trim();
498
+ const normalizedInput = (input ?? '').trim();
499
499
  if (!normalizedInput) {
500
500
  return CSS_PROPERTIES.slice(0, 15); // Show first 15 by default
501
501
  }
@@ -544,7 +544,7 @@ export function filterPropertyValues(propertyName: string, input: string): strin
544
544
  return []; // No predefined values for this property
545
545
  }
546
546
 
547
- const normalizedInput = input.trim().toLowerCase();
547
+ const normalizedInput = (input ?? '').trim().toLowerCase();
548
548
  if (!normalizedInput) {
549
549
  return values; // Return all values if no input
550
550
  }
@@ -23,6 +23,7 @@ export * from './styleUtils';
23
23
  export * from './cssProperties';
24
24
  export * from './cssGeneration';
25
25
  export * from './colorProperties';
26
+ export * from './cssNamedColors';
26
27
  export * from './utilityClassMapper';
27
28
  export * from './elementClassName';
28
29
  export * from './styleValueRegistry';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meno-core",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "meno": "./dist/bin/cli.js"