@homebound/truss 2.1.0-next.1 → 2.1.0-next.3

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 CHANGED
@@ -1010,9 +1010,32 @@ type Opts<T> = {
1010
1010
  rules: T,
1011
1011
  enabled: boolean,
1012
1012
  important: boolean,
1013
- selector: string | undefined
1013
+ selector: string | undefined,
1014
+ elseApplied: boolean,
1014
1015
  };
1015
1016
 
1017
+ function invertMediaQuery(query: string): string {
1018
+ const screenPrefix = "@media screen and ";
1019
+ if (query.startsWith(screenPrefix)) {
1020
+ const conditions = query.slice(screenPrefix.length).trim();
1021
+ const rangeMatch = conditions.match(/^\(min-width: (\d+)px\) and \(max-width: (\d+)px\)$/);
1022
+ if (rangeMatch) {
1023
+ const min = Number(rangeMatch[1]);
1024
+ const max = Number(rangeMatch[2]);
1025
+ return \`@media screen and (max-width: \${min - 1}px), screen and (min-width: \${max + 1}px)\`;
1026
+ }
1027
+ const minMatch = conditions.match(/^\(min-width: (\d+)px\)$/);
1028
+ if (minMatch) {
1029
+ return \`@media screen and (max-width: \${Number(minMatch[1]) - 1}px)\`;
1030
+ }
1031
+ const maxMatch = conditions.match(/^\(max-width: (\d+)px\)$/);
1032
+ if (maxMatch) {
1033
+ return \`@media screen and (min-width: \${Number(maxMatch[1]) + 1}px)\`;
1034
+ }
1035
+ }
1036
+ return query.replace("@media", "@media not");
1037
+ }
1038
+
1016
1039
  class CssBuilder<T extends Properties> {
1017
1040
  constructor(private opts: Opts<T>) {}
1018
1041
 
@@ -1056,13 +1079,13 @@ class CssBuilder<T extends Properties> {
1056
1079
 
1057
1080
  get else() {
1058
1081
  if (this.selector !== undefined) {
1059
- if (this.selector.includes("not")) {
1082
+ if (this.opts.elseApplied) {
1060
1083
  throw new Error("else was already called");
1061
1084
  } else {
1062
- return this.newCss({ selector: this.selector.replace("@media", "@media not") });
1085
+ return this.newCss({ selector: invertMediaQuery(this.selector), elseApplied: true });
1063
1086
  }
1064
1087
  }
1065
- return this.newCss({ enabled: !this.enabled });
1088
+ return this.newCss({ enabled: !this.enabled, elseApplied: true });
1066
1089
  }
1067
1090
 
1068
1091
  get important() { return this.newCss({ important: true }); }
@@ -1139,7 +1162,7 @@ export enum Palette {
1139
1162
  export type Xss<P extends keyof Properties> = Pick<Properties, P>;
1140
1163
 
1141
1164
  /** An entry point for Css expressions. CssBuilder is immutable so this is safe to share. */
1142
- export const Css = new CssBuilder({ rules: {}, enabled: true, important: false, selector: undefined });
1165
+ export const Css = new CssBuilder({ rules: {}, enabled: true, important: false, selector: undefined, elseApplied: false });
1143
1166
 
1144
1167
  ${typeAliasCode}
1145
1168
 
@@ -1230,6 +1253,7 @@ type Opts<T> = {
1230
1253
  rules: T;
1231
1254
  enabled: boolean;
1232
1255
  selector: string | undefined;
1256
+ elseApplied: boolean;
1233
1257
  };
1234
1258
 
1235
1259
  class CssBuilder<T extends Properties> {
@@ -1311,13 +1335,22 @@ class CssBuilder<T extends Properties> {
1311
1335
  if(mediaQuery: string): CssBuilder<T>;
1312
1336
  if(condOrMediaQuery: boolean | string): CssBuilder<T> {
1313
1337
  if (typeof condOrMediaQuery === "boolean") {
1314
- return new CssBuilder({ ...this.opts, enabled: condOrMediaQuery });
1338
+ return new CssBuilder({ ...this.opts, enabled: condOrMediaQuery, elseApplied: false });
1315
1339
  }
1316
- return this.newCss({ selector: condOrMediaQuery });
1340
+ return this.newCss({ selector: condOrMediaQuery, elseApplied: false });
1317
1341
  }
1318
1342
 
1319
1343
  get else(): CssBuilder<T> {
1320
- return new CssBuilder({ ...this.opts, enabled: !this.enabled });
1344
+ if (this.selector !== undefined) {
1345
+ if (this.opts.elseApplied) {
1346
+ throw new Error("else was already called");
1347
+ }
1348
+ return this.newCss({ selector: invertMediaQuery(this.selector), elseApplied: true });
1349
+ }
1350
+ if (this.opts.elseApplied) {
1351
+ throw new Error("else was already called");
1352
+ }
1353
+ return new CssBuilder({ ...this.opts, enabled: !this.enabled, elseApplied: true });
1321
1354
  }
1322
1355
 
1323
1356
  add<P extends Properties>(props: P): CssBuilder<T & P>;
@@ -1376,12 +1409,35 @@ export enum Palette {
1376
1409
  export type Xss<P extends keyof Properties> = Pick<Properties, P>;
1377
1410
 
1378
1411
  /** An entry point for Css expressions. CssBuilder is immutable so this is safe to share. */
1379
- export const Css = new CssBuilder({ rules: {}, enabled: true, selector: undefined });
1412
+ export const Css = new CssBuilder({ rules: {}, enabled: true, selector: undefined, elseApplied: false });
1380
1413
 
1381
1414
  ${typeAliasCode}
1382
1415
 
1383
1416
  ${breakpointCode}
1384
1417
 
1418
+ function invertMediaQuery(query: string): string {
1419
+ const screenPrefix = "@media screen and ";
1420
+ if (query.startsWith(screenPrefix)) {
1421
+ const conditions = query.slice(screenPrefix.length).trim();
1422
+ const rangeMatch = conditions.match(/^\(min-width: (\d+)px\) and \(max-width: (\d+)px\)$/);
1423
+ if (rangeMatch) {
1424
+ const min = Number(rangeMatch[1]);
1425
+ const max = Number(rangeMatch[2]);
1426
+ return \`@media screen and (max-width: \${min - 1}px), screen and (min-width: \${max + 1}px)\`;
1427
+ }
1428
+ const minMatch = conditions.match(/^\(min-width: (\d+)px\)$/);
1429
+ if (minMatch) {
1430
+ return \`@media screen and (max-width: \${Number(minMatch[1]) - 1}px)\`;
1431
+ }
1432
+ const maxMatch = conditions.match(/^\(max-width: (\d+)px\)$/);
1433
+ if (maxMatch) {
1434
+ return \`@media screen and (min-width: \${Number(maxMatch[1]) + 1}px)\`;
1435
+ }
1436
+ }
1437
+ return query.replace("@media", "@media not");
1438
+ }
1439
+
1440
+
1385
1441
  ${extras || ""}
1386
1442
  `;
1387
1443
  }