meno-core 1.0.48 → 1.0.49

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 (74) hide show
  1. package/dist/build-static.js +7 -7
  2. package/dist/chunks/{chunk-UUA5LEWF.js → chunk-6IVUG7FY.js} +138 -7
  3. package/dist/chunks/chunk-6IVUG7FY.js.map +7 -0
  4. package/dist/chunks/{chunk-B2RTLDXY.js → chunk-AZQYF6KE.js} +132 -1
  5. package/dist/chunks/chunk-AZQYF6KE.js.map +7 -0
  6. package/dist/chunks/{chunk-NKUV77SR.js → chunk-CHD5UCFF.js} +21 -9
  7. package/dist/chunks/{chunk-NKUV77SR.js.map → chunk-CHD5UCFF.js.map} +2 -2
  8. package/dist/chunks/{chunk-TPQ7APVQ.js → chunk-EQYDSPBB.js} +418 -62
  9. package/dist/chunks/chunk-EQYDSPBB.js.map +7 -0
  10. package/dist/chunks/{chunk-RQSTH2BS.js → chunk-H4JSCDNW.js} +2 -2
  11. package/dist/chunks/{chunk-EK4KESLU.js → chunk-J23ZX5AP.js} +8 -2
  12. package/dist/chunks/{chunk-EK4KESLU.js.map → chunk-J23ZX5AP.js.map} +2 -2
  13. package/dist/chunks/{chunk-D5E3OKSL.js → chunk-JER5NQVM.js} +5 -5
  14. package/dist/chunks/{chunk-BJRKEPMP.js → chunk-KPU2XHOS.js} +5 -2
  15. package/dist/chunks/{chunk-BJRKEPMP.js.map → chunk-KPU2XHOS.js.map} +2 -2
  16. package/dist/chunks/{chunk-NP76N4HQ.js → chunk-LKAGAQ3M.js} +2 -2
  17. package/dist/chunks/{chunk-3FHJUHAS.js → chunk-S2CX6HFM.js} +260 -25
  18. package/dist/chunks/chunk-S2CX6HFM.js.map +7 -0
  19. package/dist/chunks/{configService-IGJEC3MC.js → configService-CCA6AIDI.js} +3 -3
  20. package/dist/entries/server-router.js +9 -9
  21. package/dist/entries/server-router.js.map +2 -2
  22. package/dist/lib/client/index.js +54 -20
  23. package/dist/lib/client/index.js.map +3 -3
  24. package/dist/lib/server/index.js +9 -9
  25. package/dist/lib/shared/index.js +46 -10
  26. package/dist/lib/shared/index.js.map +3 -3
  27. package/entries/server-router.tsx +6 -2
  28. package/lib/client/core/ComponentBuilder.ts +8 -1
  29. package/lib/client/core/builders/embedBuilder.ts +15 -2
  30. package/lib/client/core/builders/linkNodeBuilder.ts +15 -2
  31. package/lib/client/core/builders/localeListBuilder.ts +17 -6
  32. package/lib/client/styles/StyleInjector.ts +3 -2
  33. package/lib/client/theme.ts +4 -4
  34. package/lib/server/cssGenerator.test.ts +64 -1
  35. package/lib/server/cssGenerator.ts +48 -9
  36. package/lib/server/providers/fileSystemCMSProvider.test.ts +163 -0
  37. package/lib/server/providers/fileSystemCMSProvider.ts +200 -11
  38. package/lib/server/routes/index.ts +1 -1
  39. package/lib/server/routes/pages.ts +23 -1
  40. package/lib/server/services/cmsService.test.ts +246 -0
  41. package/lib/server/services/cmsService.ts +122 -5
  42. package/lib/server/services/configService.ts +5 -0
  43. package/lib/server/ssr/attributeBuilder.ts +41 -0
  44. package/lib/server/ssr/htmlGenerator.test.ts +113 -0
  45. package/lib/server/ssr/htmlGenerator.ts +51 -4
  46. package/lib/server/ssr/liveReloadIntegration.test.ts +209 -0
  47. package/lib/server/ssr/ssrRenderer.test.ts +306 -0
  48. package/lib/server/ssr/ssrRenderer.ts +182 -44
  49. package/lib/shared/cssGeneration.test.ts +267 -1
  50. package/lib/shared/cssGeneration.ts +240 -18
  51. package/lib/shared/cssProperties.test.ts +247 -1
  52. package/lib/shared/cssProperties.ts +196 -6
  53. package/lib/shared/interfaces/contentProvider.ts +39 -6
  54. package/lib/shared/pathSecurity.ts +16 -0
  55. package/lib/shared/responsiveScaling.test.ts +143 -0
  56. package/lib/shared/responsiveScaling.ts +253 -2
  57. package/lib/shared/themeDefaults.test.ts +3 -3
  58. package/lib/shared/themeDefaults.ts +3 -3
  59. package/lib/shared/types/cms.ts +28 -3
  60. package/lib/shared/types/index.ts +1 -0
  61. package/lib/shared/utilityClassConfig.ts +3 -0
  62. package/lib/shared/utilityClassMapper.test.ts +123 -0
  63. package/lib/shared/utilityClassMapper.ts +179 -8
  64. package/lib/shared/validation/schemas.ts +15 -1
  65. package/lib/shared/validation/validators.ts +26 -1
  66. package/package.json +1 -1
  67. package/dist/chunks/chunk-3FHJUHAS.js.map +0 -7
  68. package/dist/chunks/chunk-B2RTLDXY.js.map +0 -7
  69. package/dist/chunks/chunk-TPQ7APVQ.js.map +0 -7
  70. package/dist/chunks/chunk-UUA5LEWF.js.map +0 -7
  71. /package/dist/chunks/{chunk-RQSTH2BS.js.map → chunk-H4JSCDNW.js.map} +0 -0
  72. /package/dist/chunks/{chunk-D5E3OKSL.js.map → chunk-JER5NQVM.js.map} +0 -0
  73. /package/dist/chunks/{chunk-NP76N4HQ.js.map → chunk-LKAGAQ3M.js.map} +0 -0
  74. /package/dist/chunks/{configService-IGJEC3MC.js.map → configService-CCA6AIDI.js.map} +0 -0
@@ -9,15 +9,15 @@ import {
9
9
  hashContent,
10
10
  injectTrackingScript,
11
11
  isCMSPage
12
- } from "./chunks/chunk-D5E3OKSL.js";
13
- import "./chunks/chunk-TPQ7APVQ.js";
14
- import "./chunks/chunk-BJRKEPMP.js";
12
+ } from "./chunks/chunk-JER5NQVM.js";
13
+ import "./chunks/chunk-EQYDSPBB.js";
14
+ import "./chunks/chunk-KPU2XHOS.js";
15
15
  import "./chunks/chunk-I7YIGZXT.js";
16
16
  import "./chunks/chunk-WQFG7PAH.js";
17
- import "./chunks/chunk-EK4KESLU.js";
18
- import "./chunks/chunk-NP76N4HQ.js";
19
- import "./chunks/chunk-3FHJUHAS.js";
20
- import "./chunks/chunk-B2RTLDXY.js";
17
+ import "./chunks/chunk-J23ZX5AP.js";
18
+ import "./chunks/chunk-LKAGAQ3M.js";
19
+ import "./chunks/chunk-S2CX6HFM.js";
20
+ import "./chunks/chunk-AZQYF6KE.js";
21
21
  import "./chunks/chunk-UB44F4Z2.js";
22
22
  import "./chunks/chunk-2QK6U5UK.js";
23
23
  import "./chunks/chunk-KSBZ2L7C.js";
@@ -378,14 +378,15 @@ function getPropertyPriority(property) {
378
378
  return CSS_PROPERTY_PRIORITY[property] ?? 3;
379
379
  }
380
380
  var CSS_PROPERTY_GROUPS = {
381
- "Layout": ["display", "position", "top", "right", "bottom", "left", "inset", "zIndex"],
382
- "Dimensions": ["width", "height", "minWidth", "maxWidth", "minHeight", "maxHeight", "aspectRatio"],
383
- "Spacing": ["margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft", "gap", "rowGap", "columnGap"],
384
- "Flexbox": ["flex", "flexDirection", "flexWrap", "flexFlow", "justifyContent", "alignItems", "alignContent", "alignSelf", "flexGrow", "flexShrink", "flexBasis", "order"],
381
+ "Layout": ["display"],
382
+ "Spacing": ["margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft"],
383
+ "Size": ["width", "height", "minWidth", "maxWidth", "minHeight", "maxHeight", "aspectRatio"],
384
+ "Position": ["position", "top", "right", "bottom", "left", "inset", "zIndex"],
385
+ "Flexbox": ["flex", "flexDirection", "flexWrap", "flexFlow", "justifyContent", "alignItems", "alignContent", "gap", "rowGap", "columnGap", "alignSelf", "flexGrow", "flexShrink", "flexBasis", "order"],
385
386
  "Grid": ["grid", "gridTemplateColumns", "gridTemplateRows", "gridTemplateAreas", "gridGap", "gridColumn", "gridRow", "gridArea", "gridAutoFlow", "gridAutoColumns", "gridAutoRows", "justifyItems", "justifySelf", "placeContent", "placeItems", "placeSelf"],
386
- "Typography": ["fontSize", "fontWeight", "fontFamily", "fontStyle", "lineHeight", "textAlign", "textDecoration", "textTransform", "letterSpacing", "wordSpacing", "wordBreak", "overflowWrap", "textIndent", "verticalAlign", "color"],
387
+ "Typography": ["fontWeight", "fontSize", "fontFamily", "fontStyle", "lineHeight", "color", "textAlign", "textDecoration", "textTransform", "letterSpacing", "wordSpacing", "wordBreak", "overflowWrap", "textIndent", "verticalAlign"],
387
388
  "Background": ["background", "backgroundColor", "backgroundImage", "backgroundSize", "backgroundPosition", "backgroundRepeat", "opacity"],
388
- "Borders": ["border", "borderWidth", "borderStyle", "borderColor", "borderTop", "borderRight", "borderBottom", "borderLeft", "borderRadius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomLeftRadius", "borderBottomRightRadius"],
389
+ "Borders": ["borderRadius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomLeftRadius", "borderBottomRightRadius", "border", "borderWidth", "borderStyle", "borderColor", "borderTop", "borderRight", "borderBottom", "borderLeft"],
389
390
  "Outline": ["outline", "outlineWidth", "outlineStyle", "outlineColor", "outlineOffset"],
390
391
  "Effects": ["boxShadow", "textShadow", "filter", "backdropFilter", "transform", "transformOrigin", "transition", "animation", "backfaceVisibility", "mixBlendMode", "clipPath"],
391
392
  "Overflow": ["overflow", "overflowX", "overflowY", "whiteSpace", "textOverflow", "visibility", "content"],
@@ -402,6 +403,97 @@ function getPropertyGroup(propertyName) {
402
403
  }
403
404
  return "Other";
404
405
  }
