@foldkit/ui 0.146.0 → 0.148.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.
@@ -1,19 +1,23 @@
1
1
  /**
2
2
  * Builds a CSS id selector from an element's id value.
3
3
  *
4
- * The id is escaped with `CSS.escape` so values that are not valid CSS
5
- * identifiers on their own (most notably ids beginning with a digit, as
6
- * produced by UUID-prefixed ids) still yield a usable selector.
4
+ * The id is escaped per the `CSS.escape` algorithm so values that are not
5
+ * valid CSS identifiers on their own (most notably ids beginning with a
6
+ * digit, as produced by UUID-prefixed ids) still yield a usable selector.
7
+ * The escape is implemented locally rather than via the `CSS` browser
8
+ * global so views that build selectors also render under Node.
7
9
  */
8
10
  export declare const idSelector: (id: string) => string;
9
11
  /**
10
12
  * Builds a CSS attribute selector matching `attribute` against `value`.
11
13
  *
12
- * The value is quoted and escaped with `CSS.escape`, so values carrying
13
- * brackets, backslashes, spaces, or a leading digit still yield a usable
14
- * selector. The quotes are load bearing: an escaped value is a valid CSS
15
- * identifier but not a valid unquoted attribute value, so dropping them makes
16
- * selectors for digit-leading ids fail to parse.
14
+ * The value is quoted and escaped per the `CSS.escape` algorithm, so values
15
+ * carrying brackets, backslashes, spaces, or a leading digit still yield a
16
+ * usable selector. The quotes are load bearing: an escaped value is a valid
17
+ * CSS identifier but not a valid unquoted attribute value, so dropping them
18
+ * makes selectors for digit-leading ids fail to parse. The escape is the
19
+ * same local implementation `idSelector` uses, so attribute selectors also
20
+ * build under Node during server rendering.
17
21
  */
18
22
  export declare const attributeSelector: (attribute: string, value: string) => string;
19
23
  //# sourceMappingURL=selectors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/internal/selectors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,KAAG,MAA8B,CAAA;AAEtE;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,KAAG,MAC5B,CAAA"}
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/internal/selectors.ts"],"names":[],"mappings":"AAsDA;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,KAAG,MAAuC,CAAA;AAE/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,KAAG,MACnB,CAAA"}
@@ -1,19 +1,73 @@
1
1
  import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ const NULL_CHARACTER_CODE = 0;
3
+ const REPLACEMENT_CHARACTER = '�';
4
+ const DELETE_CHARACTER_CODE = 0x7f;
5
+ const MAX_CONTROL_CHARACTER_CODE = 0x1f;
6
+ const DIGIT_ZERO_CODE = 0x30;
7
+ const DIGIT_NINE_CODE = 0x39;
8
+ const HYPHEN_CODE = 0x2d;
9
+ const UNDERSCORE_CODE = 0x5f;
10
+ const UPPERCASE_A_CODE = 0x41;
11
+ const UPPERCASE_Z_CODE = 0x5a;
12
+ const LOWERCASE_A_CODE = 0x61;
13
+ const LOWERCASE_Z_CODE = 0x7a;
14
+ const FIRST_NON_ASCII_CODE = 0x80;
15
+ const isDigitCode = (code) => __foldkitBrandViewResult((code >= DIGIT_ZERO_CODE && code <= DIGIT_NINE_CODE), "@foldkit/ui/internal/selectors.js#isDigitCode");
16
+ const isIdentifierCode = (code) => __foldkitBrandViewResult((code >= FIRST_NON_ASCII_CODE ||
17
+ isDigitCode(code) ||
18
+ code === HYPHEN_CODE ||
19
+ code === UNDERSCORE_CODE ||
20
+ (code >= UPPERCASE_A_CODE && code <= UPPERCASE_Z_CODE) ||
21
+ (code >= LOWERCASE_A_CODE && code <= LOWERCASE_Z_CODE)), "@foldkit/ui/internal/selectors.js#isIdentifierCode");
22
+ // NOTE: the CSS.escape algorithm from the CSSOM spec, implemented locally
23
+ // because `CSS` is a browser global and selector building runs during view
24
+ // construction, which also happens under server rendering in Node.
25
+ const escapeCssIdentifier = (value) => {
26
+ const firstCode = value.charCodeAt(0);
27
+ let escaped = '';
28
+ for (let index = 0; index < value.length; index++) {
29
+ const code = value.charCodeAt(index);
30
+ const character = value.charAt(index);
31
+ if (code === NULL_CHARACTER_CODE) {
32
+ escaped += REPLACEMENT_CHARACTER;
33
+ }
34
+ else if ((code >= 1 && code <= MAX_CONTROL_CHARACTER_CODE) ||
35
+ code === DELETE_CHARACTER_CODE ||
36
+ (isDigitCode(code) &&
37
+ (index === 0 || (index === 1 && firstCode === HYPHEN_CODE)))) {
38
+ escaped += `\\${code.toString(16)} `;
39
+ }
40
+ else if (index === 0 && code === HYPHEN_CODE && value.length === 1) {
41
+ escaped += `\\${character}`;
42
+ }
43
+ else if (isIdentifierCode(code)) {
44
+ escaped += character;
45
+ }
46
+ else {
47
+ escaped += `\\${character}`;
48
+ }
49
+ }
50
+ return __foldkitBrandViewResult((escaped), "@foldkit/ui/internal/selectors.js#escapeCssIdentifier");
51
+ };
2
52
  /**
3
53
  * Builds a CSS id selector from an element's id value.
4
54
  *
5
- * The id is escaped with `CSS.escape` so values that are not valid CSS
6
- * identifiers on their own (most notably ids beginning with a digit, as
7
- * produced by UUID-prefixed ids) still yield a usable selector.
55
+ * The id is escaped per the `CSS.escape` algorithm so values that are not
56
+ * valid CSS identifiers on their own (most notably ids beginning with a
57
+ * digit, as produced by UUID-prefixed ids) still yield a usable selector.
58
+ * The escape is implemented locally rather than via the `CSS` browser
59
+ * global so views that build selectors also render under Node.
8
60
  */
