@webstudio-is/css-data 0.267.0 → 0.269.0

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/lib/index.js CHANGED
@@ -310,6 +310,26 @@ var html = /* @__PURE__ */ new Map([
310
310
  ["button:background-color", { type: "keyword", value: "lightgray" }]
311
311
  ]);
312
312
 
313
+ // src/html-elements.ts
314
+ var htmlReplacedElementTags = [
315
+ "audio",
316
+ "canvas",
317
+ "embed",
318
+ "iframe",
319
+ "img",
320
+ "input",
321
+ "object",
322
+ "select",
323
+ "textarea",
324
+ "video"
325
+ ];
326
+ var htmlReplacedElementTagSet = new Set(htmlReplacedElementTags);
327
+ var isHtmlReplacedElementTag = (tag) => {
328
+ return htmlReplacedElementTagSet.has(
329
+ tag
330
+ );
331
+ };
332
+
313
333
  // src/__generated__/keyword-values.ts
314
334
  var keywordValues = {
315
335
  "-webkit-font-smoothing": [
@@ -10376,10 +10396,13 @@ import * as csstree2 from "css-tree";
10376
10396
 
10377
10397
  // src/parse-css-value.ts
10378
10398
  import {
10399
+ definitionSyntax,
10379
10400
  generate,
10380
10401
  lexer,
10381
10402
  List,
10382
10403
  parse,
10404
+ tokenize,
10405
+ tokenTypes,
10383
10406
  walk
10384
10407
  } from "css-tree";
10385
10408
  import warnOnce from "warn-once";
@@ -10408,9 +10431,156 @@ var splitRepeated = (nodes) => {
10408
10431
  }
10409
10432
  return lists;
10410
10433
  };
10434
+ var cssNumericFunctionNames = /* @__PURE__ */ new Set([
10435
+ "calc",
10436
+ "min",
10437
+ "max",
10438
+ "clamp",
10439
+ "round",
10440
+ "mod",
10441
+ "rem",
10442
+ "sin",
10443
+ "cos",
10444
+ "tan",
10445
+ "asin",
10446
+ "acos",
10447
+ "atan",
10448
+ "atan2",
10449
+ "pow",
10450
+ "sqrt",
10451
+ "hypot",
10452
+ "log",
10453
+ "exp",
10454
+ "abs",
10455
+ "sign"
10456
+ ]);
10457
+ var cssMathConstants = /* @__PURE__ */ new Set(["e", "pi", "infinity", "-infinity", "nan"]);
10458
+ var cssNumericTypeNames = /* @__PURE__ */ new Set([
10459
+ "length",
10460
+ "length-percentage",
10461
+ "percentage",
10462
+ "number",
10463
+ "integer",
10464
+ "angle",
10465
+ "time",
10466
+ "frequency",
10467
+ "resolution",
10468
+ "flex",
10469
+ "alpha-value"
10470
+ ]);
10471
+ var canFallbackToCssMath = (ast, syntax) => {
10472
+ if (syntax === void 0) {
10473
+ return false;
10474
+ }
10475
+ let hasCssNumericType = false;
10476
+ try {
10477
+ definitionSyntax.walk(definitionSyntax.parse(syntax), (node) => {
10478
+ if (node.type === "Type" && "name" in node && cssNumericTypeNames.has(node.name)) {
10479
+ hasCssNumericType = true;
10480
+ }
10481
+ });
10482
+ } catch {
10483
+ return false;
10484
+ }
10485
+ if (hasCssNumericType === false) {
10486
+ return false;
10487
+ }
10488
+ let hasCssNumericFunction = false;
10489
+ let hasUnknownIdentifier = false;
10490
+ walk(ast, (node) => {
10491
+ if (node.type === "Function" && cssNumericFunctionNames.has(node.name)) {
10492
+ hasCssNumericFunction = true;
10493
+ }
10494
+ if (node.type === "Identifier" && cssMathConstants.has(node.name.toLowerCase()) === false) {
10495
+ hasUnknownIdentifier = true;
10496
+ }
10497
+ });
10498
+ return hasCssNumericFunction && hasUnknownIdentifier === false;
10499
+ };
10500
+ var getSyntaxMatchErrorSyntax = (error) => {
10501
+ if (error != null && "syntax" in error && typeof error.syntax === "string") {
10502
+ return error.syntax;
10503
+ }
10504
+ };
10505
+ var matchingOpenToken = /* @__PURE__ */ new Map([
10506
+ [tokenTypes.RightSquareBracket, tokenTypes.LeftSquareBracket],
10507
+ [tokenTypes.RightCurlyBracket, tokenTypes.LeftCurlyBracket]
10508
+ ]);
10509
+ var endsWithUnescaped = (value, char) => {
10510
+ if (value.endsWith(char) === false) {
10511
+ return false;
10512
+ }
10513
+ let backslashes = 0;
10514
+ for (let index = value.length - 2; index >= 0; index -= 1) {
10515
+ if (value[index] !== "\\") {
10516
+ break;
10517
+ }
10518
+ backslashes += 1;
10519
+ }
10520
+ return backslashes % 2 === 0;
10521
+ };
10522
+ var isValidCustomPropertyValue = (value) => {
10523
+ if (endsWithUnescaped(value, "\\")) {
10524
+ return false;
10525
+ }
10526
+ const blockStack = [];
10527
+ const tokenizeValue = tokenize;
10528
+ tokenizeValue(value, (type, start, end) => {
10529
+ const tokenValue = value.slice(start, end);
10530
+ if (type === tokenTypes.BadString || type === tokenTypes.BadUrl) {
10531
+ blockStack.push(Number.NaN);
10532
+ return;
10533
+ }
10534
+ if (type === tokenTypes.String) {
10535
+ const quote = tokenValue[0];
10536
+ if (quote !== void 0 && (quote === `"` || quote === `'`) && (tokenValue.length < 2 || endsWithUnescaped(tokenValue, quote) === false)) {
10537
+ blockStack.push(Number.NaN);
10538
+ }
10539
+ return;
10540
+ }
10541
+ if (type === tokenTypes.Url) {
10542
+ if (endsWithUnescaped(tokenValue, ")") === false) {
10543
+ blockStack.push(Number.NaN);
10544
+ }
10545
+ return;
10546
+ }
10547
+ if (type === tokenTypes.Comment) {
10548
+ if (tokenValue.endsWith("*/") === false) {
10549
+ blockStack.push(Number.NaN);
10550
+ }
10551
+ return;
10552
+ }
10553
+ if (type === tokenTypes.Function || type === tokenTypes.LeftParenthesis || type === tokenTypes.LeftSquareBracket || type === tokenTypes.LeftCurlyBracket) {
10554
+ blockStack.push(type);
10555
+ return;
10556
+ }
10557
+ if (type === tokenTypes.RightParenthesis) {
10558
+ const open = blockStack.at(-1);
10559
+ if (open !== tokenTypes.LeftParenthesis && open !== tokenTypes.Function) {
10560
+ blockStack.push(Number.NaN);
10561
+ return;
10562
+ }
10563
+ blockStack.pop();
10564
+ return;
10565
+ }
10566
+ const expectedOpen = matchingOpenToken.get(type);
10567
+ if (expectedOpen !== void 0) {
10568
+ if (blockStack.at(-1) !== expectedOpen) {
10569
+ blockStack.push(Number.NaN);
10570
+ return;
10571
+ }
10572
+ blockStack.pop();
10573
+ return;
10574
+ }
10575
+ if (type === tokenTypes.Semicolon && blockStack.length === 0) {
10576
+ blockStack.push(Number.NaN);
10577
+ }
10578
+ });
10579
+ return blockStack.length === 0;
10580
+ };
10411
10581
  var isValidDeclaration = (property, value) => {
10412
10582
  if (property.startsWith("--")) {
10413
- return true;
10583
+ return isValidCustomPropertyValue(value);
10414
10584
  }
10415
10585
  const ast = cssTryParseValue(value);
10416
10586
  if (ast != null) {
@@ -10429,6 +10599,9 @@ var isValidDeclaration = (property, value) => {
10429
10599
  if (property === "white-space-collapse" || property === "text-wrap-mode" || property === "text-wrap-style") {
10430
10600
  return keywordValues[property].includes(value);
10431
10601
  }
10602
+ if (typeof CSS !== "undefined" && CSS.supports(property, value)) {
10603
+ return true;
10604
+ }
10432
10605
  if (typeof CSSStyleValue !== "undefined") {
10433
10606
  try {
10434
10607
  CSSStyleValue.parse(property, value);
@@ -10449,6 +10622,9 @@ var isValidDeclaration = (property, value) => {
10449
10622
  if (matchResult.error?.message.includes("Unknown property")) {
10450
10623
  return true;
10451
10624
  }
10625
+ if (matchResult.matched == null && canFallbackToCssMath(ast, getSyntaxMatchErrorSyntax(matchResult.error))) {
10626
+ return true;
10627
+ }
10452
10628
  return matchResult.matched != null;
10453
10629
  };
10454
10630
  var repeatedProps = /* @__PURE__ */ new Set([
@@ -12918,6 +13094,9 @@ var camelCaseProperty = (property) => {
12918
13094
  return camelCase(property);
12919
13095
  };
12920
13096
  var parseCssValue2 = (property, value) => {
13097
+ if (property.startsWith("--")) {
13098
+ return /* @__PURE__ */ new Map([[property, parseCssValue(property, value)]]);
13099
+ }
12921
13100
  const expanded = new Map(expandShorthands([[property, value]]));
12922
13101
  const final = /* @__PURE__ */ new Map();
12923
13102
  for (const [property2, value2] of expanded) {
@@ -13290,12 +13469,29 @@ var substituteVarsInShorthand = (property, value, customProperties, cssVars) =>
13290
13469
  };
13291
13470
  var cssTreeTryParse = (input) => {
13292
13471
  try {
13293
- const ast = csstree6.parse(input);
13472
+ const ast = csstree6.parse(input, { positions: true });
13294
13473
  return ast;
13295
13474
  } catch {
13296
13475
  return;
13297
13476
  }
13298
13477
  };
13478
+ var getRawDeclarationValue = (css, declaration) => {
13479
+ const loc = declaration.value.loc;
13480
+ if (loc === null) {
13481
+ return;
13482
+ }
13483
+ return css.slice(loc.start.offset, loc.end.offset).trim();
13484
+ };
13485
+ var normalizeCustomPropertyValue = (value) => {
13486
+ if (value === "") {
13487
+ return value;
13488
+ }
13489
+ try {
13490
+ return csstree6.generate(csstree6.parse(value, { context: "value" }));
13491
+ } catch {
13492
+ return value;
13493
+ }
13494
+ };
13299
13495
  var extractCssCustomProperties = (css) => {
13300
13496
  const map = /* @__PURE__ */ new Map();
13301
13497
  const ast = cssTreeTryParse(css);
@@ -13308,7 +13504,10 @@ var extractCssCustomProperties = (css) => {
13308
13504
  const decl = node;
13309
13505
  const prop = normalizeProperty(decl.property);
13310
13506
  if (prop.startsWith("--")) {
13311
- map.set(prop, csstree6.generate(decl.value));
13507
+ const value = getRawDeclarationValue(css, decl);
13508
+ if (value !== void 0 && isValidCustomPropertyValue(value)) {
13509
+ map.set(prop, normalizeCustomPropertyValue(value));
13510
+ }
13312
13511
  }
13313
13512
  }
13314
13513
  });
@@ -13332,7 +13531,10 @@ var parseCss = (css, cssVars) => {
13332
13531
  const decl = node;
13333
13532
  const prop = normalizeProperty(decl.property);
13334
13533
  if (prop.startsWith("--")) {
13335
- customProperties.set(prop, csstree6.generate(decl.value));
13534
+ const value = getRawDeclarationValue(css, decl);
13535
+ if (value !== void 0 && isValidCustomPropertyValue(value)) {
13536
+ customProperties.set(prop, normalizeCustomPropertyValue(value));
13537
+ }
13336
13538
  }
13337
13539
  }
13338
13540
  });
@@ -13463,8 +13665,9 @@ var parseCss = (css, cssVars) => {
13463
13665
  selector = void 0;
13464
13666
  }
13465
13667
  }
13466
- const stringValue = csstree6.generate(node.value);
13467
13668
  const property = normalizeProperty(node.property);
13669
+ const rawValue = getRawDeclarationValue(css, node);
13670
+ const stringValue = property.startsWith("--") && rawValue !== void 0 ? isValidCustomPropertyValue(rawValue) ? normalizeCustomPropertyValue(rawValue) : rawValue : csstree6.generate(node.value).trim();
13468
13671
  let parsedCss;
13469
13672
  if (shorthandSet.has(property)) {
13470
13673
  const substituted = substituteVarsInShorthand(
@@ -13486,6 +13689,12 @@ var parseCss = (css, cssVars) => {
13486
13689
  } else {
13487
13690
  parsedCss = parseCssValue2(property, stringValue);
13488
13691
  }
13692
+ if (property.startsWith("--") && [...parsedCss.values()].some((value) => value.type === "invalid")) {
13693
+ errors.push(
13694
+ `"${property}" was not applied because its value is invalid`
13695
+ );
13696
+ return;
13697
+ }
13489
13698
  for (const { name: selector, state } of selectors) {
13490
13699
  for (const [prop, value] of parsedCss) {
13491
13700
  const normalizedProperty = normalizeProperty(prop);
@@ -17506,9 +17715,12 @@ export {
17506
17715
  getGridAxisLabel,
17507
17716
  getGridAxisMode,
17508
17717
  html,
17718
+ htmlReplacedElementTags,
17509
17719
  isEditableGridMode,
17720
+ isHtmlReplacedElementTag,
17510
17721
  isImplicitGridMode,
17511
17722
  isPseudoElement,
17723
+ isValidCustomPropertyValue,
17512
17724
  isValidDeclaration,
17513
17725
  keywordValues,
17514
17726
  parseClassBasedSelector,
@@ -0,0 +1,9 @@
1
+ /**
2
+ * HTML elements whose rendering is replaced by external content or a
3
+ * browser-provided widget.
4
+ *
5
+ * This is useful for CSS rules that distinguish regular inline boxes from
6
+ * replaced inline boxes.
7
+ */
8
+ export declare const htmlReplacedElementTags: readonly ["audio", "canvas", "embed", "iframe", "img", "input", "object", "select", "textarea", "video"];
9
+ export declare const isHtmlReplacedElementTag: (tag: string) => tag is (typeof htmlReplacedElementTags)[number];
@@ -1,5 +1,6 @@
1
1
  import type {} from "./css-tree";
2
2
  export { html } from "./__generated__/html";
3
+ export * from "./html-elements";
3
4
  export * from "./__generated__/keyword-values";
4
5
  export * from "./__generated__/units";
5
6
  export { properties as propertyDescriptions, declarations as declarationDescriptions, propertySyntaxesGenerated as propertySyntaxes, } from "./__generated__/property-value-descriptions";
@@ -1,6 +1,7 @@
1
1
  import { type CssNode, type FunctionNode } from "css-tree";
2
2
  import { type ColorValue, type StyleValue, type VarValue, type CssProperty } from "@webstudio-is/css-engine";
3
3
  export declare const cssTryParseValue: (input: string) => undefined | CssNode;
4
+ export declare const isValidCustomPropertyValue: (value: string) => boolean;
4
5
  export declare const isValidDeclaration: (property: CssProperty, value: string) => boolean;
5
6
  export declare const parseColor: (colorString: string) => undefined | ColorValue;
6
7
  export declare const parseCssVar: (node: FunctionNode) => undefined | VarValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webstudio-is/css-data",
3
- "version": "0.267.0",
3
+ "version": "0.269.0",
4
4
  "description": "CSS Data",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -36,7 +36,7 @@
36
36
  "change-case": "^5.4.4",
37
37
  "css-tree": "^3.1.0",
38
38
  "warn-once": "^0.1.1",
39
- "@webstudio-is/css-engine": "0.267.0"
39
+ "@webstudio-is/css-engine": "0.269.0"
40
40
  },
41
41
  "scripts": {
42
42
  "typecheck": "tsgo --noEmit",