meno-core 1.1.4 → 1.1.6

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 (37) hide show
  1. package/dist/chunks/{chunk-ZEDLSHYQ.js → chunk-GHNLTFCN.js} +44 -12
  2. package/dist/chunks/chunk-GHNLTFCN.js.map +7 -0
  3. package/dist/chunks/{chunk-UOF4MCAD.js → chunk-KX2LPIZZ.js} +607 -16
  4. package/dist/chunks/{chunk-UOF4MCAD.js.map → chunk-KX2LPIZZ.js.map} +3 -3
  5. package/dist/chunks/{chunk-FQBIC2OB.js → chunk-YMBUSHII.js} +1 -1
  6. package/dist/chunks/{chunk-FQBIC2OB.js.map → chunk-YMBUSHII.js.map} +1 -1
  7. package/dist/lib/client/index.js +56 -12
  8. package/dist/lib/client/index.js.map +2 -2
  9. package/dist/lib/server/index.js +121 -26
  10. package/dist/lib/server/index.js.map +3 -3
  11. package/dist/lib/shared/index.js +8 -2
  12. package/dist/lib/shared/index.js.map +1 -1
  13. package/lib/client/core/ComponentBuilder.test.ts +137 -0
  14. package/lib/client/core/ComponentBuilder.ts +52 -13
  15. package/lib/client/core/builders/embedBuilder.ts +15 -1
  16. package/lib/client/core/builders/linkNodeBuilder.ts +15 -1
  17. package/lib/client/core/builders/localeListBuilder.ts +15 -1
  18. package/lib/client/templateEngine.test.ts +106 -3
  19. package/lib/client/templateEngine.ts +50 -10
  20. package/lib/server/fileWatcher.test.ts +90 -0
  21. package/lib/server/fileWatcher.ts +36 -0
  22. package/lib/server/services/configService.ts +0 -5
  23. package/lib/server/ssr/htmlGenerator.test.ts +105 -3
  24. package/lib/server/ssr/htmlGenerator.ts +94 -42
  25. package/lib/server/ssr/ssrRenderer.test.ts +100 -0
  26. package/lib/server/ssr/ssrRenderer.ts +59 -14
  27. package/lib/shared/cssGeneration.test.ts +36 -0
  28. package/lib/shared/cssGeneration.ts +6 -1
  29. package/lib/shared/tailwindThemeScale.ts +1 -0
  30. package/lib/shared/templateStyleVars.ts +49 -0
  31. package/lib/shared/types/comment.ts +9 -3
  32. package/lib/shared/utilityClassConfig.ts +469 -10
  33. package/lib/shared/utilityClassMapper.test.ts +200 -2
  34. package/lib/shared/utilityClassMapper.ts +153 -0
  35. package/lib/shared/utilityClassNames.ts +90 -0
  36. package/package.json +1 -1
  37. package/dist/chunks/chunk-ZEDLSHYQ.js.map +0 -7
@@ -384,6 +384,42 @@ describe('cssGeneration', () => {
384
384
  expect(generateRuleForClass('[text-overflow:ellipsis]')).toBe('text-overflow: ellipsis;');
385
385
  expect(generateRuleForClass('[clip-path:circle(50%)]')).toBe('clip-path: circle(50%);');
386
386
  });
387
+
388
+ test('filter functions wrap the value in their function', () => {
389
+ expect(generateRuleForClass('blur-[70px]')).toBe('filter: blur(70px);');
390
+ expect(generateRuleForClass('backdrop-blur-[8px]')).toBe('backdrop-filter: blur(8px);');
391
+ expect(generateRuleForClass('blur-(--glow)')).toBe('filter: blur(var(--glow));');
392
+ expect(generateRuleForClass('brightness-50')).toBe('filter: brightness(0.5);');
393
+ expect(generateRuleForClass('grayscale')).toBe('filter: grayscale(100%);');
394
+ expect(generateRuleForClass('hue-rotate-90')).toBe('filter: hue-rotate(90deg);');
395
+ expect(generateRuleForClass('drop-shadow-[0_4px_6px_#0003]')).toBe('filter: drop-shadow(0 4px 6px #0003);');
396
+ expect(generateRuleForClass('backdrop-opacity-50')).toBe('backdrop-filter: opacity(0.5);');
397
+ // Length named scale is deliberately not absorbed (no blur theme tokens).
398
+ expect(generateRuleForClass('blur-sm')).toBeNull();
399
+ });
400
+
401
+ test('per-axis transforms and side radius expand correctly', () => {
402
+ expect(generateRuleForClass('skew-x-[10deg]')).toBe('transform: skewX(10deg);');
403
+ expect(generateRuleForClass('scale-y-95')).toBe('scale: 1 0.95;');
404
+ expect(generateRuleForClass('rounded-t-lg')).toBe(
405
+ 'border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-lg);',
406
+ );
407
+ expect(generateRuleForClass('rounded-l-[8px]')).toBe(
408
+ 'border-top-left-radius: 8px; border-bottom-left-radius: 8px;',
409
+ );
410
+ });
411
+
412
+ test('new statics and viewport keywords', () => {
413
+ expect(generateRuleForClass('italic')).toBe('font-style: italic;');
414
+ expect(generateRuleForClass('text-nowrap')).toBe('white-space: nowrap;');
415
+ expect(generateRuleForClass('break-words')).toBe('overflow-wrap: break-word;');
416
+ expect(generateRuleForClass('isolate')).toBe('isolation: isolate;');
417
+ expect(generateRuleForClass('snap-x')).toBe('scroll-snap-type: x mandatory;');
418
+ expect(generateRuleForClass('mix-blend-multiply')).toBe('mix-blend-mode: multiply;');
419
+ expect(generateRuleForClass('columns-3')).toBe('columns: 3;');
420
+ expect(generateRuleForClass('h-dvh')).toBe('height: 100dvh;');
421
+ expect(generateRuleForClass('shadow-inner')).toBe('box-shadow: var(--shadow-inner);');
422
+ });
387
423
  });
388
424
  });
389
425
 
@@ -4,7 +4,7 @@
4
4
  * Used by both client and server to ensure consistent CSS output
5
5
  */
6
6
 
7
- import { propertyOrder, staticUtilityReverse, presetClassReverse } from './utilityClassConfig';
7
+ import { propertyOrder, staticUtilityReverse, presetClassReverse, ROUNDED_SIDE_CORNERS } from './utilityClassConfig';
8
8
  import {
9
9
  parseUtilityClass,
10
10
  splitVariantPrefix,
@@ -217,6 +217,11 @@ export function generateRuleForClass(className: string, knownTokens?: ReadonlySe
217
217
  if (root === 'size') {
218
218
  return `width: ${value}; height: ${value};`;
219
219
  }
220
+ // Side border-radius: no CSS per-side shorthand — emit both corner longhands.
221
+ const sideCorners = root ? ROUNDED_SIDE_CORNERS[root] : undefined;
222
+ if (sideCorners) {
223
+ return `${sideCorners[0]}: ${value}; ${sideCorners[1]}: ${value};`;
224
+ }
220
225
  if (root === 'px') {
221
226
  return `padding-left: ${value}; padding-right: ${value};`;
222
227
  }
@@ -137,6 +137,7 @@ const SPECS: ScaleSpec[] = [
137
137
  ['lg', '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)'],
138
138
  ['xl', '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)'],
139
139
  ['2xl', '0 25px 50px -12px rgb(0 0 0 / 0.25)'],
140
+ ['inner', 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)'],
140
141
  ],
141
142
  },
142
143
  {
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Design-canvas bridge for `{{template}}`-bound style declarations — meno-core's mirror
3
+ * of the meno-astro var-bridge (packages/astro `runtime/cssValue.ts` templateVarName +
4
+ * `runtime/style.ts` resolveMappingsInFlat).
5
+ *
6
+ * A style value bound to a prop template (`gap: "{{gap}}px"`) can't be a static utility
7
+ * class in a real Astro build — its value is per-instance — so meno-astro emits the class
8
+ * `gap-[var(--m-<bp>-gap)]` and sets that variable inline on the element. Two consequences
9
+ * the design canvas must reproduce for WYSIWYG parity:
10
+ *
11
+ * 1. Auto-responsive scaling never applies to the declaration (the scaler can't scale a
12
+ * `var()`), so the value renders CONSTANT across breakpoints in a real build. Before
13
+ * this bridge, the canvas resolved the template to a concrete class (`gap-[40px]`)
14
+ * which the scaler happily shrank at tablet/mobile — values looked responsive in
15
+ * Fast Design Mode and fixed on the published site.
16
+ * 2. The inline style sets the VARIABLE, not the property, so interactive class rules
17
+ * (`:hover`, `.is-open`) still override the declaration by normal specificity.
18
+ *
19
+ * `processStructure` (templateEngine) performs the bridging when it resolves a component
20
+ * structure's templates: the resolved style carries `var(--m-<bp>-<prop>)` values and the
21
+ * variable assignments land on the node under {@link TEMPLATE_VARS_KEY} — an EPHEMERAL,
22
+ * render-only field (never persisted, never validated). The client builders apply it via
23
+ * their element ref (like interactive-style variables); the SSR renderer folds it into the
24
+ * element's inline `style="…"`.
25
+ */
26
+
27
+ /**
28
+ * The CSS custom-property name bridging a `{{template}}`-bound declaration to its utility
29
+ * rule. MUST stay byte-identical to meno-astro's `templateVarName` (runtime/cssValue.ts) —
30
+ * the canvas and the real build render the same variable names so what you inspect in
31
+ * Fast Design Mode matches the published output.
32
+ */
33
+ export function templateVarName(breakpoint: string, cssProp: string): string {
34
+ const kebab = cssProp.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
35
+ return `--m-${breakpoint}-${kebab}`;
36
+ }
37
+
38
+ /** Ephemeral node field carrying the bridged variable assignments (render-only). */
39
+ export const TEMPLATE_VARS_KEY = '__templateVars';
40
+
41
+ /** Read the bridged `--m-<bp>-<prop>` assignments off a processed node, if any. */
42
+ export function getTemplateVars(node: unknown): Record<string, string> | undefined {
43
+ if (!node || typeof node !== 'object') return undefined;
44
+ const vars = (node as Record<string, unknown>)[TEMPLATE_VARS_KEY];
45
+ if (!vars || typeof vars !== 'object' || Array.isArray(vars)) return undefined;
46
+ const entries = Object.entries(vars as Record<string, unknown>);
47
+ if (entries.length === 0) return undefined;
48
+ return vars as Record<string, string>;
49
+ }
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Comments are Figma-style pins placed on components in the studio canvas.
5
5
  * One file per pin (thread embedded). Storage layout (status as top folder):
6
- * {projectRoot}/comments/<status>/<pageSlug>--<seq>--<titleSlug>.json
7
- * e.g. comments/open/blog__post--3--hero-is-too-dark.json
6
+ * {projectRoot}/comments/<status>/<pageSlug>--<seq>--<titleSlug>--<idFrag>.json
7
+ * e.g. comments/open/blog__post--3--hero-is-too-dark--550e8400.json
8
8
  *
9
9
  * Pins are an authoring-time concept — they live in studio only.
10
10
  */
@@ -119,7 +119,13 @@ export interface Comment {
119
119
  _filename: string;
120
120
  /** Page path the pin lives on (e.g. `"blog/post"`). */
121
121
  _pagePath: string;
122
- /** Stable per-page badge number. Server assigns at create time. */
122
+ /**
123
+ * Best-effort creation counter (server stamps `max+1` at create time), used
124
+ * as the human-scannable middle segment of the filename. NOT collision-proof
125
+ * under concurrent/offline creation and NOT the badge shown to users — the pin
126
+ * badge is derived client-side from the full set (see `assignDisplaySeq`), so a
127
+ * repeated `_seq` here is harmless.
128
+ */
123
129
  _seq: number;
124
130
  /** ISO timestamps. */
125
131
  _createdAt: string;