@homebound/truss 2.1.0-next.1 → 2.1.0-next.2
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/build/index.js +65 -9
- package/build/index.js.map +1 -1
- package/build/plugin/index.js +145 -48
- package/build/plugin/index.js.map +1 -1
- package/package.json +1 -1
package/build/plugin/index.js
CHANGED
|
@@ -165,16 +165,32 @@ function collectVariableRules(rules, seg, mapping) {
|
|
|
165
165
|
for (const prop of seg.variableProps) {
|
|
166
166
|
const className = prefix ? `${prefix}${baseKey}_var` : `${baseKey}_var`;
|
|
167
167
|
const varName = toCssVariableName(className, baseKey, prop);
|
|
168
|
-
|
|
168
|
+
const declaration = { cssProperty: camelToKebab(prop), cssValue: `var(${varName})`, cssVarName: varName };
|
|
169
|
+
const existingRule = rules.get(className);
|
|
170
|
+
if (!existingRule) {
|
|
169
171
|
rules.set(className, {
|
|
170
172
|
className,
|
|
171
|
-
cssProperty:
|
|
172
|
-
cssValue:
|
|
173
|
+
cssProperty: declaration.cssProperty,
|
|
174
|
+
cssValue: declaration.cssValue,
|
|
175
|
+
declarations: [declaration],
|
|
173
176
|
pseudoClass: seg.pseudoClass ?? void 0,
|
|
174
177
|
mediaQuery: seg.mediaQuery ?? void 0,
|
|
175
178
|
pseudoElement: seg.pseudoElement ?? void 0,
|
|
176
179
|
cssVarName: varName
|
|
177
180
|
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
existingRule.declarations ??= [
|
|
184
|
+
{
|
|
185
|
+
cssProperty: existingRule.cssProperty,
|
|
186
|
+
cssValue: existingRule.cssValue,
|
|
187
|
+
cssVarName: existingRule.cssVarName
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
if (!existingRule.declarations.some(function(entry) {
|
|
191
|
+
return entry.cssProperty === declaration.cssProperty;
|
|
192
|
+
})) {
|
|
193
|
+
existingRule.declarations.push(declaration);
|
|
178
194
|
}
|
|
179
195
|
}
|
|
180
196
|
if (seg.variableExtraDefs) {
|
|
@@ -227,11 +243,14 @@ function collectWhenVariableRules(rules, seg, mapping) {
|
|
|
227
243
|
for (const prop of seg.variableProps) {
|
|
228
244
|
const className = `${prefix}${baseKey}_var`;
|
|
229
245
|
const varName = toCssVariableName(className, baseKey, prop);
|
|
230
|
-
|
|
246
|
+
const declaration = { cssProperty: camelToKebab(prop), cssValue: `var(${varName})`, cssVarName: varName };
|
|
247
|
+
const existingRule = rules.get(className);
|
|
248
|
+
if (!existingRule) {
|
|
231
249
|
rules.set(className, {
|
|
232
250
|
className,
|
|
233
|
-
cssProperty:
|
|
234
|
-
cssValue:
|
|
251
|
+
cssProperty: declaration.cssProperty,
|
|
252
|
+
cssValue: declaration.cssValue,
|
|
253
|
+
declarations: [declaration],
|
|
235
254
|
cssVarName: varName,
|
|
236
255
|
whenSelector: {
|
|
237
256
|
relationship: wp.relationship ?? "ancestor",
|
|
@@ -239,6 +258,19 @@ function collectWhenVariableRules(rules, seg, mapping) {
|
|
|
239
258
|
pseudo: wp.pseudo
|
|
240
259
|
}
|
|
241
260
|
});
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
existingRule.declarations ??= [
|
|
264
|
+
{
|
|
265
|
+
cssProperty: existingRule.cssProperty,
|
|
266
|
+
cssValue: existingRule.cssValue,
|
|
267
|
+
cssVarName: existingRule.cssVarName
|
|
268
|
+
}
|
|
269
|
+
];
|
|
270
|
+
if (!existingRule.declarations.some(function(entry) {
|
|
271
|
+
return entry.cssProperty === declaration.cssProperty;
|
|
272
|
+
})) {
|
|
273
|
+
existingRule.declarations.push(declaration);
|
|
242
274
|
}
|
|
243
275
|
}
|
|
244
276
|
if (seg.variableExtraDefs) {
|
|
@@ -351,30 +383,26 @@ function generateCssText(rules) {
|
|
|
351
383
|
lines.push(formatMediaPseudoElementRule(rule));
|
|
352
384
|
}
|
|
353
385
|
for (const rule of allRules) {
|
|
354
|
-
|
|
355
|
-
|
|
386
|
+
for (const declaration of getRuleDeclarations(rule)) {
|
|
387
|
+
if (declaration.cssVarName) {
|
|
388
|
+
lines.push(`@property ${declaration.cssVarName} {
|
|
356
389
|
syntax: "*";
|
|
357
390
|
inherits: false;
|
|
358
391
|
}`);
|
|
392
|
+
}
|
|
359
393
|
}
|
|
360
394
|
}
|
|
361
395
|
return lines.join("\n");
|
|
362
396
|
}
|
|
363
397
|
function formatBaseRule(rule) {
|
|
364
|
-
return `.${rule.className}
|
|
365
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
366
|
-
}`;
|
|
398
|
+
return formatRuleBlock(`.${rule.className}`, rule);
|
|
367
399
|
}
|
|
368
400
|
function formatPseudoRule(rule) {
|
|
369
401
|
const pe = rule.pseudoElement ? rule.pseudoElement : "";
|
|
370
|
-
return `.${rule.className}${rule.pseudoClass}${pe}
|
|
371
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
372
|
-
}`;
|
|
402
|
+
return formatRuleBlock(`.${rule.className}${rule.pseudoClass}${pe}`, rule);
|
|
373
403
|
}
|
|
374
404
|
function formatPseudoElementRule(rule) {
|
|
375
|
-
return `.${rule.className}${rule.pseudoElement}
|
|
376
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
377
|
-
}`;
|
|
405
|
+
return formatRuleBlock(`.${rule.className}${rule.pseudoElement}`, rule);
|
|
378
406
|
}
|
|
379
407
|
function formatWhenRule(rule) {
|
|
380
408
|
const whenSelector = rule.whenSelector;
|
|
@@ -384,53 +412,50 @@ function formatWhenRule(rule) {
|
|
|
384
412
|
const markerSelector = `.${whenSelector.markerClass}${whenSelector.pseudo}`;
|
|
385
413
|
const targetSelector = `.${rule.className}`;
|
|
386
414
|
if (whenSelector.relationship === "ancestor") {
|
|
387
|
-
return `${markerSelector} ${targetSelector}
|
|
388
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
389
|
-
}`;
|
|
415
|
+
return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
|
|
390
416
|
}
|
|
391
417
|
if (whenSelector.relationship === "descendant") {
|
|
392
|
-
return `${targetSelector}:has(${markerSelector})
|
|
393
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
394
|
-
}`;
|
|
418
|
+
return formatRuleBlock(`${targetSelector}:has(${markerSelector})`, rule);
|
|
395
419
|
}
|
|
396
420
|
if (whenSelector.relationship === "siblingAfter") {
|
|
397
|
-
return `${targetSelector}:has(~ ${markerSelector})
|
|
398
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
399
|
-
}`;
|
|
421
|
+
return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector})`, rule);
|
|
400
422
|
}
|
|
401
423
|
if (whenSelector.relationship === "siblingBefore") {
|
|
402
|
-
return `${markerSelector} ~ ${targetSelector}
|
|
403
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
404
|
-
}`;
|
|
424
|
+
return formatRuleBlock(`${markerSelector} ~ ${targetSelector}`, rule);
|
|
405
425
|
}
|
|
406
426
|
if (whenSelector.relationship === "anySibling") {
|
|
407
|
-
return `${targetSelector}:has(~ ${markerSelector}), ${markerSelector} ~ ${targetSelector}
|
|
408
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
409
|
-
}`;
|
|
427
|
+
return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector}), ${markerSelector} ~ ${targetSelector}`, rule);
|
|
410
428
|
}
|
|
411
|
-
return `${markerSelector} ${targetSelector}
|
|
412
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
413
|
-
}`;
|
|
429
|
+
return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
|
|
414
430
|
}
|
|
415
431
|
function formatMediaRule(rule) {
|
|
416
|
-
return
|
|
417
|
-
.${rule.className}.${rule.className} {
|
|
418
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
419
|
-
}
|
|
420
|
-
}`;
|
|
432
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}`, rule);
|
|
421
433
|
}
|
|
422
434
|
function formatMediaPseudoRule(rule) {
|
|
423
|
-
return
|
|
424
|
-
.${rule.className}.${rule.className}${rule.pseudoClass} {
|
|
425
|
-
${rule.cssProperty}: ${rule.cssValue};
|
|
426
|
-
}
|
|
427
|
-
}`;
|
|
435
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${rule.pseudoClass}`, rule);
|
|
428
436
|
}
|
|
429
437
|
function formatMediaPseudoElementRule(rule) {
|
|
430
438
|
const pe = rule.pseudoElement ?? "";
|
|
431
|
-
return
|
|
432
|
-
|
|
433
|
-
|
|
439
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${pe}`, rule);
|
|
440
|
+
}
|
|
441
|
+
function getRuleDeclarations(rule) {
|
|
442
|
+
return rule.declarations ?? [{ cssProperty: rule.cssProperty, cssValue: rule.cssValue, cssVarName: rule.cssVarName }];
|
|
443
|
+
}
|
|
444
|
+
function formatRuleBlock(selector, rule) {
|
|
445
|
+
const body = getRuleDeclarations(rule).map(function(declaration) {
|
|
446
|
+
return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
|
|
447
|
+
}).join("\n");
|
|
448
|
+
return `${selector} {
|
|
449
|
+
${body}
|
|
450
|
+
}`;
|
|
451
|
+
}
|
|
452
|
+
function formatNestedRuleBlock(wrapper, selector, rule) {
|
|
453
|
+
const body = getRuleDeclarations(rule).map(function(declaration) {
|
|
454
|
+
return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
|
|
455
|
+
}).join("\n");
|
|
456
|
+
return `${wrapper} {
|
|
457
|
+
${selector} {
|
|
458
|
+
${body}
|
|
434
459
|
}
|
|
435
460
|
}`;
|
|
436
461
|
}
|
|
@@ -573,6 +598,31 @@ function resolveFullChain(chain, mapping, options) {
|
|
|
573
598
|
let currentNodes = [];
|
|
574
599
|
while (i < filteredChain.length) {
|
|
575
600
|
const node = filteredChain[i];
|
|
601
|
+
const mediaStart = getMediaConditionalStartNode(node, mapping);
|
|
602
|
+
if (mediaStart) {
|
|
603
|
+
const elseIndex = findElseIndex(filteredChain, i + 1);
|
|
604
|
+
if (elseIndex !== -1) {
|
|
605
|
+
if (currentNodes.length > 0) {
|
|
606
|
+
const unconditionalSegs = resolveChain(currentNodes, mapping);
|
|
607
|
+
parts.push({
|
|
608
|
+
type: "unconditional",
|
|
609
|
+
segments: options?.skipMerge ? unconditionalSegs : mergeOverlappingConditions(unconditionalSegs)
|
|
610
|
+
});
|
|
611
|
+
currentNodes = [];
|
|
612
|
+
}
|
|
613
|
+
const thenNodes = mediaStart.thenNodes ? [...mediaStart.thenNodes, ...filteredChain.slice(i + 1, elseIndex)] : filteredChain.slice(i, elseIndex);
|
|
614
|
+
const elseNodes = [makeMediaQueryNode(mediaStart.inverseMediaQuery), ...filteredChain.slice(elseIndex + 1)];
|
|
615
|
+
const thenSegs = resolveChain(thenNodes, mapping);
|
|
616
|
+
const elseSegs = resolveChain(elseNodes, mapping);
|
|
617
|
+
const combinedSegs = [...thenSegs, ...elseSegs];
|
|
618
|
+
parts.push({
|
|
619
|
+
type: "unconditional",
|
|
620
|
+
segments: options?.skipMerge ? combinedSegs : mergeOverlappingConditions(combinedSegs)
|
|
621
|
+
});
|
|
622
|
+
i = filteredChain.length;
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
576
626
|
if (node.type === "if") {
|
|
577
627
|
if (node.conditionNode.type === "StringLiteral") {
|
|
578
628
|
const mediaQuery = node.conditionNode.value;
|
|
@@ -639,6 +689,53 @@ function resolveFullChain(chain, mapping, options) {
|
|
|
639
689
|
}
|
|
640
690
|
return { parts, markers, errors: [...scanErrors, ...segmentErrors] };
|
|
641
691
|
}
|
|
692
|
+
function getMediaConditionalStartNode(node, mapping) {
|
|
693
|
+
if (node.type === "if" && node.conditionNode.type === "StringLiteral") {
|
|
694
|
+
return {
|
|
695
|
+
inverseMediaQuery: invertMediaQuery(node.conditionNode.value),
|
|
696
|
+
thenNodes: [makeMediaQueryNode(node.conditionNode.value)]
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
if (node.type === "getter" && mapping.breakpoints && node.name in mapping.breakpoints) {
|
|
700
|
+
return { inverseMediaQuery: invertMediaQuery(mapping.breakpoints[node.name]) };
|
|
701
|
+
}
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
function findElseIndex(chain, start) {
|
|
705
|
+
for (let i = start; i < chain.length; i++) {
|
|
706
|
+
if (chain[i].type === "if") {
|
|
707
|
+
return -1;
|
|
708
|
+
}
|
|
709
|
+
if (chain[i].type === "else") {
|
|
710
|
+
return i;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return -1;
|
|
714
|
+
}
|
|
715
|
+
function makeMediaQueryNode(mediaQuery) {
|
|
716
|
+
return { type: "__mediaQuery", mediaQuery };
|
|
717
|
+
}
|
|
718
|
+
function invertMediaQuery(query) {
|
|
719
|
+
const screenPrefix = "@media screen and ";
|
|
720
|
+
if (query.startsWith(screenPrefix)) {
|
|
721
|
+
const conditions = query.slice(screenPrefix.length).trim();
|
|
722
|
+
const rangeMatch = conditions.match(/^\(min-width: (\d+)px\) and \(max-width: (\d+)px\)$/);
|
|
723
|
+
if (rangeMatch) {
|
|
724
|
+
const min = Number(rangeMatch[1]);
|
|
725
|
+
const max = Number(rangeMatch[2]);
|
|
726
|
+
return `@media screen and (max-width: ${min - 1}px), screen and (min-width: ${max + 1}px)`;
|
|
727
|
+
}
|
|
728
|
+
const minMatch = conditions.match(/^\(min-width: (\d+)px\)$/);
|
|
729
|
+
if (minMatch) {
|
|
730
|
+
return `@media screen and (max-width: ${Number(minMatch[1]) - 1}px)`;
|
|
731
|
+
}
|
|
732
|
+
const maxMatch = conditions.match(/^\(max-width: (\d+)px\)$/);
|
|
733
|
+
if (maxMatch) {
|
|
734
|
+
return `@media screen and (min-width: ${Number(maxMatch[1]) + 1}px)`;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return query.replace("@media", "@media not");
|
|
738
|
+
}
|
|
642
739
|
function resolveChain(chain, mapping) {
|
|
643
740
|
const segments = [];
|
|
644
741
|
let currentMediaQuery = null;
|