9
- export const idSelector = (id) => __foldkitBrandViewResult((`#${CSS.escape(id)}`), "@foldkit/ui/internal/selectors.js#idSelector");
61
+ export const idSelector = (id) => __foldkitBrandViewResult((`#${escapeCssIdentifier(id)}`), "@foldkit/ui/internal/selectors.js#idSelector");
10
62
  /**
11
63
  * Builds a CSS attribute selector matching `attribute` against `value`.
12
64
  *
13
- * The value is quoted and escaped with `CSS.escape`, so values carrying
14
- * brackets, backslashes, spaces, or a leading digit still yield a usable
15
- * selector. The quotes are load bearing: an escaped value is a valid CSS
16
- * identifier but not a valid unquoted attribute value, so dropping them makes
17
- * selectors for digit-leading ids fail to parse.
65
+ * The value is quoted and escaped per the `CSS.escape` algorithm, so values
66
+ * carrying brackets, backslashes, spaces, or a leading digit still yield a
67
+ * usable selector. The quotes are load bearing: an escaped value is a valid
68
+ * CSS identifier but not a valid unquoted attribute value, so dropping them
69
+ * makes selectors for digit-leading ids fail to parse. The escape is the
70
+ * same local implementation `idSelector` uses, so attribute selectors also
71
+ * build under Node during server rendering.
18
72
  */
19
- export const attributeSelector = (attribute, value) => __foldkitBrandViewResult((`[${attribute}="${CSS.escape(value)}"]`), "@foldkit/ui/internal/selectors.js#attributeSelector");
73
+ export const attributeSelector = (attribute, value) => __foldkitBrandViewResult((`[${attribute}="${escapeCssIdentifier(value)}"]`), "@foldkit/ui/internal/selectors.js#attributeSelector");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldkit/ui",
3
- "version": "0.146.0",
3
+ "version": "0.148.0",
4
4
  "description": "Headless, accessible UI components for Foldkit",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -131,8 +131,8 @@
131
131
  "typedoc": "^0.28.19",
132
132
  "typescript": "^6.0.3",
133
133
  "vitest": "^4.1.9",
134
- "@foldkit/vite-plugin": "0.14.0",
135
- "foldkit": "0.146.0"
134
+ "@foldkit/vite-plugin": "0.16.0",
135
+ "foldkit": "0.148.0"
136
136
  },
137
137
  "keywords": [
138
138
  "foldkit",