406
+ var VISUAL_MODE_PROPERTIES = {
407
+ "Layout": ["display"],
408
+ "Grid": ["gridTemplateColumns"],
409
+ "Flexbox": ["flexDirection", "flexWrap", "justifyContent", "alignItems", "gap", "flexGrow", "flexShrink", "flexBasis"],
410
+ "Spacing": ["margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft"],
411
+ "Size": ["width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight"],
412
+ "Position": ["position", "top", "right", "bottom", "left", "zIndex"],
413
+ "Typography": ["fontFamily", "fontWeight", "fontSize", "lineHeight", "color", "letterSpacing", "textAlign", "textTransform", "textDecoration"],
414
+ "Background": ["backgroundColor", "backgroundImage", "backgroundSize", "backgroundPosition", "backgroundRepeat", "opacity"],
415
+ "Borders": ["borderRadius", "borderWidth", "borderStyle", "borderColor"],
416
+ "Effects": ["boxShadow", "transform", "transition", "filter"],
417
+ "Overflow": ["overflow", "whiteSpace"],
418
+ "Interaction": ["cursor", "pointerEvents"]
419
+ };
420
+ var VISUAL_MODE_PROPERTIES_SET = new Set(
421
+ Object.values(VISUAL_MODE_PROPERTIES).flat()
422
+ );
423
+ function isVisualModeProperty(prop) {
424
+ return VISUAL_MODE_PROPERTIES_SET.has(prop);
425
+ }
426
+ var isFlexDisplay = (d) => d === "flex" || d === "inline-flex";
427
+ var isGridDisplay = (d) => d === "grid" || d === "inline-grid";
428
+ var isListTag = (t) => t === "ul" || t === "ol" || t === "li";
429
+ var isMediaTag = (t) => t === "img" || t === "video";
430
+ var VISUAL_MODE_RULES = {
431
+ // Flex/Grid CONTAINER props — own display must be flex/grid.
432
+ flexDirection: (ctx) => isFlexDisplay(ctx.display),
433
+ flexWrap: (ctx) => isFlexDisplay(ctx.display),
434
+ justifyContent: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
435
+ alignItems: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
436
+ alignContent: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
437
+ gap: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
438
+ rowGap: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
439
+ columnGap: (ctx) => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),
440
+ gridTemplateColumns: (ctx) => isGridDisplay(ctx.display),
441
+ gridTemplateRows: (ctx) => isGridDisplay(ctx.display),
442
+ gridTemplateAreas: (ctx) => isGridDisplay(ctx.display),
443
+ gridGap: (ctx) => isGridDisplay(ctx.display),
444
+ gridAutoFlow: (ctx) => isGridDisplay(ctx.display),
445
+ gridAutoColumns: (ctx) => isGridDisplay(ctx.display),
446
+ gridAutoRows: (ctx) => isGridDisplay(ctx.display),
447
+ justifyItems: (ctx) => isGridDisplay(ctx.display),
448
+ placeItems: (ctx) => isGridDisplay(ctx.display),
449
+ placeContent: (ctx) => isGridDisplay(ctx.display),
450
+ // Flex/Grid ITEM props — PARENT display must be flex/grid.
451
+ flex: (ctx) => isFlexDisplay(ctx.parentDisplay),
452
+ flexFlow: (ctx) => isFlexDisplay(ctx.parentDisplay),
453
+ flexGrow: (ctx) => isFlexDisplay(ctx.parentDisplay),
454
+ flexShrink: (ctx) => isFlexDisplay(ctx.parentDisplay),
455
+ flexBasis: (ctx) => isFlexDisplay(ctx.parentDisplay),
456
+ alignSelf: (ctx) => isFlexDisplay(ctx.parentDisplay) || isGridDisplay(ctx.parentDisplay),
457
+ justifySelf: (ctx) => isGridDisplay(ctx.parentDisplay),
458
+ placeSelf: (ctx) => isGridDisplay(ctx.parentDisplay),
459
+ order: (ctx) => isFlexDisplay(ctx.parentDisplay) || isGridDisplay(ctx.parentDisplay),
460
+ gridArea: (ctx) => isGridDisplay(ctx.parentDisplay),
461
+ gridColumn: (ctx) => isGridDisplay(ctx.parentDisplay),
462
+ gridRow: (ctx) => isGridDisplay(ctx.parentDisplay),
463
+ // Position-dependent inset properties.
464
+ top: (ctx) => ctx.position !== "static",
465
+ right: (ctx) => ctx.position !== "static",
466
+ bottom: (ctx) => ctx.position !== "static",
467
+ left: (ctx) => ctx.position !== "static",
468
+ inset: (ctx) => ctx.position !== "static",
469
+ zIndex: (ctx) => ctx.position !== "static",
470
+ // Tag-based.
471
+ objectFit: (ctx) => isMediaTag(ctx.tagName),
472
+ objectPosition: (ctx) => isMediaTag(ctx.tagName),
473
+ listStyle: (ctx) => isListTag(ctx.tagName),
474
+ listStyleType: (ctx) => isListTag(ctx.tagName),
475
+ listStylePosition: (ctx) => isListTag(ctx.tagName),
476
+ // Padding/margin shorthand-vs-longhand auto-toggle.
477
+ // When ANY longhand is set, hide shorthand; otherwise hide longhands.
478
+ padding: (ctx) => !ctx.hasPaddingLonghand,
479
+ paddingTop: (ctx) => ctx.hasPaddingLonghand,
480
+ paddingRight: (ctx) => ctx.hasPaddingLonghand,
481
+ paddingBottom: (ctx) => ctx.hasPaddingLonghand,
482
+ paddingLeft: (ctx) => ctx.hasPaddingLonghand,
483
+ margin: (ctx) => !ctx.hasMarginLonghand,
484
+ marginTop: (ctx) => ctx.hasMarginLonghand,
485
+ marginRight: (ctx) => ctx.hasMarginLonghand,
486
+ marginBottom: (ctx) => ctx.hasMarginLonghand,
487
+ marginLeft: (ctx) => ctx.hasMarginLonghand,
488
+ // Background-image-only props — meaningless without a background image.
489
+ backgroundPosition: (ctx) => ctx.hasBackgroundImage,
490
+ backgroundSize: (ctx) => ctx.hasBackgroundImage,
491
+ backgroundRepeat: (ctx) => ctx.hasBackgroundImage
492
+ };
493
+ function isVisualModeRowVisible(prop, ctx) {
494
+ const rule = VISUAL_MODE_RULES[prop];
495
+ return rule ? rule(ctx) : true;
496
+ }
405
497
  function matchesAbbreviation(property, input) {
406
498
  if (!input) return false;
407
499
  let propertyIndex = 0;
@@ -462,6 +554,39 @@ function filterPropertyValues(propertyName, input) {
462
554
  function getPropertyType(propertyName) {
463
555
  return CSS_PROPERTIES_DEFINITION[propertyName]?.type;
464
556
  }
557
+ var UNITLESS_PROPERTIES = /* @__PURE__ */ new Set([
558
+ "fontWeight",
559
+ "lineHeight",
560
+ "opacity",
561
+ "fillOpacity",
562
+ "strokeOpacity",
563
+ "stopOpacity",
564
+ "zIndex",
565
+ "order",
566
+ "flexGrow",
567
+ "flexShrink",
568
+ "flex",
569
+ "columnCount",
570
+ "columns",
571
+ "tabSize",
572
+ "orphans",
573
+ "widows",
574
+ "gridRow",
575
+ "gridColumn",
576
+ "gridRowStart",
577
+ "gridRowEnd",
578
+ "gridColumnStart",
579
+ "gridColumnEnd",
580
+ "animationIterationCount",
581
+ "aspectRatio",
582
+ "scale"
583
+ ]);
584
+ function appendsPxByDefault(propertyName) {
585
+ if (UNITLESS_PROPERTIES.has(propertyName)) return false;
586
+ const def = CSS_PROPERTIES_DEFINITION[propertyName];
587
+ if (def?.type === "select" || def?.type === "boolean" || def?.type === "number") return false;
588
+ return true;
589
+ }
465
590
 
466
591
  // lib/shared/errorLogger.ts
467
592
  var errorHandler = null;
@@ -507,12 +632,18 @@ export {
507
632
  CSS_PROPERTIES,
508
633
  CSS_PROPERTY_GROUPS,
509
634
  getPropertyGroup,
635
+ VISUAL_MODE_PROPERTIES,
636
+ isVisualModeProperty,
637
+ VISUAL_MODE_RULES,
638
+ isVisualModeRowVisible,
510
639
  filterCSSProperties,
511
640
  getPropertyValues,
512
641
  filterPropertyValues,
513
642
  getPropertyType,
643
+ UNITLESS_PROPERTIES,
644
+ appendsPxByDefault,
514
645
  setErrorHandler,
515
646
  logRuntimeError,
516
647
  logNetworkError
517
648
  };
518
- //# sourceMappingURL=chunk-UUA5LEWF.js.map
649
+ //# sourceMappingURL=chunk-6IVUG7FY.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../lib/shared/cssProperties.ts", "../../lib/shared/errorLogger.ts"],
4
+ "sourcesContent": ["/**\n * CSS Property Definition structure\n */\ninterface CSSPropertyDefinition {\n values?: readonly string[];\n type?: 'string' | 'select' | 'boolean' | 'number';\n}\n\n/**\n * CSS Properties with their valid values and metadata\n * Used for autocomplete suggestions for both property names and values\n */\nexport const CSS_PROPERTIES_DEFINITION: Record<string, CSSPropertyDefinition> = {\n // Display & Layout\n display: {\n values: ['block', 'flex', 'grid', 'inline', 'inline-block', 'inline-flex', 'inline-grid', 'none'],\n type: 'select',\n },\n position: {\n values: ['static', 'relative', 'absolute', 'fixed', 'sticky'],\n type: 'select',\n },\n top: { type: 'string' },\n right: { type: 'string' },\n bottom: { type: 'string' },\n left: { type: 'string' },\n inset: { type: 'string' },\n zIndex: { type: 'number' },\n\n // Dimensions\n width: { type: 'string' },\n height: { type: 'string' },\n minWidth: { type: 'string' },\n maxWidth: { type: 'string' },\n minHeight: { type: 'string' },\n maxHeight: { type: 'string' },\n aspectRatio: { type: 'string' },\n\n // Spacing\n margin: { type: 'string' },\n marginTop: { type: 'string' },\n marginRight: { type: 'string' },\n marginBottom: { type: 'string' },\n marginLeft: { type: 'string' },\n padding: { type: 'string' },\n paddingTop: { type: 'string' },\n paddingRight: { type: 'string' },\n paddingBottom: { type: 'string' },\n paddingLeft: { type: 'string' },\n gap: { type: 'string' },\n rowGap: { type: 'string' },\n columnGap: { type: 'string' },\n\n // Borders\n border: { type: 'string' },\n borderWidth: { type: 'string' },\n borderStyle: {\n values: ['solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset', 'none'],\n type: 'select',\n },\n borderColor: { type: 'string' },\n borderTop: { type: 'string' },\n borderRight: { type: 'string' },\n borderBottom: { type: 'string' },\n borderLeft: { type: 'string' },\n borderRadius: { type: 'string' },\n borderTopLeftRadius: { type: 'string' },\n borderTopRightRadius: { type: 'string' },\n borderBottomLeftRadius: { type: 'string' },\n borderBottomRightRadius: { type: 'string' },\n\n // Background & Colors\n background: { type: 'string' },\n backgroundColor: { type: 'string' },\n backgroundImage: { type: 'string' },\n backgroundSize: {\n values: ['auto', 'cover', 'contain'],\n type: 'select',\n },\n backgroundPosition: {\n values: ['top', 'bottom', 'left', 'right', 'center'],\n type: 'select',\n },\n backgroundRepeat: {\n values: ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'],\n type: 'select',\n },\n color: { type: 'string' },\n opacity: { type: 'number' },\n\n // Flexbox\n flex: { type: 'string' },\n flexDirection: {\n values: ['row', 'column', 'row-reverse', 'column-reverse'],\n type: 'select',\n },\n flexWrap: {\n values: ['nowrap', 'wrap', 'wrap-reverse'],\n type: 'select',\n },\n flexFlow: { type: 'string' },\n justifyContent: {\n values: ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'],\n type: 'select',\n },\n alignItems: {\n values: ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'],\n type: 'select',\n },\n alignContent: {\n values: ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'stretch'],\n type: 'select',\n },\n alignSelf: {\n values: ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'],\n type: 'select',\n },\n flexGrow: { type: 'number' },\n flexShrink: { type: 'number' },\n flexBasis: { type: 'string' },\n order: { type: 'number' },\n\n // Grid\n grid: { type: 'string' },\n gridTemplateColumns: { type: 'string' },\n gridTemplateRows: { type: 'string' },\n gridTemplateAreas: { type: 'string' },\n gridGap: { type: 'string' },\n gridColumn: { type: 'string' },\n gridRow: { type: 'string' },\n gridArea: { type: 'string' },\n gridAutoFlow: {\n values: ['row', 'column', 'row dense', 'column dense'],\n type: 'select',\n },\n gridAutoColumns: { type: 'string' },\n gridAutoRows: { type: 'string' },\n justifyItems: {\n values: ['start', 'end', 'center', 'stretch'],\n type: 'select',\n },\n justifySelf: {\n values: ['auto', 'start', 'end', 'center', 'stretch'],\n type: 'select',\n },\n placeContent: { type: 'string' },\n placeItems: { type: 'string' },\n placeSelf: { type: 'string' },\n\n // Text & Font\n fontSize: { type: 'string' },\n fontWeight: {\n values: ['100', '200', '300', '400', '500', '600', '700', '800', '900', 'normal', 'bold'],\n type: 'select',\n },\n fontFamily: { type: 'string' },\n fontStyle: {\n values: ['normal', 'italic', 'oblique'],\n type: 'select',\n },\n lineHeight: { type: 'string' },\n textAlign: {\n values: ['left', 'right', 'center', 'justify', 'start', 'end'],\n type: 'select',\n },\n textDecoration: {\n values: ['none', 'underline', 'overline', 'line-through'],\n type: 'select',\n },\n textTransform: {\n values: ['none', 'capitalize', 'uppercase', 'lowercase'],\n type: 'select',\n },\n letterSpacing: { type: 'string' },\n wordSpacing: { type: 'string' },\n wordBreak: {\n values: ['normal', 'break-all', 'keep-all', 'break-word'],\n type: 'select',\n },\n overflowWrap: {\n values: ['normal', 'break-word', 'anywhere'],\n type: 'select',\n },\n textIndent: { type: 'string' },\n verticalAlign: {\n values: ['baseline', 'top', 'middle', 'bottom', 'text-top', 'text-bottom', 'sub', 'super'],\n type: 'select',\n },\n\n // Box Shadow & Effects\n boxShadow: { type: 'string' },\n textShadow: { type: 'string' },\n filter: { type: 'string' },\n backdropFilter: { type: 'string' },\n transform: { type: 'string' },\n transformOrigin: { type: 'string' },\n transition: { type: 'string' },\n animation: { type: 'string' },\n backfaceVisibility: {\n values: ['visible', 'hidden'],\n type: 'select',\n },\n mixBlendMode: {\n values: ['normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'],\n type: 'select',\n },\n clipPath: { type: 'string' },\n\n // Overflow & Content\n overflow: {\n values: ['visible', 'hidden', 'scroll', 'auto'],\n type: 'select',\n },\n overflowX: {\n values: ['visible', 'hidden', 'scroll', 'auto'],\n type: 'select',\n },\n overflowY: {\n values: ['visible', 'hidden', 'scroll', 'auto'],\n type: 'select',\n },\n whiteSpace: {\n values: ['normal', 'nowrap', 'pre', 'pre-wrap', 'pre-line'],\n type: 'select',\n },\n textOverflow: {\n values: ['clip', 'ellipsis'],\n type: 'select',\n },\n visibility: {\n values: ['visible', 'hidden', 'collapse'],\n type: 'select',\n },\n content: { type: 'string' },\n\n // Cursor & Interaction\n cursor: {\n values: ['auto', 'default', 'pointer', 'wait', 'text', 'move', 'not-allowed', 'help'],\n type: 'select',\n },\n pointerEvents: {\n values: ['auto', 'none'],\n type: 'select',\n },\n userSelect: {\n values: ['auto', 'none', 'text', 'all'],\n type: 'select',\n },\n\n // Outline\n outline: { type: 'string' },\n outlineWidth: { type: 'string' },\n outlineStyle: {\n values: ['none', 'solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset'],\n type: 'select',\n },\n outlineColor: { type: 'string' },\n outlineOffset: { type: 'string' },\n\n // Lists\n listStyle: { type: 'string' },\n listStyleType: {\n values: ['none', 'disc', 'circle', 'square', 'decimal', 'decimal-leading-zero', 'lower-roman', 'upper-roman', 'lower-alpha', 'upper-alpha'],\n type: 'select',\n },\n listStylePosition: {\n values: ['inside', 'outside'],\n type: 'select',\n },\n\n // Miscellaneous\n float: {\n values: ['left', 'right', 'none'],\n type: 'select',\n },\n clear: {\n values: ['left', 'right', 'both', 'none'],\n type: 'select',\n },\n boxSizing: {\n values: ['content-box', 'border-box'],\n type: 'select',\n },\n objectFit: {\n values: ['fill', 'contain', 'cover', 'scale-down'],\n type: 'select',\n },\n objectPosition: {\n values: ['top', 'bottom', 'left', 'right', 'center'],\n type: 'select',\n },\n resize: {\n values: ['none', 'both', 'horizontal', 'vertical'],\n type: 'select',\n },\n scrollBehavior: {\n values: ['auto', 'smooth'],\n type: 'select',\n },\n accentColor: { type: 'string' },\n\n // SVG\n stroke: { type: 'string' },\n strokeWidth: { type: 'string' },\n strokeDasharray: { type: 'string' },\n strokeDashoffset: { type: 'string' },\n strokeLinecap: {\n values: ['butt', 'round', 'square'],\n type: 'select',\n },\n strokeLinejoin: {\n values: ['miter', 'round', 'bevel'],\n type: 'select',\n },\n strokeOpacity: { type: 'number' },\n fill: { type: 'string' },\n fillOpacity: { type: 'number' },\n fillRule: {\n values: ['nonzero', 'evenodd'],\n type: 'select',\n },\n};\n\n/**\n * Common CSS properties for autocomplete suggestions (camelCase for React/JS)\n * Derived from CSS_PROPERTIES_DEFINITION keys\n */\nexport const CSS_PROPERTIES = Object.keys(CSS_PROPERTIES_DEFINITION);\n\n/**\n * Popularity tiers for CSS properties (lower = more common).\n * Properties not listed default to tier 3.\n * Used to sort autocomplete suggestions within each match group.\n */\nconst CSS_PROPERTY_PRIORITY: Record<string, number> = {\n // Tier 1: Most commonly used\n display: 1,\n position: 1,\n width: 1,\n height: 1,\n margin: 1,\n padding: 1,\n color: 1,\n backgroundColor: 1,\n fontSize: 1,\n fontWeight: 1,\n border: 1,\n borderRadius: 1,\n flex: 1,\n flexDirection: 1,\n justifyContent: 1,\n alignItems: 1,\n gap: 1,\n opacity: 1,\n overflow: 1,\n zIndex: 1,\n top: 1,\n right: 1,\n bottom: 1,\n left: 1,\n cursor: 1,\n background: 1,\n boxShadow: 1,\n transition: 1,\n transform: 1,\n lineHeight: 1,\n textAlign: 1,\n\n // Tier 2: Common but less frequent\n maxWidth: 2,\n maxHeight: 2,\n minWidth: 3,\n minHeight: 3,\n marginTop: 2,\n marginBottom: 2,\n marginLeft: 2,\n marginRight: 2,\n paddingTop: 2,\n paddingBottom: 2,\n paddingLeft: 2,\n paddingRight: 2,\n fontFamily: 2,\n fontStyle: 2,\n textDecoration: 2,\n textTransform: 2,\n letterSpacing: 2,\n borderWidth: 2,\n borderStyle: 2,\n borderColor: 2,\n borderBottom: 2,\n borderTop: 2,\n flexWrap: 2,\n flexGrow: 2,\n flexShrink: 2,\n flexBasis: 2,\n alignSelf: 2,\n gridTemplateColumns: 2,\n gridTemplateRows: 2,\n backgroundImage: 2,\n backgroundSize: 2,\n backgroundPosition: 2,\n whiteSpace: 2,\n textOverflow: 2,\n visibility: 2,\n pointerEvents: 2,\n userSelect: 2,\n boxSizing: 2,\n objectFit: 2,\n filter: 2,\n animation: 2,\n outline: 2,\n inset: 2,\n};\n\nfunction getPropertyPriority(property: string): number {\n return CSS_PROPERTY_PRIORITY[property] ?? 3;\n}\n\n/**\n * CSS Property Groups for organizing styles in the editor\n * Order determines display order in the UI\n */\nexport const CSS_PROPERTY_GROUPS: Record<string, string[]> = {\n 'Layout': ['display'],\n 'Spacing': ['margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],\n 'Size': ['width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'aspectRatio'],\n 'Position': ['position', 'top', 'right', 'bottom', 'left', 'inset', 'zIndex'],\n 'Flexbox': ['flex', 'flexDirection', 'flexWrap', 'flexFlow', 'justifyContent', 'alignItems', 'alignContent', 'gap', 'rowGap', 'columnGap', 'alignSelf', 'flexGrow', 'flexShrink', 'flexBasis', 'order'],\n 'Grid': ['grid', 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridGap', 'gridColumn', 'gridRow', 'gridArea', 'gridAutoFlow', 'gridAutoColumns', 'gridAutoRows', 'justifyItems', 'justifySelf', 'placeContent', 'placeItems', 'placeSelf'],\n 'Typography': ['fontWeight', 'fontSize', 'fontFamily', 'fontStyle', 'lineHeight', 'color', 'textAlign', 'textDecoration', 'textTransform', 'letterSpacing', 'wordSpacing', 'wordBreak', 'overflowWrap', 'textIndent', 'verticalAlign'],\n 'Background': ['background', 'backgroundColor', 'backgroundImage', 'backgroundSize', 'backgroundPosition', 'backgroundRepeat', 'opacity'],\n 'Borders': ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius', 'border', 'borderWidth', 'borderStyle', 'borderColor', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft'],\n 'Outline': ['outline', 'outlineWidth', 'outlineStyle', 'outlineColor', 'outlineOffset'],\n 'Effects': ['boxShadow', 'textShadow', 'filter', 'backdropFilter', 'transform', 'transformOrigin', 'transition', 'animation', 'backfaceVisibility', 'mixBlendMode', 'clipPath'],\n 'Overflow': ['overflow', 'overflowX', 'overflowY', 'whiteSpace', 'textOverflow', 'visibility', 'content'],\n 'Interaction': ['cursor', 'pointerEvents', 'userSelect'],\n 'Lists': ['listStyle', 'listStyleType', 'listStylePosition'],\n 'Other': ['float', 'clear', 'boxSizing', 'objectFit', 'objectPosition', 'resize', 'scrollBehavior', 'accentColor'],\n 'SVG': ['stroke', 'strokeWidth', 'strokeDasharray', 'strokeDashoffset', 'strokeLinecap', 'strokeLinejoin', 'strokeOpacity', 'fill', 'fillOpacity', 'fillRule'],\n};\n\n/**\n * Get the group name for a CSS property\n * @param propertyName - The CSS property name\n * @returns The group name or 'Other' if not found\n */\nexport function getPropertyGroup(propertyName: string): string {\n for (const [groupName, properties] of Object.entries(CSS_PROPERTY_GROUPS)) {\n if (properties.includes(propertyName)) {\n return groupName;\n }\n }\n return 'Other';\n}\n\n/**\n * Subset of CSS properties shown as \"always-visible\" rows in the visual style\n * editor mode (Webflow-like). Each property here renders even when unset, so\n * the user can see at a glance which properties are available and click an\n * empty row to start typing a value.\n *\n * Keys must be group names from CSS_PROPERTY_GROUPS so the visual editor can\n * reuse the same group headers as list mode.\n */\nexport const VISUAL_MODE_PROPERTIES: Record<string, string[]> = {\n 'Layout': ['display'],\n 'Grid': ['gridTemplateColumns'],\n 'Flexbox': ['flexDirection', 'flexWrap', 'justifyContent', 'alignItems', 'gap', 'flexGrow', 'flexShrink', 'flexBasis'],\n 'Spacing': ['margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],\n 'Size': ['width', 'height', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight'],\n 'Position': ['position', 'top', 'right', 'bottom', 'left', 'zIndex'],\n 'Typography': ['fontFamily', 'fontWeight', 'fontSize', 'lineHeight', 'color', 'letterSpacing', 'textAlign', 'textTransform', 'textDecoration'],\n 'Background': ['backgroundColor', 'backgroundImage', 'backgroundSize', 'backgroundPosition', 'backgroundRepeat', 'opacity'],\n 'Borders': ['borderRadius', 'borderWidth', 'borderStyle', 'borderColor'],\n 'Effects': ['boxShadow', 'transform', 'transition', 'filter'],\n 'Overflow': ['overflow', 'whiteSpace'],\n 'Interaction': ['cursor', 'pointerEvents'],\n};\n\nconst VISUAL_MODE_PROPERTIES_SET = new Set(\n Object.values(VISUAL_MODE_PROPERTIES).flat()\n);\n\n/**\n * True if `prop` belongs to the always-visible visual-mode list.\n */\nexport function isVisualModeProperty(prop: string): boolean {\n return VISUAL_MODE_PROPERTIES_SET.has(prop);\n}\n\n/**\n * Context used by visual-mode visibility rules. Captures everything a rule\n * needs to decide whether a property row is meaningful for the currently\n * selected element. Built once per render in `StyleEditor`.\n */\nexport interface VisualModeRuleContext {\n /** Effective `display` of the selected element \u2014 getComputedStyle().display\n * with declared (instance/inherited/effective) merge as fallback when the\n * iframe hasn't loaded yet. Defaults to 'block'. */\n display: string;\n /** Effective `display` of the DOM parent \u2014 used for flex/grid item props\n * whose applicability depends on the parent's layout mode. '' when no\n * parent is reachable (root element, iframe missing). */\n parentDisplay: string;\n /** Effective `position` of the selected element. Defaults to 'static'. */\n position: string;\n /** Lowercase HTML tag name of the selected element ('div', 'img', 'ul'\u2026). */\n tagName: string;\n /** True if any of paddingTop / paddingRight / paddingBottom / paddingLeft\n * is set anywhere in the cascade (instance + inherited + effective).\n * When true, the panel shows the four longhand rows and hides `padding`. */\n hasPaddingLonghand: boolean;\n /** Same as `hasPaddingLonghand` for the four `margin*` longhands. */\n hasMarginLonghand: boolean;\n /** True if `backgroundImage` (or the `background` shorthand) is set anywhere\n * in the cascade. Drives visibility of background-image-only properties\n * like `backgroundPosition` / `backgroundSize` / `backgroundRepeat`. */\n hasBackgroundImage: boolean;\n}\n\nexport type VisualModeRule = (ctx: VisualModeRuleContext) => boolean;\n\nconst isFlexDisplay = (d: string) => d === 'flex' || d === 'inline-flex';\nconst isGridDisplay = (d: string) => d === 'grid' || d === 'inline-grid';\nconst isListTag = (t: string) => t === 'ul' || t === 'ol' || t === 'li';\nconst isMediaTag = (t: string) => t === 'img' || t === 'video';\n\n/**\n * Visibility rules for the visual-mode style panel. Each entry is a predicate\n * that returns true when the row should be rendered for the current element\n * context. Properties without an entry are always visible. Properties that\n * are *explicitly set* on the element bypass these rules (the explicit-value\n * override is enforced by the caller, not here).\n */\nexport const VISUAL_MODE_RULES: Record<string, VisualModeRule> = {\n // Flex/Grid CONTAINER props \u2014 own display must be flex/grid.\n flexDirection: ctx => isFlexDisplay(ctx.display),\n flexWrap: ctx => isFlexDisplay(ctx.display),\n justifyContent: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n alignItems: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n alignContent: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n gap: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n rowGap: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n columnGap: ctx => isFlexDisplay(ctx.display) || isGridDisplay(ctx.display),\n gridTemplateColumns: ctx => isGridDisplay(ctx.display),\n gridTemplateRows: ctx => isGridDisplay(ctx.display),\n gridTemplateAreas: ctx => isGridDisplay(ctx.display),\n gridGap: ctx => isGridDisplay(ctx.display),\n gridAutoFlow: ctx => isGridDisplay(ctx.display),\n gridAutoColumns: ctx => isGridDisplay(ctx.display),\n gridAutoRows: ctx => isGridDisplay(ctx.display),\n justifyItems: ctx => isGridDisplay(ctx.display),\n placeItems: ctx => isGridDisplay(ctx.display),\n placeContent: ctx => isGridDisplay(ctx.display),\n\n // Flex/Grid ITEM props \u2014 PARENT display must be flex/grid.\n flex: ctx => isFlexDisplay(ctx.parentDisplay),\n flexFlow: ctx => isFlexDisplay(ctx.parentDisplay),\n flexGrow: ctx => isFlexDisplay(ctx.parentDisplay),\n flexShrink: ctx => isFlexDisplay(ctx.parentDisplay),\n flexBasis: ctx => isFlexDisplay(ctx.parentDisplay),\n alignSelf: ctx => isFlexDisplay(ctx.parentDisplay) || isGridDisplay(ctx.parentDisplay),\n justifySelf: ctx => isGridDisplay(ctx.parentDisplay),\n placeSelf: ctx => isGridDisplay(ctx.parentDisplay),\n order: ctx => isFlexDisplay(ctx.parentDisplay) || isGridDisplay(ctx.parentDisplay),\n gridArea: ctx => isGridDisplay(ctx.parentDisplay),\n gridColumn: ctx => isGridDisplay(ctx.parentDisplay),\n gridRow: ctx => isGridDisplay(ctx.parentDisplay),\n\n // Position-dependent inset properties.\n top: ctx => ctx.position !== 'static',\n right: ctx => ctx.position !== 'static',\n bottom: ctx => ctx.position !== 'static',\n left: ctx => ctx.position !== 'static',\n inset: ctx => ctx.position !== 'static',\n zIndex: ctx => ctx.position !== 'static',\n\n // Tag-based.\n objectFit: ctx => isMediaTag(ctx.tagName),\n objectPosition: ctx => isMediaTag(ctx.tagName),\n listStyle: ctx => isListTag(ctx.tagName),\n listStyleType: ctx => isListTag(ctx.tagName),\n listStylePosition: ctx => isListTag(ctx.tagName),\n\n // Padding/margin shorthand-vs-longhand auto-toggle.\n // When ANY longhand is set, hide shorthand; otherwise hide longhands.\n padding: ctx => !ctx.hasPaddingLonghand,\n paddingTop: ctx => ctx.hasPaddingLonghand,\n paddingRight: ctx => ctx.hasPaddingLonghand,\n paddingBottom: ctx => ctx.hasPaddingLonghand,\n paddingLeft: ctx => ctx.hasPaddingLonghand,\n margin: ctx => !ctx.hasMarginLonghand,\n marginTop: ctx => ctx.hasMarginLonghand,\n marginRight: ctx => ctx.hasMarginLonghand,\n marginBottom: ctx => ctx.hasMarginLonghand,\n marginLeft: ctx => ctx.hasMarginLonghand,\n\n // Background-image-only props \u2014 meaningless without a background image.\n backgroundPosition: ctx => ctx.hasBackgroundImage,\n backgroundSize: ctx => ctx.hasBackgroundImage,\n backgroundRepeat: ctx => ctx.hasBackgroundImage,\n};\n\n/**\n * True if `prop` should be visible in the visual-mode panel given `ctx`.\n * Properties without an entry in `VISUAL_MODE_RULES` default to visible.\n * Callers are responsible for the explicit-value override (a property that\n * the user has set must remain visible regardless of the rule outcome).\n */\nexport function isVisualModeRowVisible(prop: string, ctx: VisualModeRuleContext): boolean {\n const rule = VISUAL_MODE_RULES[prop];\n return rule ? rule(ctx) : true;\n}\n\n/**\n * Check if property matches the abbreviation pattern\n * For example, \"bC\" matches \"backgroundColor\" (b\u2192b, C\u2192C capital letter)\n */\nfunction matchesAbbreviation(property: string, input: string): boolean {\n if (!input) return false;\n\n let propertyIndex = 0;\n\n for (let inputIndex = 0; inputIndex < input.length; inputIndex++) {\n const inputChar = input[inputIndex];\n let found = false;\n\n // Search from current position to end of property for a match at a word boundary\n while (propertyIndex < property.length) {\n const propChar = property[propertyIndex];\n // Word boundary = first character OR capital letter\n const isWordBoundary = propertyIndex === 0 ||\n (propChar === propChar.toUpperCase() && propChar !== propChar.toLowerCase());\n\n if (isWordBoundary && inputChar.toLowerCase() === propChar.toLowerCase()) {\n // Match found at word boundary\n found = true;\n propertyIndex++; // Move past this character for next search\n break;\n }\n\n propertyIndex++;\n }\n\n if (!found) {\n return false; // Couldn't find this input character at a word boundary\n }\n }\n\n return true;\n}\n\n/**\n * Filter CSS properties based on input value\n * Supports both startsWith matching and camelCase abbreviation matching\n */\nexport function filterCSSProperties(input: string): string[] {\n const normalizedInput = (input ?? '').trim();\n if (!normalizedInput) {\n return CSS_PROPERTIES.slice(0, 15); // Show first 15 by default\n }\n\n // First, try startsWith matching (exact prefix match)\n const startsWithMatches = CSS_PROPERTIES.filter(prop =>\n prop.toLowerCase().startsWith(normalizedInput.toLowerCase())\n );\n\n // Then, try abbreviation/fuzzy matching\n const abbreviationMatches = CSS_PROPERTIES.filter(prop =>\n matchesAbbreviation(prop, normalizedInput) &&\n !startsWithMatches.includes(prop) // Don't duplicate startsWith matches\n );\n\n // Sort each group by popularity, then combine: exact matches first, then fuzzy matches\n const byPriority = (a: string, b: string) =>\n getPropertyPriority(a) - getPropertyPriority(b);\n\n return [\n ...startsWithMatches.sort(byPriority),\n ...abbreviationMatches.sort(byPriority),\n ];\n}\n\n/**\n * Get available values for a specific CSS property\n * @param propertyName - The CSS property name (e.g., 'flexDirection')\n * @returns Array of valid values for the property, or empty array if property has no predefined values\n */\nexport function getPropertyValues(propertyName: string): string[] {\n const values = CSS_PROPERTIES_DEFINITION[propertyName]?.values;\n return values ? Array.from(values) : [];\n}\n\n/**\n * Filter values for a specific CSS property based on input\n * Supports substring matching and returns values that contain the input\n * @param propertyName - The CSS property name (e.g., 'flexDirection')\n * @param input - The user input to filter values by\n * @returns Filtered array of valid values for the property\n */\nexport function filterPropertyValues(propertyName: string, input: string): string[] {\n const values = getPropertyValues(propertyName);\n if (!values.length) {\n return []; // No predefined values for this property\n }\n\n const normalizedInput = (input ?? '').trim().toLowerCase();\n if (!normalizedInput) {\n return values; // Return all values if no input\n }\n\n // Filter values that contain the input (substring match)\n return values.filter(value =>\n value.toLowerCase().includes(normalizedInput)\n );\n}\n\n/**\n * Get the property type for a CSS property\n * @param propertyName - The CSS property name\n * @returns The property type ('string' | 'select' | 'boolean' | 'number') or undefined\n */\nexport function getPropertyType(propertyName: string): 'string' | 'select' | 'boolean' | 'number' | undefined {\n return CSS_PROPERTIES_DEFINITION[propertyName]?.type;\n}\n\n/**\n * CSS properties whose numeric values are unitless by spec \u2014 `font-weight: 400`,\n * `line-height: 1.5`, `opacity: 0.8`, `z-index: 10`, etc. The auto-px commit\n * normalizer must NOT append `px` to bare numbers for these.\n */\nexport const UNITLESS_PROPERTIES: ReadonlySet<string> = new Set([\n 'fontWeight', 'lineHeight',\n 'opacity', 'fillOpacity', 'strokeOpacity', 'stopOpacity',\n 'zIndex', 'order',\n 'flexGrow', 'flexShrink', 'flex',\n 'columnCount', 'columns', 'tabSize', 'orphans', 'widows',\n 'gridRow', 'gridColumn', 'gridRowStart', 'gridRowEnd',\n 'gridColumnStart', 'gridColumnEnd',\n 'animationIterationCount',\n 'aspectRatio',\n 'scale',\n]);\n\n/**\n * Whether bare numeric values for `propertyName` should be treated as pixels at\n * commit time (e.g. typing `52` for `width` becomes `52px`). Unitless props,\n * `select`/`boolean` keyword props, and existing `number`-typed entries return false.\n */\nexport function appendsPxByDefault(propertyName: string): boolean {\n if (UNITLESS_PROPERTIES.has(propertyName)) return false;\n const def = CSS_PROPERTIES_DEFINITION[propertyName];\n if (def?.type === 'select' || def?.type === 'boolean' || def?.type === 'number') return false;\n return true;\n}\n", "/**\n * Error Logger\n * Centralized error logging with optional telemetry integration\n */\n\nimport type { ErrorCategory } from './errors';\n\ninterface ErrorLogEntry {\n location: string;\n category: ErrorCategory;\n error: unknown;\n context?: Record<string, unknown>;\n timestamp: number;\n}\n\ntype ErrorHandler = (entry: ErrorLogEntry) => void;\n\nlet errorHandler: ErrorHandler | null = null;\n\n/**\n * Set custom error handler (for telemetry integration)\n */\nexport function setErrorHandler(handler: ErrorHandler | null): void {\n errorHandler = handler;\n}\n\n/**\n * Check if running in development mode\n */\nfunction isDevelopment(): boolean {\n // Check for Node.js environment\n if (typeof process !== 'undefined' && process.env?.NODE_ENV) {\n return process.env.NODE_ENV === 'development';\n }\n // Browser environment - assume development if no production indicators\n return true;\n}\n\n/**\n * Log runtime error with context\n * Use for graceful degradation scenarios where error is handled but should be visible\n */\nexport function logRuntimeError(\n location: string,\n error: unknown,\n context?: Record<string, unknown>\n): void {\n const entry: ErrorLogEntry = {\n location,\n category: 'runtime',\n error,\n context,\n timestamp: Date.now(),\n };\n\n // Development: always log to console\n if (isDevelopment()) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`[${location}] ${errorMessage}`, context ?? '');\n }\n\n // Custom handler (telemetry, etc.)\n errorHandler?.(entry);\n}\n\n/**\n * Log network/API error\n */\nexport function logNetworkError(\n location: string,\n error: unknown,\n context?: Record<string, unknown>\n): void {\n const entry: ErrorLogEntry = {\n location,\n category: 'network',\n error,\n context,\n timestamp: Date.now(),\n };\n\n if (isDevelopment()) {\n console.error(`[${location}] Network error:`, error, context ?? '');\n }\n\n errorHandler?.(entry);\n}\n"],
5
+ "mappings": ";AAYO,IAAM,4BAAmE;AAAA;AAAA,EAE9E,SAAS;AAAA,IACP,QAAQ,CAAC,SAAS,QAAQ,QAAQ,UAAU,gBAAgB,eAAe,eAAe,MAAM;AAAA,IAChG,MAAM;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACR,QAAQ,CAAC,UAAU,YAAY,YAAY,SAAS,QAAQ;AAAA,IAC5D,MAAM;AAAA,EACR;AAAA,EACA,KAAK,EAAE,MAAM,SAAS;AAAA,EACtB,OAAO,EAAE,MAAM,SAAS;AAAA,EACxB,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,MAAM,EAAE,MAAM,SAAS;AAAA,EACvB,OAAO,EAAE,MAAM,SAAS;AAAA,EACxB,QAAQ,EAAE,MAAM,SAAS;AAAA;AAAA,EAGzB,OAAO,EAAE,MAAM,SAAS;AAAA,EACxB,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,aAAa,EAAE,MAAM,SAAS;AAAA;AAAA,EAG9B,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,SAAS,EAAE,MAAM,SAAS;AAAA,EAC1B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,eAAe,EAAE,MAAM,SAAS;AAAA,EAChC,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,KAAK,EAAE,MAAM,SAAS;AAAA,EACtB,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,WAAW,EAAE,MAAM,SAAS;AAAA;AAAA,EAG5B,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,aAAa;AAAA,IACX,QAAQ,CAAC,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS,UAAU,MAAM;AAAA,IAC5F,MAAM;AAAA,EACR;AAAA,EACA,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,qBAAqB,EAAE,MAAM,SAAS;AAAA,EACtC,sBAAsB,EAAE,MAAM,SAAS;AAAA,EACvC,wBAAwB,EAAE,MAAM,SAAS;AAAA,EACzC,yBAAyB,EAAE,MAAM,SAAS;AAAA;AAAA,EAG1C,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,iBAAiB,EAAE,MAAM,SAAS;AAAA,EAClC,iBAAiB,EAAE,MAAM,SAAS;AAAA,EAClC,gBAAgB;AAAA,IACd,QAAQ,CAAC,QAAQ,SAAS,SAAS;AAAA,IACnC,MAAM;AAAA,EACR;AAAA,EACA,oBAAoB;AAAA,IAClB,QAAQ,CAAC,OAAO,UAAU,QAAQ,SAAS,QAAQ;AAAA,IACnD,MAAM;AAAA,EACR;AAAA,EACA,kBAAkB;AAAA,IAChB,QAAQ,CAAC,UAAU,YAAY,YAAY,WAAW;AAAA,IACtD,MAAM;AAAA,EACR;AAAA,EACA,OAAO,EAAE,MAAM,SAAS;AAAA,EACxB,SAAS,EAAE,MAAM,SAAS;AAAA;AAAA,EAG1B,MAAM,EAAE,MAAM,SAAS;AAAA,EACvB,eAAe;AAAA,IACb,QAAQ,CAAC,OAAO,UAAU,eAAe,gBAAgB;AAAA,IACzD,MAAM;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACR,QAAQ,CAAC,UAAU,QAAQ,cAAc;AAAA,IACzC,MAAM;AAAA,EACR;AAAA,EACA,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,gBAAgB;AAAA,IACd,QAAQ,CAAC,cAAc,YAAY,UAAU,iBAAiB,gBAAgB,cAAc;AAAA,IAC5F,MAAM;AAAA,EACR;AAAA,EACA,YAAY;AAAA,IACV,QAAQ,CAAC,cAAc,YAAY,UAAU,WAAW,UAAU;AAAA,IAClE,MAAM;AAAA,EACR;AAAA,EACA,cAAc;AAAA,IACZ,QAAQ,CAAC,cAAc,YAAY,UAAU,iBAAiB,gBAAgB,SAAS;AAAA,IACvF,MAAM;AAAA,EACR;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,CAAC,QAAQ,cAAc,YAAY,UAAU,WAAW,UAAU;AAAA,IAC1E,MAAM;AAAA,EACR;AAAA,EACA,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,OAAO,EAAE,MAAM,SAAS;AAAA;AAAA,EAGxB,MAAM,EAAE,MAAM,SAAS;AAAA,EACvB,qBAAqB,EAAE,MAAM,SAAS;AAAA,EACtC,kBAAkB,EAAE,MAAM,SAAS;AAAA,EACnC,mBAAmB,EAAE,MAAM,SAAS;AAAA,EACpC,SAAS,EAAE,MAAM,SAAS;AAAA,EAC1B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,SAAS,EAAE,MAAM,SAAS;AAAA,EAC1B,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,cAAc;AAAA,IACZ,QAAQ,CAAC,OAAO,UAAU,aAAa,cAAc;AAAA,IACrD,MAAM;AAAA,EACR;AAAA,EACA,iBAAiB,EAAE,MAAM,SAAS;AAAA,EAClC,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,cAAc;AAAA,IACZ,QAAQ,CAAC,SAAS,OAAO,UAAU,SAAS;AAAA,IAC5C,MAAM;AAAA,EACR;AAAA,EACA,aAAa;AAAA,IACX,QAAQ,CAAC,QAAQ,SAAS,OAAO,UAAU,SAAS;AAAA,IACpD,MAAM;AAAA,EACR;AAAA,EACA,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,WAAW,EAAE,MAAM,SAAS;AAAA;AAAA,EAG5B,UAAU,EAAE,MAAM,SAAS;AAAA,EAC3B,YAAY;AAAA,IACV,QAAQ,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,UAAU,MAAM;AAAA,IACxF,MAAM;AAAA,EACR;AAAA,EACA,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,WAAW;AAAA,IACT,QAAQ,CAAC,UAAU,UAAU,SAAS;AAAA,IACtC,MAAM;AAAA,EACR;AAAA,EACA,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,WAAW;AAAA,IACT,QAAQ,CAAC,QAAQ,SAAS,UAAU,WAAW,SAAS,KAAK;AAAA,IAC7D,MAAM;AAAA,EACR;AAAA,EACA,gBAAgB;AAAA,IACd,QAAQ,CAAC,QAAQ,aAAa,YAAY,cAAc;AAAA,IACxD,MAAM;AAAA,EACR;AAAA,EACA,eAAe;AAAA,IACb,QAAQ,CAAC,QAAQ,cAAc,aAAa,WAAW;AAAA,IACvD,MAAM;AAAA,EACR;AAAA,EACA,eAAe,EAAE,MAAM,SAAS;AAAA,EAChC,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,WAAW;AAAA,IACT,QAAQ,CAAC,UAAU,aAAa,YAAY,YAAY;AAAA,IACxD,MAAM;AAAA,EACR;AAAA,EACA,cAAc;AAAA,IACZ,QAAQ,CAAC,UAAU,cAAc,UAAU;AAAA,IAC3C,MAAM;AAAA,EACR;AAAA,EACA,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,eAAe;AAAA,IACb,QAAQ,CAAC,YAAY,OAAO,UAAU,UAAU,YAAY,eAAe,OAAO,OAAO;AAAA,IACzF,MAAM;AAAA,EACR;AAAA;AAAA,EAGA,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,gBAAgB,EAAE,MAAM,SAAS;AAAA,EACjC,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,iBAAiB,EAAE,MAAM,SAAS;AAAA,EAClC,YAAY,EAAE,MAAM,SAAS;AAAA,EAC7B,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,oBAAoB;AAAA,IAClB,QAAQ,CAAC,WAAW,QAAQ;AAAA,IAC5B,MAAM;AAAA,EACR;AAAA,EACA,cAAc;AAAA,IACZ,QAAQ,CAAC,UAAU,YAAY,UAAU,WAAW,UAAU,WAAW,eAAe,cAAc,cAAc,cAAc,cAAc,aAAa,OAAO,cAAc,SAAS,YAAY;AAAA,IACvM,MAAM;AAAA,EACR;AAAA,EACA,UAAU,EAAE,MAAM,SAAS;AAAA;AAAA,EAG3B,UAAU;AAAA,IACR,QAAQ,CAAC,WAAW,UAAU,UAAU,MAAM;AAAA,IAC9C,MAAM;AAAA,EACR;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,CAAC,WAAW,UAAU,UAAU,MAAM;AAAA,IAC9C,MAAM;AAAA,EACR;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,CAAC,WAAW,UAAU,UAAU,MAAM;AAAA,IAC9C,MAAM;AAAA,EACR;AAAA,EACA,YAAY;AAAA,IACV,QAAQ,CAAC,UAAU,UAAU,OAAO,YAAY,UAAU;AAAA,IAC1D,MAAM;AAAA,EACR;AAAA,EACA,cAAc;AAAA,IACZ,QAAQ,CAAC,QAAQ,UAAU;AAAA,IAC3B,MAAM;AAAA,EACR;AAAA,EACA,YAAY;AAAA,IACV,QAAQ,CAAC,WAAW,UAAU,UAAU;AAAA,IACxC,MAAM;AAAA,EACR;AAAA,EACA,SAAS,EAAE,MAAM,SAAS;AAAA;AAAA,EAG1B,QAAQ;AAAA,IACN,QAAQ,CAAC,QAAQ,WAAW,WAAW,QAAQ,QAAQ,QAAQ,eAAe,MAAM;AAAA,IACpF,MAAM;AAAA,EACR;AAAA,EACA,eAAe;AAAA,IACb,QAAQ,CAAC,QAAQ,MAAM;AAAA,IACvB,MAAM;AAAA,EACR;AAAA,EACA,YAAY;AAAA,IACV,QAAQ,CAAC,QAAQ,QAAQ,QAAQ,KAAK;AAAA,IACtC,MAAM;AAAA,EACR;AAAA;AAAA,EAGA,SAAS,EAAE,MAAM,SAAS;AAAA,EAC1B,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,cAAc;AAAA,IACZ,QAAQ,CAAC,QAAQ,SAAS,UAAU,UAAU,UAAU,UAAU,SAAS,SAAS,QAAQ;AAAA,IAC5F,MAAM;AAAA,EACR;AAAA,EACA,cAAc,EAAE,MAAM,SAAS;AAAA,EAC/B,eAAe,EAAE,MAAM,SAAS;AAAA;AAAA,EAGhC,WAAW,EAAE,MAAM,SAAS;AAAA,EAC5B,eAAe;AAAA,IACb,QAAQ,CAAC,QAAQ,QAAQ,UAAU,UAAU,WAAW,wBAAwB,eAAe,eAAe,eAAe,aAAa;AAAA,IAC1I,MAAM;AAAA,EACR;AAAA,EACA,mBAAmB;AAAA,IACjB,QAAQ,CAAC,UAAU,SAAS;AAAA,IAC5B,MAAM;AAAA,EACR;AAAA;AAAA,EAGA,OAAO;AAAA,IACL,QAAQ,CAAC,QAAQ,SAAS,MAAM;AAAA,IAChC,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,CAAC,QAAQ,SAAS,QAAQ,MAAM;AAAA,IACxC,MAAM;AAAA,EACR;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,CAAC,eAAe,YAAY;AAAA,IACpC,MAAM;AAAA,EACR;AAAA,EACA,WAAW;AAAA,IACT,QAAQ,CAAC,QAAQ,WAAW,SAAS,YAAY;AAAA,IACjD,MAAM;AAAA,EACR;AAAA,EACA,gBAAgB;AAAA,IACd,QAAQ,CAAC,OAAO,UAAU,QAAQ,SAAS,QAAQ;AAAA,IACnD,MAAM;AAAA,EACR;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ,CAAC,QAAQ,QAAQ,cAAc,UAAU;AAAA,IACjD,MAAM;AAAA,EACR;AAAA,EACA,gBAAgB;AAAA,IACd,QAAQ,CAAC,QAAQ,QAAQ;AAAA,IACzB,MAAM;AAAA,EACR;AAAA,EACA,aAAa,EAAE,MAAM,SAAS;AAAA;AAAA,EAG9B,QAAQ,EAAE,MAAM,SAAS;AAAA,EACzB,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,iBAAiB,EAAE,MAAM,SAAS;AAAA,EAClC,kBAAkB,EAAE,MAAM,SAAS;AAAA,EACnC,eAAe;AAAA,IACb,QAAQ,CAAC,QAAQ,SAAS,QAAQ;AAAA,IAClC,MAAM;AAAA,EACR;AAAA,EACA,gBAAgB;AAAA,IACd,QAAQ,CAAC,SAAS,SAAS,OAAO;AAAA,IAClC,MAAM;AAAA,EACR;AAAA,EACA,eAAe,EAAE,MAAM,SAAS;AAAA,EAChC,MAAM,EAAE,MAAM,SAAS;AAAA,EACvB,aAAa,EAAE,MAAM,SAAS;AAAA,EAC9B,UAAU;AAAA,IACR,QAAQ,CAAC,WAAW,SAAS;AAAA,IAC7B,MAAM;AAAA,EACR;AACF;AAMO,IAAM,iBAAiB,OAAO,KAAK,yBAAyB;AAOnE,IAAM,wBAAgD;AAAA;AAAA,EAEpD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AAAA,EACN,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA;AAAA,EAGX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,OAAO;AACT;AAEA,SAAS,oBAAoB,UAA0B;AACrD,SAAO,sBAAsB,QAAQ,KAAK;AAC5C;AAMO,IAAM,sBAAgD;AAAA,EAC3D,UAAU,CAAC,SAAS;AAAA,EACpB,WAAW,CAAC,UAAU,aAAa,eAAe,gBAAgB,cAAc,WAAW,cAAc,gBAAgB,iBAAiB,aAAa;AAAA,EACvJ,QAAQ,CAAC,SAAS,UAAU,YAAY,YAAY,aAAa,aAAa,aAAa;AAAA,EAC3F,YAAY,CAAC,YAAY,OAAO,SAAS,UAAU,QAAQ,SAAS,QAAQ;AAAA,EAC5E,WAAW,CAAC,QAAQ,iBAAiB,YAAY,YAAY,kBAAkB,cAAc,gBAAgB,OAAO,UAAU,aAAa,aAAa,YAAY,cAAc,aAAa,OAAO;AAAA,EACtM,QAAQ,CAAC,QAAQ,uBAAuB,oBAAoB,qBAAqB,WAAW,cAAc,WAAW,YAAY,gBAAgB,mBAAmB,gBAAgB,gBAAgB,eAAe,gBAAgB,cAAc,WAAW;AAAA,EAC5P,cAAc,CAAC,cAAc,YAAY,cAAc,aAAa,cAAc,SAAS,aAAa,kBAAkB,iBAAiB,iBAAiB,eAAe,aAAa,gBAAgB,cAAc,eAAe;AAAA,EACrO,cAAc,CAAC,cAAc,mBAAmB,mBAAmB,kBAAkB,sBAAsB,oBAAoB,SAAS;AAAA,EACxI,WAAW,CAAC,gBAAgB,uBAAuB,wBAAwB,0BAA0B,2BAA2B,UAAU,eAAe,eAAe,eAAe,aAAa,eAAe,gBAAgB,YAAY;AAAA,EAC/O,WAAW,CAAC,WAAW,gBAAgB,gBAAgB,gBAAgB,eAAe;AAAA,EACtF,WAAW,CAAC,aAAa,cAAc,UAAU,kBAAkB,aAAa,mBAAmB,cAAc,aAAa,sBAAsB,gBAAgB,UAAU;AAAA,EAC9K,YAAY,CAAC,YAAY,aAAa,aAAa,cAAc,gBAAgB,cAAc,SAAS;AAAA,EACxG,eAAe,CAAC,UAAU,iBAAiB,YAAY;AAAA,EACvD,SAAS,CAAC,aAAa,iBAAiB,mBAAmB;AAAA,EAC3D,SAAS,CAAC,SAAS,SAAS,aAAa,aAAa,kBAAkB,UAAU,kBAAkB,aAAa;AAAA,EACjH,OAAO,CAAC,UAAU,eAAe,mBAAmB,oBAAoB,iBAAiB,kBAAkB,iBAAiB,QAAQ,eAAe,UAAU;AAC/J;AAOO,SAAS,iBAAiB,cAA8B;AAC7D,aAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,mBAAmB,GAAG;AACzE,QAAI,WAAW,SAAS,YAAY,GAAG;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAWO,IAAM,yBAAmD;AAAA,EAC9D,UAAU,CAAC,SAAS;AAAA,EACpB,QAAQ,CAAC,qBAAqB;AAAA,EAC9B,WAAW,CAAC,iBAAiB,YAAY,kBAAkB,cAAc,OAAO,YAAY,cAAc,WAAW;AAAA,EACrH,WAAW,CAAC,UAAU,aAAa,eAAe,gBAAgB,cAAc,WAAW,cAAc,gBAAgB,iBAAiB,aAAa;AAAA,EACvJ,QAAQ,CAAC,SAAS,UAAU,YAAY,aAAa,YAAY,WAAW;AAAA,EAC5E,YAAY,CAAC,YAAY,OAAO,SAAS,UAAU,QAAQ,QAAQ;AAAA,EACnE,cAAc,CAAC,cAAc,cAAc,YAAY,cAAc,SAAS,iBAAiB,aAAa,iBAAiB,gBAAgB;AAAA,EAC7I,cAAc,CAAC,mBAAmB,mBAAmB,kBAAkB,sBAAsB,oBAAoB,SAAS;AAAA,EAC1H,WAAW,CAAC,gBAAgB,eAAe,eAAe,aAAa;AAAA,EACvE,WAAW,CAAC,aAAa,aAAa,cAAc,QAAQ;AAAA,EAC5D,YAAY,CAAC,YAAY,YAAY;AAAA,EACrC,eAAe,CAAC,UAAU,eAAe;AAC3C;AAEA,IAAM,6BAA6B,IAAI;AAAA,EACrC,OAAO,OAAO,sBAAsB,EAAE,KAAK;AAC7C;AAKO,SAAS,qBAAqB,MAAuB;AAC1D,SAAO,2BAA2B,IAAI,IAAI;AAC5C;AAkCA,IAAM,gBAAgB,CAAC,MAAc,MAAM,UAAU,MAAM;AAC3D,IAAM,gBAAgB,CAAC,MAAc,MAAM,UAAU,MAAM;AAC3D,IAAM,YAAY,CAAC,MAAc,MAAM,QAAQ,MAAM,QAAQ,MAAM;AACnE,IAAM,aAAa,CAAC,MAAc,MAAM,SAAS,MAAM;AAShD,IAAM,oBAAoD;AAAA;AAAA,EAE/D,eAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,UAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,gBAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,YAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,cAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,KAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,QAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,WAAqB,SAAO,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACnF,qBAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,kBAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,mBAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,SAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,cAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,iBAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,cAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,cAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,YAAqB,SAAO,cAAc,IAAI,OAAO;AAAA,EACrD,cAAqB,SAAO,cAAc,IAAI,OAAO;AAAA;AAAA,EAGrD,MAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,UAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,UAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,YAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,WAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,WAAa,SAAO,cAAc,IAAI,aAAa,KAAK,cAAc,IAAI,aAAa;AAAA,EACvF,aAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,WAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,OAAa,SAAO,cAAc,IAAI,aAAa,KAAK,cAAc,IAAI,aAAa;AAAA,EACvF,UAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,YAAa,SAAO,cAAc,IAAI,aAAa;AAAA,EACnD,SAAa,SAAO,cAAc,IAAI,aAAa;AAAA;AAAA,EAGnD,KAAQ,SAAO,IAAI,aAAa;AAAA,EAChC,OAAQ,SAAO,IAAI,aAAa;AAAA,EAChC,QAAQ,SAAO,IAAI,aAAa;AAAA,EAChC,MAAQ,SAAO,IAAI,aAAa;AAAA,EAChC,OAAQ,SAAO,IAAI,aAAa;AAAA,EAChC,QAAQ,SAAO,IAAI,aAAa;AAAA;AAAA,EAGhC,WAAmB,SAAO,WAAW,IAAI,OAAO;AAAA,EAChD,gBAAmB,SAAO,WAAW,IAAI,OAAO;AAAA,EAChD,WAAmB,SAAO,UAAU,IAAI,OAAO;AAAA,EAC/C,eAAmB,SAAO,UAAU,IAAI,OAAO;AAAA,EAC/C,mBAAmB,SAAO,UAAU,IAAI,OAAO;AAAA;AAAA;AAAA,EAI/C,SAAe,SAAO,CAAC,IAAI;AAAA,EAC3B,YAAe,SAAO,IAAI;AAAA,EAC1B,cAAe,SAAO,IAAI;AAAA,EAC1B,eAAe,SAAO,IAAI;AAAA,EAC1B,aAAe,SAAO,IAAI;AAAA,EAC1B,QAAe,SAAO,CAAC,IAAI;AAAA,EAC3B,WAAe,SAAO,IAAI;AAAA,EAC1B,aAAe,SAAO,IAAI;AAAA,EAC1B,cAAe,SAAO,IAAI;AAAA,EAC1B,YAAe,SAAO,IAAI;AAAA;AAAA,EAG1B,oBAAoB,SAAO,IAAI;AAAA,EAC/B,gBAAoB,SAAO,IAAI;AAAA,EAC/B,kBAAoB,SAAO,IAAI;AACjC;AAQO,SAAS,uBAAuB,MAAc,KAAqC;AACxF,QAAM,OAAO,kBAAkB,IAAI;AACnC,SAAO,OAAO,KAAK,GAAG,IAAI;AAC5B;AAMA,SAAS,oBAAoB,UAAkB,OAAwB;AACrE,MAAI,CAAC,MAAO,QAAO;AAEnB,MAAI,gBAAgB;AAEpB,WAAS,aAAa,GAAG,aAAa,MAAM,QAAQ,cAAc;AAChE,UAAM,YAAY,MAAM,UAAU;AAClC,QAAI,QAAQ;AAGZ,WAAO,gBAAgB,SAAS,QAAQ;AACtC,YAAM,WAAW,SAAS,aAAa;AAEvC,YAAM,iBAAiB,kBAAkB,KACtC,aAAa,SAAS,YAAY,KAAK,aAAa,SAAS,YAAY;AAE5E,UAAI,kBAAkB,UAAU,YAAY,MAAM,SAAS,YAAY,GAAG;AAExE,gBAAQ;AACR;AACA;AAAA,MACF;AAEA;AAAA,IACF;AAEA,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,oBAAoB,OAAyB;AAC3D,QAAM,mBAAmB,SAAS,IAAI,KAAK;AAC3C,MAAI,CAAC,iBAAiB;AACpB,WAAO,eAAe,MAAM,GAAG,EAAE;AAAA,EACnC;AAGA,QAAM,oBAAoB,eAAe;AAAA,IAAO,UAC9C,KAAK,YAAY,EAAE,WAAW,gBAAgB,YAAY,CAAC;AAAA,EAC7D;AAGA,QAAM,sBAAsB,eAAe;AAAA,IAAO,UAChD,oBAAoB,MAAM,eAAe,KACzC,CAAC,kBAAkB,SAAS,IAAI;AAAA;AAAA,EAClC;AAGA,QAAM,aAAa,CAAC,GAAW,MAC7B,oBAAoB,CAAC,IAAI,oBAAoB,CAAC;AAEhD,SAAO;AAAA,IACL,GAAG,kBAAkB,KAAK,UAAU;AAAA,IACpC,GAAG,oBAAoB,KAAK,UAAU;AAAA,EACxC;AACF;AAOO,SAAS,kBAAkB,cAAgC;AAChE,QAAM,SAAS,0BAA0B,YAAY,GAAG;AACxD,SAAO,SAAS,MAAM,KAAK,MAAM,IAAI,CAAC;AACxC;AASO,SAAS,qBAAqB,cAAsB,OAAyB;AAClF,QAAM,SAAS,kBAAkB,YAAY;AAC7C,MAAI,CAAC,OAAO,QAAQ;AAClB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,mBAAmB,SAAS,IAAI,KAAK,EAAE,YAAY;AACzD,MAAI,CAAC,iBAAiB;AACpB,WAAO;AAAA,EACT;AAGA,SAAO,OAAO;AAAA,IAAO,WACnB,MAAM,YAAY,EAAE,SAAS,eAAe;AAAA,EAC9C;AACF;AAOO,SAAS,gBAAgB,cAA8E;AAC5G,SAAO,0BAA0B,YAAY,GAAG;AAClD;AAOO,IAAM,sBAA2C,oBAAI,IAAI;AAAA,EAC9D;AAAA,EAAc;AAAA,EACd;AAAA,EAAW;AAAA,EAAe;AAAA,EAAiB;AAAA,EAC3C;AAAA,EAAU;AAAA,EACV;AAAA,EAAY;AAAA,EAAc;AAAA,EAC1B;AAAA,EAAe;AAAA,EAAW;AAAA,EAAW;AAAA,EAAW;AAAA,EAChD;AAAA,EAAW;AAAA,EAAc;AAAA,EAAgB;AAAA,EACzC;AAAA,EAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,SAAS,mBAAmB,cAA+B;AAChE,MAAI,oBAAoB,IAAI,YAAY,EAAG,QAAO;AAClD,QAAM,MAAM,0BAA0B,YAAY;AAClD,MAAI,KAAK,SAAS,YAAY,KAAK,SAAS,aAAa,KAAK,SAAS,SAAU,QAAO;AACxF,SAAO;AACT;;;ACjuBA,IAAI,eAAoC;AAKjC,SAAS,gBAAgB,SAAoC;AAClE,iBAAe;AACjB;AAKA,SAAS,gBAAyB;AAEhC,MAAI,OAAO,YAAY,eAAe,QAAQ,KAAK,UAAU;AAC3D,WAAO,QAAQ,IAAI,aAAa;AAAA,EAClC;AAEA,SAAO;AACT;AAMO,SAAS,gBACd,UACA,OACA,SACM;AACN,QAAM,QAAuB;AAAA,IAC3B;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,EACtB;AAGA,MAAI,cAAc,GAAG;AACnB,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,YAAQ,MAAM,IAAI,QAAQ,KAAK,YAAY,IAAI,WAAW,EAAE;AAAA,EAC9D;AAGA,iBAAe,KAAK;AACtB;AAKO,SAAS,gBACd,UACA,OACA,SACM;AACN,QAAM,QAAuB;AAAA,IAC3B;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,EACtB;AAEA,MAAI,cAAc,GAAG;AACnB,YAAQ,MAAM,IAAI,QAAQ,oBAAoB,OAAO,WAAW,EAAE;AAAA,EACpE;AAEA,iBAAe,KAAK;AACtB;",
6
+ "names": []
7
+ }
@@ -223,6 +223,8 @@ function clearStoredLocale() {
223
223
  }
224
224
 
225
225
  // lib/shared/responsiveScaling.ts
226
+ var DEFAULT_FLUID_RANGE = { min: 320, max: 1440 };
227
+ var DEFAULT_SITE_MARGIN = { min: 16, max: 32 };
226
228
  function getScaleCategory(property) {
227
229
  const propertyStr = property;
228
230
  if (property === "fontSize") return "fontSize";
@@ -241,6 +243,53 @@ function parseValue(valueStr) {
241
243
  unit: match[2]
242
244
  };
243
245
  }
246
+ var SCALABLE_CSS_PROPERTIES = /* @__PURE__ */ new Set([
247
+ "padding",
248
+ "padding-left",
249
+ "padding-right",
250
+ "padding-top",
251
+ "padding-bottom",
252
+ "paddingLeft",
253
+ "paddingRight",
254
+ "paddingTop",
255
+ "paddingBottom",
256
+ "margin",
257
+ "margin-left",
258
+ "margin-right",
259
+ "margin-top",
260
+ "margin-bottom",
261
+ "marginLeft",
262
+ "marginRight",
263
+ "marginTop",
264
+ "marginBottom",
265
+ "font-size",
266
+ "fontSize",
267
+ "gap",
268
+ "row-gap",
269
+ "column-gap",
270
+ "rowGap",
271
+ "columnGap",
272
+ "border-radius",
273
+ "borderRadius",
274
+ "border-top-left-radius",
275
+ "border-top-right-radius",
276
+ "border-bottom-left-radius",
277
+ "border-bottom-right-radius",
278
+ "borderTopLeftRadius",
279
+ "borderTopRightRadius",
280
+ "borderBottomLeftRadius",
281
+ "borderBottomRightRadius",
282
+ "width",
283
+ "height",
284
+ "max-width",
285
+ "max-height",
286
+ "min-width",
287
+ "min-height",
288
+ "maxWidth",
289
+ "maxHeight",
290
+ "minWidth",
291
+ "minHeight"
292
+ ]);
244
293
  function calculateResponsiveValue(baseValue, baseReference, scale) {
245
294
  if (Math.abs(baseValue) <= baseReference) {
246
295
  return Math.round(baseValue);
@@ -314,9 +363,82 @@ function resolveVariableValueAtBreakpoint(variable, breakpoint, responsiveScales
314
363
  }
315
364
  return variable.value;
316
365
  }
366
+ function getSmallestBreakpointName(breakpoints) {
367
+ if (!breakpoints) return null;
368
+ const entries = Object.entries(breakpoints);
369
+ if (entries.length === 0) return null;
370
+ let smallestName = entries[0][0];
371
+ let smallestWidth = entries[0][1].breakpoint;
372
+ for (const [name, cfg] of entries) {
373
+ if (cfg.breakpoint < smallestWidth) {
374
+ smallestWidth = cfg.breakpoint;
375
+ smallestName = name;
376
+ }
377
+ }
378
+ return smallestName;
379
+ }
380
+ function buildFluidClamp(baseValue, unit, scale, vpMin, vpMax, baseReference = 16) {
381
+ const max = baseValue;
382
+ const min = calculateResponsiveValue(baseValue, baseReference, scale);
383
+ if (min === max || vpMax === vpMin) {
384
+ return `${formatNumber(max)}${unit}`;
385
+ }
386
+ const unitToPx = unit === "rem" ? 16 : 1;
387
+ const minPx = min * unitToPx;
388
+ const maxPx = max * unitToPx;
389
+ const slopePx = (maxPx - minPx) / (vpMax - vpMin);
390
+ const interceptPx = minPx - slopePx * vpMin;
391
+ const interceptInUnit = interceptPx / unitToPx;
392
+ const slopeVw = slopePx * 100;
393
+ return `clamp(${formatNumber(min)}${unit}, ${formatNumber(interceptInUnit)}${unit} + ${formatNumber(slopeVw)}vw, ${formatNumber(max)}${unit})`;
394
+ }
395
+ function buildFluidClampWithExplicitMin(minValue, maxValue, unit, vpMin, vpMax) {
396
+ if (minValue === maxValue || vpMax === vpMin) {
397
+ return `${formatNumber(maxValue)}${unit}`;
398
+ }
399
+ const unitToPx = unit === "rem" ? 16 : 1;
400
+ const minPx = minValue * unitToPx;
401
+ const maxPx = maxValue * unitToPx;
402
+ const slopePx = (maxPx - minPx) / (vpMax - vpMin);
403
+ const interceptPx = minPx - slopePx * vpMin;
404
+ const interceptInUnit = interceptPx / unitToPx;
405
+ const slopeVw = slopePx * 100;
406
+ return `clamp(${formatNumber(minValue)}${unit}, ${formatNumber(interceptInUnit)}${unit} + ${formatNumber(slopeVw)}vw, ${formatNumber(maxValue)}${unit})`;
407
+ }
408
+ function formatNumber(n) {
409
+ if (Number.isInteger(n)) return String(n);
410
+ return Number(n.toFixed(4)).toString();
411
+ }
412
+ function buildSiteMarginClamp(siteMargin, fluidRange) {
413
+ const { min, max } = siteMargin;
414
+ const { min: vpMin, max: vpMax } = fluidRange;
415
+ if (min === max || vpMax === vpMin) {
416
+ return `${formatNumber(max)}px`;
417
+ }
418
+ const slopePx = (max - min) / (vpMax - vpMin);
419
+ const interceptPx = min - slopePx * vpMin;
420
+ const slopeVw = slopePx * 100;
421
+ return `clamp(${formatNumber(min)}px, ${formatNumber(interceptPx)}px + ${formatNumber(slopeVw)}vw, ${formatNumber(max)}px)`;
422
+ }
423
+ function buildFluidPropertyValue(valueStr, scale, vpMin, vpMax, baseReference = 16) {
424
+ const parts = parseMultiValue(valueStr);
425
+ if (parts.length === 0) return null;
426
+ let anyScaled = false;
427
+ const out = parts.map((part) => {
428
+ const parsed = parseValue(part);
429
+ if (!parsed) return part;
430
+ if (parsed.unit === "%" || parsed.unit === "em") return part;
431
+ anyScaled = true;
432
+ return buildFluidClamp(parsed.value, parsed.unit, scale, vpMin, vpMax, baseReference);
433
+ });
434
+ return anyScaled ? out.join(" ") : null;
435
+ }
317
436
  var DEFAULT_RESPONSIVE_SCALES = {
318
437
  enabled: false,
438
+ mode: "breakpoints",
319
439
  baseReference: 16,
440
+ fluidRange: { ...DEFAULT_FLUID_RANGE },
441
+ siteMargin: { ...DEFAULT_SITE_MARGIN },
320
442
  fontSize: {
321
443
  tablet: 0.88,
322
444
  mobile: 0.75
@@ -412,6 +534,10 @@ export {
412
534
  getStoredLocale,
413
535
  setStoredLocale,
414
536
  clearStoredLocale,
537
+ DEFAULT_FLUID_RANGE,
538
+ DEFAULT_SITE_MARGIN,
539
+ parseValue,
540
+ SCALABLE_CSS_PROPERTIES,
415
541
  calculateResponsiveValue,
416
542
  getScaleMultiplier,
417
543
  parseMultiValue,
@@ -419,10 +545,15 @@ export {
419
545
  scalePropertyValue,
420
546
  getResponsiveValues,
421
547
  resolveVariableValueAtBreakpoint,
548
+ getSmallestBreakpointName,
549
+ buildFluidClamp,
550
+ buildFluidClampWithExplicitMin,
551
+ buildSiteMarginClamp,
552
+ buildFluidPropertyValue,
422
553
  DEFAULT_RESPONSIVE_SCALES,
423
554
  DEFAULT_REM_CONFIG,
424
555
  convertPxToRem,
425
556
  shouldConvertProperty,
426
557
  applyRemConversion
427
558
  };
428
- //# sourceMappingURL=chunk-B2RTLDXY.js.map
559
+ //# sourceMappingURL=chunk-AZQYF6KE.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../lib/shared/breakpoints.ts", "../../lib/shared/i18n.ts", "../../lib/shared/responsiveScaling.ts", "../../lib/shared/pxToRem.ts"],
4
+ "sourcesContent": ["/**\n * Shared Breakpoint Configuration\n * Defines breakpoints for responsive design\n * Supports dynamic breakpoints from project.config.json\n */\n\n/**\n * Extended breakpoint entry with separate CSS threshold and editor preview width\n * - breakpoint: The CSS media query threshold (max-width value)\n * - previewPoint: The width used in editor preview mode (defaults to breakpoint if not specified)\n * - label: Optional display label for UI (e.g., \"Tablet Landscape\", \"Phone\")\n */\nexport interface BreakpointEntry {\n breakpoint: number;\n previewPoint: number;\n label?: string;\n}\n\n/**\n * Input format for breakpoint config - supports both legacy (number) and new (object) format\n * Legacy: { tablet: 1024 }\n * New: { tablet: { breakpoint: 1024, previewPoint: 768 } }\n */\nexport type BreakpointConfigInput = Record<string, number | BreakpointEntry>;\n\n/**\n * Normalized breakpoint config - always uses object format\n */\nexport type BreakpointConfig = Record<string, BreakpointEntry>;\n\n/**\n * Legacy format for backward compatibility (simple number values)\n */\nexport type LegacyBreakpointConfig = Record<string, number>;\n\n// BreakpointName is now a string to support dynamic breakpoints\nexport type BreakpointName = string;\n\nexport const DEFAULT_BREAKPOINTS: BreakpointConfig = {\n tablet: { breakpoint: 1024, previewPoint: 768 },\n mobile: { breakpoint: 540, previewPoint: 375 },\n} as const;\n\n/**\n * Normalize a breakpoint config input to the full object format\n * Converts legacy number format to object format\n * If previewPoint is not specified, defaults to breakpoint value\n */\nexport function normalizeBreakpointConfig(\n input: BreakpointConfigInput | LegacyBreakpointConfig\n): BreakpointConfig {\n const result: BreakpointConfig = {};\n\n for (const [name, value] of Object.entries(input)) {\n if (typeof value === 'number') {\n // Legacy format: number -> { breakpoint: value, previewPoint: value }\n result[name] = { breakpoint: value, previewPoint: value };\n } else if (typeof value === 'object' && value !== null) {\n // New format: ensure both values exist, preserve label if present\n result[name] = {\n breakpoint: value.breakpoint,\n previewPoint: value.previewPoint ?? value.breakpoint,\n ...(value.label !== undefined && { label: value.label }),\n };\n }\n }\n\n return result;\n}\n\n/**\n * Get just the breakpoint values for CSS generation (media queries)\n * Returns Record<string, number> with breakpoint values\n */\nexport function getBreakpointValues(config: BreakpointConfig): LegacyBreakpointConfig {\n const result: LegacyBreakpointConfig = {};\n for (const [name, entry] of Object.entries(config)) {\n result[name] = entry.breakpoint;\n }\n return result;\n}\n\n/**\n * Get just the preview point values for editor preview\n * Returns Record<string, number> with previewPoint values\n */\nexport function getPreviewPointValues(config: BreakpointConfig): LegacyBreakpointConfig {\n const result: LegacyBreakpointConfig = {};\n for (const [name, entry] of Object.entries(config)) {\n result[name] = entry.previewPoint;\n }\n return result;\n}\n\n/**\n * Get all breakpoint names from the breakpoint configuration\n * Always includes 'base' plus all keys from the config\n * Order: base (desktop) -> breakpoints sorted by value descending (largest to smallest viewport)\n */\nexport function getAllBreakpointNames(\n breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS\n): BreakpointName[] {\n // Base is always included first\n const names: BreakpointName[] = ['base'];\n\n // Get all breakpoint names from config and sort by breakpoint value (descending)\n // This ensures proper order: largest viewport first\n const breakpointEntries = Object.entries(breakpoints);\n breakpointEntries.sort((a, b) => b[1].breakpoint - a[1].breakpoint); // Sort descending by breakpoint value\n\n // Add breakpoint names in sorted order\n for (const [name] of breakpointEntries) {\n names.push(name);\n }\n\n return names;\n}\n\n/**\n * Get active breakpoint name based on viewport width\n * Returns the smallest breakpoint that the viewport width is less than or equal to\n * If viewport is larger than all breakpoints, returns 'base'\n * Uses .breakpoint value for comparison (CSS threshold)\n */\nexport function getBreakpointName(\n viewportWidth: number,\n breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS\n): BreakpointName {\n // Sort breakpoints by breakpoint value (ascending) to find the smallest one that matches\n const breakpointEntries = Object.entries(breakpoints);\n breakpointEntries.sort((a, b) => a[1].breakpoint - b[1].breakpoint); // Sort ascending by breakpoint value\n\n // Find the smallest breakpoint that viewport width is <= to\n for (const [name, entry] of breakpointEntries) {\n if (viewportWidth <= entry.breakpoint) {\n return name;\n }\n }\n\n // If viewport is larger than all breakpoints, return 'base'\n return 'base';\n}\n\n/**\n * Get display label for a breakpoint\n * Priority:\n * 1. Label from config (if set)\n * 2. \"Desktop\" for 'base'\n * 3. Auto-capitalized name (camelCase -> Title Case)\n */\nexport function getBreakpointLabel(\n name: BreakpointName,\n breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS\n): string {\n // Base always returns \"Desktop\"\n if (name === 'base') {\n return 'Desktop';\n }\n\n // Check for custom label in config\n const entry = breakpoints[name];\n if (entry?.label) {\n return entry.label;\n }\n\n // Auto-format: camelCase -> Title Case\n // e.g., \"tabletLandscape\" -> \"Tablet Landscape\"\n return name\n .replace(/([A-Z])/g, ' $1')\n .replace(/^./, (str) => str.toUpperCase())\n .trim();\n}\n", "/**\n * Internationalization (i18n) utilities\n * Handles inline translation resolution for component props\n */\n\nimport type { I18nValue, I18nConfig, LocaleConfig } from './types/components';\n\n/**\n * Default i18n configuration\n */\nexport const DEFAULT_I18N_CONFIG: I18nConfig = {\n defaultLocale: 'en',\n locales: [\n { code: 'en', name: 'English', nativeName: 'English', langTag: 'en-US' }\n ],\n};\n\n// ============================================\n// Locale helper functions\n// ============================================\n\n/**\n * Get array of locale codes from config\n */\nexport function getLocaleCodes(config: I18nConfig): string[] {\n return config.locales.map(loc => loc.code);\n}\n\n/**\n * Find a locale config by its code\n */\nexport function findLocaleByCode(config: I18nConfig, code: string): LocaleConfig | undefined {\n return config.locales.find(loc => loc.code === code);\n}\n\n/**\n * Check if a locale code is valid/exists in config\n */\nexport function isValidLocaleCode(config: I18nConfig, code: string): boolean {\n return config.locales.some(loc => loc.code === code);\n}\n\n// ============================================\n// Config Migration (old string[] -> new LocaleConfig[])\n// ============================================\n\n/**\n * Convert old locale format (string) to new format (LocaleConfig)\n */\nfunction migrateLocaleString(code: string): LocaleConfig {\n const upperCode = code.toUpperCase();\n return {\n code: code.toLowerCase(),\n name: upperCode,\n nativeName: upperCode,\n langTag: `${code.toLowerCase()}-${upperCode}`,\n };\n}\n\n/**\n * Check if locales array is in old string format\n */\nfunction isOldLocaleFormat(locales: unknown): locales is string[] {\n return Array.isArray(locales) && locales.length > 0 && typeof locales[0] === 'string';\n}\n\n/**\n * Migrate i18n config from old format to new format\n * Old: { defaultLocale: \"en\", locales: [\"en\", \"pl\"] }\n * New: { defaultLocale: \"en\", locales: [{ code: \"en\", name: \"EN\", ... }] }\n */\nexport function migrateI18nConfig(i18n: unknown): I18nConfig {\n if (!i18n || typeof i18n !== 'object') {\n return DEFAULT_I18N_CONFIG;\n }\n\n const config = i18n as Record<string, unknown>;\n const defaultLocale = (config.defaultLocale as string) || 'en';\n const locales = config.locales;\n\n if (!locales || !Array.isArray(locales)) {\n return DEFAULT_I18N_CONFIG;\n }\n\n // Migrate old string[] format\n if (isOldLocaleFormat(locales)) {\n return {\n defaultLocale,\n locales: locales.map(migrateLocaleString),\n };\n }\n\n // Already in new format\n return {\n defaultLocale,\n locales: locales as LocaleConfig[],\n };\n}\n\n/**\n * Type guard to check if a value is an I18nValue object\n */\nexport function isI18nValue(value: unknown): value is I18nValue {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n return '_i18n' in value && (value as Record<string, unknown>)._i18n === true;\n}\n\n/**\n * Resolve a single translation value for the given locale\n * Fallback order: exact locale -> default locale -> first available -> empty\n * Works with any value type (strings, arrays for list props, etc.)\n */\nexport function resolveTranslation(\n value: I18nValue,\n locale: string,\n config: I18nConfig\n): unknown {\n // Try exact locale match (any type - string, array, etc.)\n if (locale in value && value[locale] !== undefined && locale !== '_i18n') {\n return value[locale];\n }\n\n // Try default locale\n if (config.defaultLocale in value && value[config.defaultLocale] !== undefined) {\n return value[config.defaultLocale];\n }\n\n // Get first available value (skip _i18n marker)\n for (const key of Object.keys(value)) {\n if (key !== '_i18n' && value[key] !== undefined) {\n return value[key];\n }\n }\n\n // Return empty string for string i18n, empty array for list i18n\n // Check if any value is an array to determine the type\n const hasArrayValue = Object.entries(value).some(\n ([k, v]) => k !== '_i18n' && Array.isArray(v)\n );\n return hasArrayValue ? [] : '';\n}\n\n/**\n * Resolve a value that might be an I18nValue or a regular value\n * Returns the original value if not an I18nValue\n */\nexport function resolveI18nValue(\n value: unknown,\n locale: string,\n config: I18nConfig\n): unknown {\n if (isI18nValue(value)) {\n return resolveTranslation(value, locale, config);\n }\n return value;\n}\n\n/**\n * Recursively resolve all I18nValue objects in a props object\n */\nexport function resolveI18nInProps(\n props: Record<string, unknown>,\n locale: string,\n config: I18nConfig\n): Record<string, unknown> {\n const resolved: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(props)) {\n if (isI18nValue(value)) {\n resolved[key] = resolveTranslation(value, locale, config);\n } else if (Array.isArray(value)) {\n resolved[key] = value.map((item) =>\n isI18nValue(item) ? resolveTranslation(item, locale, config) : item\n );\n } else if (typeof value === 'object' && value !== null) {\n // Recursively resolve nested objects (but not I18nValue which is already handled)\n resolved[key] = resolveI18nInProps(\n value as Record<string, unknown>,\n locale,\n config\n );\n } else {\n resolved[key] = value;\n }\n }\n\n return resolved;\n}\n\n/**\n * Extract locale from URL path prefix\n * e.g., '/en/about' -> 'en', '/pl/' -> 'pl', '/about' -> null\n */\nexport function extractLocaleFromPath(\n path: string,\n config: I18nConfig\n): { locale: string | null; pathWithoutLocale: string } {\n // Remove leading slash and split\n const cleanPath = path.startsWith('/') ? path.slice(1) : path;\n const segments = cleanPath.split('/');\n\n if (segments.length > 0 && isValidLocaleCode(config, segments[0])) {\n const locale = segments[0];\n const pathWithoutLocale = '/' + segments.slice(1).join('/');\n return { locale, pathWithoutLocale: pathWithoutLocale || '/' };\n }\n\n return { locale: null, pathWithoutLocale: path };\n}\n\n/**\n * Build a localized path\n * e.g., ('/about', 'pl') -> '/pl/about'\n */\nexport function buildLocalizedPath(path: string, locale: string): string {\n const cleanPath = path.startsWith('/') ? path : '/' + path;\n return `/${locale}${cleanPath === '/' ? '' : cleanPath}`;\n}\n\n/**\n * Locale context containing resolved locale info\n */\nexport interface LocaleContext {\n /** The effective locale (never null) */\n locale: string;\n /** Path with locale prefix removed */\n pathWithoutLocale: string;\n /** Whether the current locale is the default */\n isDefaultLocale: boolean;\n}\n\n/**\n * Parse locale from path and return full context with effective locale\n * Combines extractLocaleFromPath + defaultLocale resolution in one call\n */\nexport function parseLocaleFromPath(\n path: string,\n config: I18nConfig\n): LocaleContext {\n const { locale, pathWithoutLocale } = extractLocaleFromPath(path, config);\n const effectiveLocale = locale || config.defaultLocale;\n\n return {\n locale: effectiveLocale,\n pathWithoutLocale,\n isDefaultLocale: effectiveLocale === config.defaultLocale\n };\n}\n\n// ============================================\n// Client-side locale persistence utilities\n// ============================================\n\nconst LOCALE_STORAGE_KEY = 'meno_locale_preference';\nconst OLD_LOCALE_STORAGE_KEY = 'uplo_locale_preference';\n\n/**\n * Migrate locale storage key from old to new (one-time migration)\n */\nfunction migrateLocaleStorageKey(): void {\n if (typeof window === 'undefined') return;\n try {\n const oldValue = localStorage.getItem(OLD_LOCALE_STORAGE_KEY);\n const newValue = localStorage.getItem(LOCALE_STORAGE_KEY);\n if (oldValue && !newValue) {\n localStorage.setItem(LOCALE_STORAGE_KEY, oldValue);\n localStorage.removeItem(OLD_LOCALE_STORAGE_KEY);\n }\n } catch {\n // Storage not available\n }\n}\n\n/**\n * Get stored locale preference from localStorage (client-side only)\n */\nexport function getStoredLocale(): string | null {\n if (typeof window === 'undefined') return null;\n try {\n // Migrate from old key if needed\n migrateLocaleStorageKey();\n return localStorage.getItem(LOCALE_STORAGE_KEY);\n } catch {\n return null;\n }\n}\n\n/**\n * Store locale preference to localStorage (client-side only)\n */\nexport function setStoredLocale(locale: string): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.setItem(LOCALE_STORAGE_KEY, locale);\n } catch {\n // Storage not available\n }\n}\n\n/**\n * Clear stored locale preference (client-side only)\n */\nexport function clearStoredLocale(): void {\n if (typeof window === 'undefined') return;\n try {\n localStorage.removeItem(LOCALE_STORAGE_KEY);\n } catch {\n // Storage not available\n }\n}\n", "/**\n * Responsive Scaling Calculator\n * Automatically calculates responsive values for different breakpoints\n * using configured scale multipliers\n */\n\n/**\n * Scale configuration for a CSS property category\n * Keys are breakpoint names (e.g., 'tablet', 'mobile', 'small')\n * Values are scale multipliers (e.g., 0.88, 0.75)\n */\nexport type BreakpointScales = Record<string, number>;\n\nexport type ResponsiveMode = 'breakpoints' | 'fluid';\n\nexport interface FluidRange {\n /** Lower viewport bound in pixels (e.g. 320) */\n min: number;\n /** Upper viewport bound in pixels (e.g. 1440) */\n max: number;\n}\n\nexport interface SiteMarginConfig {\n /** Lower bound of the side margin at smallest viewport (px). */\n min: number;\n /** Upper bound of the side margin at largest viewport (px). */\n max: number;\n}\n\nexport interface ResponsiveScales {\n enabled: boolean;\n /** Scaling strategy. Missing \u2192 'breakpoints' (back-compat with old configs). */\n mode?: ResponsiveMode;\n baseReference: number;\n /** Viewport bounds used when `mode === 'fluid'`. Defaults to 320 / 1440 px. */\n fluidRange?: FluidRange;\n /**\n * Container side margin range, in fluid mode emitted as a CSS variable\n * `--site-margin: clamp(min, \u2026, max)` on `:root`. Lets users write\n * `width: calc(100% - var(--site-margin) * 2)` for the container pattern.\n */\n siteMargin?: SiteMarginConfig;\n fontSize?: BreakpointScales;\n padding?: BreakpointScales;\n margin?: BreakpointScales;\n gap?: BreakpointScales;\n borderRadius?: BreakpointScales;\n size?: BreakpointScales;\n [key: string]: boolean | number | string | BreakpointScales | FluidRange | SiteMarginConfig | undefined;\n}\n\nexport const DEFAULT_FLUID_RANGE: FluidRange = { min: 320, max: 1440 };\nexport const DEFAULT_SITE_MARGIN: SiteMarginConfig = { min: 16, max: 32 };\n\nexport type CSSPropertyType = 'fontSize' | 'padding' | 'margin' | 'gap' | 'paddingTop' | 'paddingRight' | 'paddingBottom' | 'paddingLeft' | 'marginTop' | 'marginRight' | 'marginBottom' | 'marginLeft' | 'rowGap' | 'columnGap' | 'borderRadius' | 'borderTopLeftRadius' | 'borderTopRightRadius' | 'borderBottomLeftRadius' | 'borderBottomRightRadius' | 'width' | 'height' | 'maxWidth' | 'maxHeight' | 'minWidth' | 'minHeight';\n\n/**\n * Map CSS property to its scale category\n * e.g., paddingTop -> padding, marginRight -> margin\n */\nfunction getScaleCategory(property: CSSPropertyType): keyof ResponsiveScales | null {\n const propertyStr = property as string;\n if (property === 'fontSize') return 'fontSize';\n if (propertyStr.startsWith('padding')) return 'padding';\n if (propertyStr.startsWith('margin')) return 'margin';\n if (property === 'gap' || property === 'rowGap' || property === 'columnGap') return 'gap';\n if (propertyStr === 'borderRadius' || (propertyStr.startsWith('border') && propertyStr.includes('Radius'))) return 'borderRadius';\n if (property === 'width' || property === 'height' || property === 'maxWidth' || property === 'maxHeight' || property === 'minWidth' || property === 'minHeight') return 'size';\n return null;\n}\n\n/**\n * Extract numeric value and unit from a CSS value string\n * e.g., \"67px\" -> { value: 67, unit: \"px\" }\n */\nexport function parseValue(valueStr: string): { value: number; unit: string } | null {\n const match = valueStr.trim().match(/^(-?[\\d.]+)(px|rem|em|%|pt)$/);\n if (!match) return null;\n return {\n value: parseFloat(match[1]),\n unit: match[2],\n };\n}\n\n/**\n * CSS properties that get fluid `clamp()` / breakpoint scaling. Mirrors the\n * `AUTO_RESPONSIVE_TYPE_MAP` keys in `cssGeneration.ts`; centralized here so\n * `utilityClassMapper.ts` can consult it without a cross-module import cycle.\n */\nexport const SCALABLE_CSS_PROPERTIES: ReadonlySet<string> = new Set([\n 'padding',\n 'padding-left',\n 'padding-right',\n 'padding-top',\n 'padding-bottom',\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'paddingBottom',\n 'margin',\n 'margin-left',\n 'margin-right',\n 'margin-top',\n 'margin-bottom',\n 'marginLeft',\n 'marginRight',\n 'marginTop',\n 'marginBottom',\n 'font-size',\n 'fontSize',\n 'gap',\n 'row-gap',\n 'column-gap',\n 'rowGap',\n 'columnGap',\n 'border-radius',\n 'borderRadius',\n 'border-top-left-radius',\n 'border-top-right-radius',\n 'border-bottom-left-radius',\n 'border-bottom-right-radius',\n 'borderTopLeftRadius',\n 'borderTopRightRadius',\n 'borderBottomLeftRadius',\n 'borderBottomRightRadius',\n 'width',\n 'height',\n 'max-width',\n 'max-height',\n 'min-width',\n 'min-height',\n 'maxWidth',\n 'maxHeight',\n 'minWidth',\n 'minHeight',\n]);\n\n/**\n * Calculate responsive value using the formula:\n * responsive_value = base_value + (base_value - base_reference) * (scale - 1)\n */\nexport function calculateResponsiveValue(\n baseValue: number,\n baseReference: number,\n scale: number\n): number {\n // Values at or below baseReference stay unchanged\n if (Math.abs(baseValue) <= baseReference) {\n return Math.round(baseValue);\n }\n const scaled = baseValue + (baseValue - baseReference) * (scale - 1);\n return Math.round(scaled);\n}\n\n/**\n * Get the scale multiplier for a specific property and breakpoint\n * @param scales - The responsive scales configuration\n * @param property - The CSS property type (e.g., 'fontSize', 'padding')\n * @param breakpoint - The breakpoint name (e.g., 'tablet', 'mobile', 'small')\n */\nexport function getScaleMultiplier(\n scales: ResponsiveScales,\n property: CSSPropertyType,\n breakpoint: string\n): number | null {\n const category = getScaleCategory(property);\n if (!category || !scales[category]) return null;\n\n const scaleConfig = scales[category] as BreakpointScales | undefined;\n return scaleConfig?.[breakpoint] ?? null;\n}\n\n/**\n * Parse multi-value CSS property (e.g., \"20px 40px\" for padding)\n * Handles both space-separated (\"20px 40px\") and hyphen-separated (\"20px-40px\") formats\n * Returns array of individual values\n */\nexport function parseMultiValue(valueStr: string): string[] {\n // First, convert hyphen separators to spaces (for class names like \"p-0-80px\" \u2192 \"0-80px\")\n // But only convert hyphens between values (digit/px followed by hyphen followed by digit/px)\n const normalized = valueStr.replace(/(?<=\\w)-(?=\\d|auto|inherit|initial|unset)/g, ' ');\n return normalized.trim().split(/\\s+/).filter(v => v.length > 0);\n}\n\n/**\n * Scale a single CSS value using the responsive scale\n * Returns null if the value cannot be parsed (no unit)\n */\nexport function scaleValue(\n valueStr: string,\n baseReference: number,\n scale: number\n): string | null {\n const parsed = parseValue(valueStr);\n if (!parsed) return null;\n\n // `%` and `em` are already relative to their rendering context\n // (container / local font-size), so they should not be rescaled.\n if (parsed.unit === '%' || parsed.unit === 'em') {\n return valueStr.trim();\n }\n\n const scaledValue = calculateResponsiveValue(parsed.value, baseReference, scale);\n return `${scaledValue}${parsed.unit}`;\n}\n\n/**\n * Scale a potentially multi-value CSS property\n * e.g., \"20px 40px\" -> \"18px 36px\" (both values scaled independently)\n * Unitless values (0, auto, inherit) are kept as-is\n */\nexport function scalePropertyValue(\n valueStr: string,\n baseReference: number,\n scale: number\n): string | null {\n const parts = parseMultiValue(valueStr);\n if (parts.length === 0) return null;\n\n const scaledParts = parts.map(part => {\n // Try to scale the value\n const scaled = scaleValue(part, baseReference, scale);\n if (scaled !== null) {\n return scaled;\n }\n // If it can't be scaled, keep it as-is (for unitless values like 0, auto, inherit)\n return part;\n });\n\n return scaledParts.join(' ');\n}\n\n/**\n * Get responsive values for all breakpoints\n * Returns object with calculated values for each breakpoint\n *\n * @param baseValue - The base CSS value (e.g., '67px')\n * @param property - The CSS property type (e.g., 'fontSize')\n * @param scales - The responsive scales configuration\n * @param breakpointNames - Optional array of breakpoint names to calculate values for.\n * If not provided, defaults to ['tablet', 'mobile'] for backward compatibility.\n */\nexport function getResponsiveValues(\n baseValue: string,\n property: CSSPropertyType,\n scales: ResponsiveScales,\n breakpointNames?: string[]\n): Record<string, string | null> {\n if (!scales.enabled) {\n return { base: baseValue };\n }\n\n const result: Record<string, string | null> = {\n base: baseValue,\n };\n\n const baseRef = scales.baseReference || 16;\n\n // Use provided breakpoint names or default to tablet/mobile for backward compatibility\n const breakpoints = breakpointNames ?? ['tablet', 'mobile'];\n\n // Calculate value for each breakpoint\n for (const breakpointName of breakpoints) {\n const scale = getScaleMultiplier(scales, property, breakpointName);\n if (scale !== null) {\n result[breakpointName] = scalePropertyValue(baseValue, baseRef, scale);\n }\n }\n\n return result;\n}\n\n/**\n * Resolve the effective value of a CSS variable at a given breakpoint.\n *\n * Precedence (mirrors generateVariablesCSS in cssGenerator.ts so the editor\n * widget stays in sync with what the browser will render):\n * 1. `breakpoint === 'base'` \u2192 variable.value\n * 2. explicit per-variable override \u2192 variable.scales[breakpoint]\n * 3. globally-scaled value (ResponsiveScales multiplier for variable.type)\n * 4. fallback \u2192 variable.value\n */\nexport function resolveVariableValueAtBreakpoint(\n variable: { value: string; type: string; scales?: Record<string, string> },\n breakpoint: string,\n responsiveScales?: ResponsiveScales | null\n): string {\n if (breakpoint === 'base') return variable.value;\n\n const override = variable.scales?.[breakpoint];\n if (override !== undefined) return override;\n\n if (responsiveScales?.enabled && variable.type !== 'none') {\n const scale = getScaleMultiplier(\n responsiveScales,\n variable.type as CSSPropertyType,\n breakpoint\n );\n if (scale !== null) {\n const baseRef = responsiveScales.baseReference || 16;\n const scaled = scalePropertyValue(variable.value, baseRef, scale);\n if (scaled !== null) return scaled;\n }\n }\n\n return variable.value;\n}\n\n/**\n * Pick the smallest (most restrictive) breakpoint name from a config object,\n * by `breakpoint` field. Used in fluid mode to choose which scale multiplier\n * defines the MIN of the clamp.\n *\n * Returns null if there are no entries.\n */\nexport function getSmallestBreakpointName(\n breakpoints: Record<string, { breakpoint: number }> | undefined | null\n): string | null {\n if (!breakpoints) return null;\n const entries = Object.entries(breakpoints);\n if (entries.length === 0) return null;\n let smallestName = entries[0][0];\n let smallestWidth = entries[0][1].breakpoint;\n for (const [name, cfg] of entries) {\n if (cfg.breakpoint < smallestWidth) {\n smallestWidth = cfg.breakpoint;\n smallestName = name;\n }\n }\n return smallestName;\n}\n\n/**\n * Build a `clamp(MIN, intercept + slope*100vw, MAX)` expression that interpolates\n * linearly between (vpMin, MIN) and (vpMax, MAX).\n *\n * - `baseValue` is the desktop/MAX value in CSS units.\n * - `unit` is the CSS unit (\"px\", \"rem\", etc.) used for both bounds.\n * - `scale` is the multiplier applied at the small end (mobile). Reuses\n * `calculateResponsiveValue` so the same multipliers used in 'breakpoints'\n * mode produce the same MIN endpoint in 'fluid' mode.\n * - `vpMin` / `vpMax` are viewport widths in pixels.\n *\n * If MIN === MAX (e.g. value at or below baseReference, or scale === 1),\n * returns a plain `${baseValue}${unit}` \u2014 no clamp emitted.\n */\nexport function buildFluidClamp(\n baseValue: number,\n unit: string,\n scale: number,\n vpMin: number,\n vpMax: number,\n baseReference = 16\n): string {\n const max = baseValue;\n const min = calculateResponsiveValue(baseValue, baseReference, scale);\n\n if (min === max || vpMax === vpMin) {\n return `${formatNumber(max)}${unit}`;\n }\n\n // Convert viewport bounds into the same unit as the value, so the\n // intercept term stays in `unit`. For px / rem we keep px throughout vw maths\n // but emit the intercept in the value's unit by converting (1rem = 16px).\n const unitToPx = unit === 'rem' ? 16 : 1;\n const minPx = min * unitToPx;\n const maxPx = max * unitToPx;\n const slopePx = (maxPx - minPx) / (vpMax - vpMin); // px per px-of-viewport\n const interceptPx = minPx - slopePx * vpMin; // px\n const interceptInUnit = interceptPx / unitToPx;\n const slopeVw = slopePx * 100; // because 1vw = viewport_width / 100 px\n\n return `clamp(${formatNumber(min)}${unit}, ${formatNumber(interceptInUnit)}${unit} + ${formatNumber(slopeVw)}vw, ${formatNumber(max)}${unit})`;\n}\n\n/**\n * Build a `clamp(MIN, intercept + slope*100vw, MAX)` expression where MIN is\n * supplied directly (e.g. from an authored mobile override) rather than\n * derived from `responsiveScales` \u00D7 `baseReference`.\n *\n * Used when a node has both `style.base.<prop>` and `style.mobile.<prop>` in\n * fluid mode \u2014 the mobile value is consumed as the clamp's small end so the\n * smooth interpolation lands exactly on the authored mobile value at the\n * narrow viewport, avoiding the jump that a separate @media override would\n * create.\n *\n * Same units / vw math as `buildFluidClamp`. Returns plain `${max}${unit}`\n * when MIN === MAX or the viewport range degenerates.\n */\nexport function buildFluidClampWithExplicitMin(\n minValue: number,\n maxValue: number,\n unit: string,\n vpMin: number,\n vpMax: number\n): string {\n if (minValue === maxValue || vpMax === vpMin) {\n return `${formatNumber(maxValue)}${unit}`;\n }\n\n const unitToPx = unit === 'rem' ? 16 : 1;\n const minPx = minValue * unitToPx;\n const maxPx = maxValue * unitToPx;\n const slopePx = (maxPx - minPx) / (vpMax - vpMin);\n const interceptPx = minPx - slopePx * vpMin;\n const interceptInUnit = interceptPx / unitToPx;\n const slopeVw = slopePx * 100;\n\n return `clamp(${formatNumber(minValue)}${unit}, ${formatNumber(interceptInUnit)}${unit} + ${formatNumber(slopeVw)}vw, ${formatNumber(maxValue)}${unit})`;\n}\n\n/**\n * Trim noisy floating-point output (e.g. 21.81818181818182 \u2192 21.8182).\n */\nfunction formatNumber(n: number): string {\n if (Number.isInteger(n)) return String(n);\n return Number(n.toFixed(4)).toString();\n}\n\n/**\n * Build the CSS value for the `--site-margin` variable in fluid mode.\n * Always emits a clamp() going from `siteMargin.min` to `siteMargin.max` (px),\n * interpolated linearly across `fluidRange.min`..`fluidRange.max`.\n *\n * If `min === max` the function returns the plain value (no clamp).\n */\nexport function buildSiteMarginClamp(\n siteMargin: SiteMarginConfig,\n fluidRange: FluidRange\n): string {\n const { min, max } = siteMargin;\n const { min: vpMin, max: vpMax } = fluidRange;\n\n if (min === max || vpMax === vpMin) {\n return `${formatNumber(max)}px`;\n }\n\n const slopePx = (max - min) / (vpMax - vpMin);\n const interceptPx = min - slopePx * vpMin;\n const slopeVw = slopePx * 100;\n\n return `clamp(${formatNumber(min)}px, ${formatNumber(interceptPx)}px + ${formatNumber(slopeVw)}vw, ${formatNumber(max)}px)`;\n}\n\n/**\n * Build a fluid clamp() value for a CSS string value (e.g. \"32px\", \"2rem\").\n * Multi-value strings (\"20px 40px\") are scaled per-token, like\n * `scalePropertyValue` does for breakpoint mode. Tokens without a unit\n * (`0`, `auto`, `inherit`) are kept verbatim.\n *\n * Returns null if no token is scalable.\n */\nexport function buildFluidPropertyValue(\n valueStr: string,\n scale: number,\n vpMin: number,\n vpMax: number,\n baseReference = 16\n): string | null {\n const parts = parseMultiValue(valueStr);\n if (parts.length === 0) return null;\n\n let anyScaled = false;\n const out = parts.map(part => {\n const parsed = parseValue(part);\n if (!parsed) return part;\n if (parsed.unit === '%' || parsed.unit === 'em') return part;\n anyScaled = true;\n return buildFluidClamp(parsed.value, parsed.unit, scale, vpMin, vpMax, baseReference);\n });\n\n return anyScaled ? out.join(' ') : null;\n}\n\n/**\n * Default responsive scales configuration\n */\nexport const DEFAULT_RESPONSIVE_SCALES: ResponsiveScales = {\n enabled: false,\n mode: 'breakpoints',\n baseReference: 16,\n fluidRange: { ...DEFAULT_FLUID_RANGE },\n siteMargin: { ...DEFAULT_SITE_MARGIN },\n fontSize: {\n tablet: 0.88,\n mobile: 0.75,\n },\n padding: {\n tablet: 0.75,\n mobile: 0.5,\n },\n margin: {\n tablet: 0.7,\n mobile: 0.45,\n },\n gap: {\n tablet: 0.65,\n mobile: 0.4,\n },\n borderRadius: {\n tablet: 0.85,\n mobile: 0.7,\n },\n size: {\n tablet: 0.9,\n mobile: 0.75,\n },\n};\n", "export interface RemConversionConfig {\n enabled: boolean;\n baseFontSize: number;\n}\n\nexport const DEFAULT_REM_CONFIG: RemConversionConfig = {\n enabled: false,\n baseFontSize: 16,\n};\n\nconst PX_REGEX = /(-?\\d*\\.?\\d+)px/g;\n\n/**\n * Convert all px values in a CSS value string to rem.\n * Handles multi-value shorthands like \"16px 32px\" -> \"1rem 2rem\".\n * 0px becomes \"0\" (unitless).\n */\nexport function convertPxToRem(cssValue: string, baseFontSize: number): string {\n return cssValue.replace(PX_REGEX, (_, num) => {\n const px = parseFloat(num);\n if (px === 0) return '0';\n const rem = px / baseFontSize;\n // Round to 4 decimal places, strip trailing zeros\n const rounded = parseFloat(rem.toFixed(4));\n return `${rounded}rem`;\n });\n}\n\n/**\n * CSS properties that should keep px values (thin borders, shadows).\n */\nconst PX_KEEP_PROPERTIES = new Set([\n 'border-width',\n 'border-top-width',\n 'border-right-width',\n 'border-bottom-width',\n 'border-left-width',\n 'outline-width',\n 'outline-offset',\n 'border',\n 'box-shadow',\n 'text-shadow',\n]);\n\nexport function shouldConvertProperty(cssProperty: string): boolean {\n return !PX_KEEP_PROPERTIES.has(cssProperty);\n}\n\n/**\n * Apply rem conversion to a CSS declarations string (e.g. \"padding: 16px; font-size: 18px\").\n * Checks each property against the exclusion list before converting.\n */\nexport function applyRemConversion(\n declarations: string,\n remConfig?: RemConversionConfig\n): string {\n if (!remConfig?.enabled) return declarations;\n\n return declarations\n .split(';')\n .map(decl => {\n const trimmed = decl.trim();\n if (!trimmed) return '';\n const colonIndex = trimmed.indexOf(':');\n if (colonIndex === -1) return trimmed;\n\n const property = trimmed.substring(0, colonIndex).trim();\n const value = trimmed.substring(colonIndex + 1).trim();\n\n if (shouldConvertProperty(property)) {\n return `${property}: ${convertPxToRem(value, remConfig.baseFontSize)}`;\n }\n return trimmed;\n })\n .filter(Boolean)\n .join('; ');\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }