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.
- package/dist/chunks/{chunk-ZEDLSHYQ.js → chunk-GHNLTFCN.js} +44 -12
- package/dist/chunks/chunk-GHNLTFCN.js.map +7 -0
- package/dist/chunks/{chunk-UOF4MCAD.js → chunk-KX2LPIZZ.js} +607 -16
- package/dist/chunks/{chunk-UOF4MCAD.js.map → chunk-KX2LPIZZ.js.map} +3 -3
- package/dist/chunks/{chunk-FQBIC2OB.js → chunk-YMBUSHII.js} +1 -1
- package/dist/chunks/{chunk-FQBIC2OB.js.map → chunk-YMBUSHII.js.map} +1 -1
- package/dist/lib/client/index.js +56 -12
- package/dist/lib/client/index.js.map +2 -2
- package/dist/lib/server/index.js +121 -26
- package/dist/lib/server/index.js.map +3 -3
- package/dist/lib/shared/index.js +8 -2
- package/dist/lib/shared/index.js.map +1 -1
- package/lib/client/core/ComponentBuilder.test.ts +137 -0
- package/lib/client/core/ComponentBuilder.ts +52 -13
- package/lib/client/core/builders/embedBuilder.ts +15 -1
- package/lib/client/core/builders/linkNodeBuilder.ts +15 -1
- package/lib/client/core/builders/localeListBuilder.ts +15 -1
- package/lib/client/templateEngine.test.ts +106 -3
- package/lib/client/templateEngine.ts +50 -10
- package/lib/server/fileWatcher.test.ts +90 -0
- package/lib/server/fileWatcher.ts +36 -0
- package/lib/server/services/configService.ts +0 -5
- package/lib/server/ssr/htmlGenerator.test.ts +105 -3
- package/lib/server/ssr/htmlGenerator.ts +94 -42
- package/lib/server/ssr/ssrRenderer.test.ts +100 -0
- package/lib/server/ssr/ssrRenderer.ts +59 -14
- package/lib/shared/cssGeneration.test.ts +36 -0
- package/lib/shared/cssGeneration.ts +6 -1
- package/lib/shared/tailwindThemeScale.ts +1 -0
- package/lib/shared/templateStyleVars.ts +49 -0
- package/lib/shared/types/comment.ts +9 -3
- package/lib/shared/utilityClassConfig.ts +469 -10
- package/lib/shared/utilityClassMapper.test.ts +200 -2
- package/lib/shared/utilityClassMapper.ts +153 -0
- package/lib/shared/utilityClassNames.ts +90 -0
- package/package.json +1 -1
- 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
|
-
/**
|
|
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;
|