Skip to content

Commit 79f9141

Browse files
committed
feat: Implied style runtime support.
1 parent 50e84d1 commit 79f9141

File tree

4 files changed

+70
-15
lines changed

4 files changed

+70
-15
lines changed

Diff for: packages/@css-blocks/ember-app/runtime/app/services/css-blocks.ts

+62-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { ObjectDictionary } from "@opticss/util";
66

77
/// @ts-ignore
88
import { data as _data } from "./-css-blocks-data";
9-
import type { AggregateRewriteData, StyleExpression } from "./AggregateRewriteData";
9+
import type { AggregateRewriteData, StyleExpression, ImpliedStyles, ConditionalStyle } from "./AggregateRewriteData";
1010

1111
const data: AggregateRewriteData = _data;
1212

@@ -99,10 +99,9 @@ const enum FalsySwitchBehavior {
9999
export default class CSSBlocksService extends Service {
100100
classNamesFor(argv: Array<string | number | boolean | null>): string {
101101
let args = argv.slice();
102-
console.log(args);
103102
args.reverse(); // pop() is faster than shift()
104103
let rewriteVersion = num(args);
105-
if (rewriteVersion > 1) throw new Error(`The rewrite is newer than expected. Please upgrade @css-blocks/ember-app.`);
104+
if (rewriteVersion > 0) throw new Error(`The rewrite schema is newer than expected. Please upgrade @css-blocks/ember-app.`);
106105

107106
let numBlocks = num(args);
108107
// the values in blockStyleIndices map style strings to an index into the array
@@ -119,6 +118,7 @@ export default class CSSBlocksService extends Service {
119118
let sourceGuid = str(args);
120119
let runtimeGuid = str(args, true); // this won't be non-null until we implement block passing.
121120
let blockIndex = data.blockIds[sourceGuid];
121+
assert(blockIndex, `unknown block ${sourceGuid}`);
122122
let runtimeBlockIndex = runtimeGuid === null ? blockIndex : data.blockIds[runtimeGuid];
123123
let blockInfo = data.blocks[blockIndex];
124124
blockStyleIndices.push(blockInfo.blockInterfaceStyles);
@@ -182,7 +182,7 @@ export default class CSSBlocksService extends Service {
182182
let currentValue = str(args, true, true);
183183
let numValues = num(args);
184184
let found = false;
185-
let legal = new Array<string>();
185+
let legal: Array<String> = [];
186186
while (numValues--) {
187187
let v = str(args);
188188
legal.push(v);
@@ -214,38 +214,88 @@ export default class CSSBlocksService extends Service {
214214
stylesApplied.add(styles[i]!);
215215
}
216216
}
217-
// TODO: style inference
217+
218+
let aliasClassNames = applyImpliedStyles(stylesApplied, data.impliedStyles);
219+
218220
let classNameIndices = new Set<number>();
221+
// TODO: Only iterate over the subset of optimizations that might match this
222+
// element's styles.
219223
for (let [clsIdx, expr] of data.optimizations) {
220224
if (evaluateExpression(expr, stylesApplied)) {
221225
classNameIndices.add(clsIdx);
222226
}
223227
}
224-
let classNames = new Array<string>();
228+
let classNames = new Array<string>(...aliasClassNames);
225229
for (let idx of classNameIndices) {
226230
classNames.push(data.outputClassnames[idx]);
227231
}
228232
let result = classNames.join(" ");
229-
console.log(result);
230233
return result;
231234
}
232235
}
233236

234-
function evaluateExpression(expr: StyleExpression, stylesApplied: Set<number>): boolean {
235-
if (typeof expr === "number") return stylesApplied.has(expr);
237+
function evaluateExpression(expr: StyleExpression, stylesApplied: Set<number>, stylesApplied2?: Set<number>): boolean {
238+
if (typeof expr === "number") return (stylesApplied.has(expr) || (!!stylesApplied2 && stylesApplied2.has(expr)));
236239
if (expr[0] === Operator.AND) {
237240
for (let i = 1; i < expr.length; i++) {
238-
if (!evaluateExpression(expr[i], stylesApplied)) return false;
241+
if (!evaluateExpression(expr[i], stylesApplied, stylesApplied2)) return false;
239242
}
240243
return true;
241244
} else if (expr[0] === Operator.OR) {
242245
for (let i = 1; i < expr.length; i++) {
243-
if (evaluateExpression(expr[i], stylesApplied)) return true;
246+
if (evaluateExpression(expr[i], stylesApplied, stylesApplied2)) return true;
244247
}
245248
return false;
246249
} else if (expr[0] === Operator.NOT) {
247-
return !evaluateExpression(expr[1], stylesApplied);
250+
return !evaluateExpression(expr[1], stylesApplied, stylesApplied2);
248251
} else {
249252
return false;
250253
}
251254
}
255+
256+
function applyImpliedStyles(stylesApplied: Set<number>, impliedStyles: ImpliedStyles): Set<string> {
257+
console.log({impliedStyles});
258+
let aliases = new Set<string>();
259+
let newStyles = new Set(stylesApplied);
260+
let failedConditions = new Set<ConditionalStyle>();
261+
// for each new style we get the directly implied styles by each of them and
262+
// add them to the next iteration of new styles. if a conditionally applied
263+
// style doesn't match, it might be due to an implied style that isn't applied
264+
// yet, so we keep the failures around and try adding them during each
265+
// iteration once new styles are taken into account.
266+
while (newStyles.size > 0) {
267+
let nextStyles = new Set<number>();
268+
let newFailedConditions = new Set<ConditionalStyle>();
269+
for (let style of newStyles) {
270+
let implied = impliedStyles[style];
271+
if (!implied) continue;
272+
for (let i of implied) {
273+
if (typeof i === "number") {
274+
nextStyles.add(i);
275+
} else if (typeof i === "string") {
276+
aliases.add(i);
277+
} else {
278+
if (evaluateExpression(i.conditions, stylesApplied, newStyles)) {
279+
nextStyles.add(i.style);
280+
} else {
281+
newFailedConditions.add(i);
282+
}
283+
}
284+
}
285+
}
286+
for (let s of newStyles) {
287+
stylesApplied.add(s);
288+
}
289+
newStyles = nextStyles;
290+
for (let c of failedConditions) {
291+
if (evaluateExpression(c.conditions, stylesApplied, newStyles)) {
292+
newStyles.add(c.style);
293+
failedConditions.delete(c);
294+
}
295+
}
296+
for (let c of newFailedConditions) {
297+
failedConditions.add(c);
298+
}
299+
}
300+
return aliases;
301+
}

Diff for: packages/@css-blocks/ember-app/src/RuntimeDataGenerator.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ export class RuntimeDataGenerator {
124124
}
125125

126126
// implied by aliasing
127-
implied.push(...style.getStyleAliases());
127+
let aliases = [...style.getStyleAliases()];
128+
if (aliases.length > 0) {
129+
console.dir({aliases});
130+
}
131+
implied.push(...aliases);
128132

129133
// implied by composition
130134
if (isBlockClass(style)) {

Diff for: private-packages/fixtures-ember-v2/ember-addon/addon/styles/components/addon-component.block.css

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
:scope {
44
extends: bold;
5+
block-alias: public-addon-component-alias;
56
--addon-component-block-scope: applied;
67
color: red;
78
}

Diff for: private-packages/fixtures-ember-v2/ember-app/app/controllers/compositions.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import Controller from '@ember/controller';
22

33
export default Controller.extend({
44
enabled: false,
5-
color: 'unset',
5+
color: 'none',
66

77
actions: {
88
toggleEnabled() {
99
this.toggleProperty("enabled");
1010
},
1111
toggleColor() {
12-
this.set('color', this.get('color') === 'unset' ? 'yellow' : 'unset');
12+
this.set('color', this.get('color') === 'none' ? 'yellow' : 'none');
1313
}
1414
}
1515
});

0 commit comments

Comments
 (0)