@wix/zero-config-implementation 1.16.0 → 1.18.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.
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function isGlobalSemanticClass(className: string): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Picks the best semantic class from a list of class names.
|
|
4
|
+
* Prefers a class without a BEM modifier (e.g. `card__header`) over one with
|
|
5
|
+
* a modifier (e.g. `card__header--active`), since the base class is more
|
|
6
|
+
* stable as a selector or element name. Falls back to the first semantic class
|
|
7
|
+
* found if all candidates have modifiers.
|
|
8
|
+
*/
|
|
9
|
+
export declare function findPreferredSemanticClass(classNames: string[]): string | undefined;
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"registry": "https://registry.npmjs.org/",
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.18.0",
|
|
8
8
|
"description": "Core library for extracting component manifests from JS and CSS files",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"main": "dist/index.js",
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
]
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
"falconPackageHash": "
|
|
78
|
+
"falconPackageHash": "28d3025e283d998b34b77ef31c51e4195289ad39631c5054675ce0b6"
|
|
79
79
|
}
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
ElementItem,
|
|
17
17
|
} from '../schema'
|
|
18
18
|
import { ELEMENTS } from '../schema'
|
|
19
|
+
import { findPreferredSemanticClass } from '../utils/css-class'
|
|
19
20
|
import { buildDataItem } from './data-item-builder'
|
|
20
21
|
import { formatDisplayName } from './utils'
|
|
21
22
|
|
|
@@ -44,7 +45,8 @@ function buildEditorElement(component: ComponentInfoWithCss): EditorElement {
|
|
|
44
45
|
|
|
45
46
|
function buildSelector(rootElement?: ExtractedElement): string {
|
|
46
47
|
if (rootElement?.attributes.class) {
|
|
47
|
-
|
|
48
|
+
const semanticClass = findPreferredSemanticClass(rootElement.attributes.class.split(' '))
|
|
49
|
+
if (semanticClass) return `.${semanticClass}`
|
|
48
50
|
}
|
|
49
51
|
return rootElement?.tag ?? ''
|
|
50
52
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { pascalCase } from 'case-anything'
|
|
9
9
|
import { type DefaultTreeAdapterMap, parseFragment } from 'parse5'
|
|
10
10
|
import { TRACE_ATTR } from '../../../../component-renderer'
|
|
11
|
+
import { findPreferredSemanticClass } from '../../../../utils/css-class'
|
|
11
12
|
import { PRESETS_WRAPPER_CLASS_NAME } from '../../utils/mock-generator'
|
|
12
13
|
import type { CssPropertiesData } from '../css-properties'
|
|
13
14
|
import { addTextProperties } from '../css-properties'
|
|
@@ -169,6 +170,12 @@ function getElementNamePart(element: Element, getElementById: (id: string) => El
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
const classAttr = getAttribute(element, 'class')
|
|
174
|
+
if (classAttr) {
|
|
175
|
+
const semanticClass = findPreferredSemanticClass(classAttr.split(' '))
|
|
176
|
+
if (semanticClass) return pascalCase(semanticClass)
|
|
177
|
+
}
|
|
178
|
+
|
|
172
179
|
return normalizeTagName(element.tagName)
|
|
173
180
|
}
|
|
174
181
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lowercase kebab-case word: starts with a letter, followed by lowercase
|
|
3
|
+
* letters, digits, or hyphens. e.g. `menu`, `item-label`, `foo2`
|
|
4
|
+
*/
|
|
5
|
+
const KEBAB_WORD = '[a-z][a-z0-9-]*'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An optional BEM element suffix: `__` followed by a kebab word.
|
|
9
|
+
* e.g. `__item-label` in `menu__item-label`
|
|
10
|
+
*/
|
|
11
|
+
const OPTIONAL_BEM_ELEMENT = `(__${KEBAB_WORD})?`
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A single BEM modifier suffix: `--` followed by a kebab word.
|
|
15
|
+
* e.g. `--primary` in `button--primary`
|
|
16
|
+
*/
|
|
17
|
+
const BEM_MODIFIER = `--${KEBAB_WORD}`
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A semantic CSS class name following BEM conventions: a kebab-case block,
|
|
21
|
+
* optionally followed by a `__element` and/or one or more `--modifier` parts.
|
|
22
|
+
* All parts must be lowercase — this rejects CSS Module hash suffixes which
|
|
23
|
+
* contain uppercase letters (e.g. `root__SvhJ-`) or leading underscores
|
|
24
|
+
* (e.g. `_root_x7k9p2`).
|
|
25
|
+
*/
|
|
26
|
+
const SEMANTIC_CLASS_PATTERN = new RegExp(`^${KEBAB_WORD}${OPTIONAL_BEM_ELEMENT}(${BEM_MODIFIER})*$`)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Matches a class that has at least one BEM modifier (`--`).
|
|
30
|
+
* Used to deprioritize modifier classes in favour of the base class.
|
|
31
|
+
*/
|
|
32
|
+
const HAS_BEM_MODIFIER = new RegExp(BEM_MODIFIER)
|
|
33
|
+
|
|
34
|
+
export function isGlobalSemanticClass(className: string): boolean {
|
|
35
|
+
return SEMANTIC_CLASS_PATTERN.test(className)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Picks the best semantic class from a list of class names.
|
|
40
|
+
* Prefers a class without a BEM modifier (e.g. `card__header`) over one with
|
|
41
|
+
* a modifier (e.g. `card__header--active`), since the base class is more
|
|
42
|
+
* stable as a selector or element name. Falls back to the first semantic class
|
|
43
|
+
* found if all candidates have modifiers.
|
|
44
|
+
*/
|
|
45
|
+
export function findPreferredSemanticClass(classNames: string[]): string | undefined {
|
|
46
|
+
const semanticClasses = classNames.filter(isGlobalSemanticClass)
|
|
47
|
+
return semanticClasses.find((className) => !HAS_BEM_MODIFIER.test(className)) ?? semanticClasses[0]
|
|
48
|
+
}
|