@wix/zero-config-implementation 1.99.0 → 1.101.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/dist/index.js +9879 -9791
- package/package.json +2 -2
- package/src/converters/css-longhand-resolver.test.ts +35 -0
- package/src/converters/css-longhand-resolver.ts +22 -0
- package/src/converters/to-editor-component.test.ts +125 -0
- package/src/converters/to-editor-component.ts +38 -18
- package/src/information-extractors/react/extractors/css-properties.test.ts +136 -0
- package/src/information-extractors/react/extractors/css-properties.ts +146 -4
- package/src/information-extractors/react/extractors/index.ts +2 -0
- package/src/information-extractors/react/index.ts +2 -0
- package/src/manifest-pipeline.ts +3 -1
|
@@ -99,6 +99,70 @@ const BOX_CSS_PROPERTIES = [
|
|
|
99
99
|
CSS_PROPERTY_TYPE.borderEndStartRadius,
|
|
100
100
|
CSS_PROPERTY_TYPE.borderEndEndRadius,
|
|
101
101
|
CSS_PROPERTY_TYPE.boxShadow,
|
|
102
|
+
CSS_PROPERTY_TYPE.width,
|
|
103
|
+
CSS_PROPERTY_TYPE.height,
|
|
104
|
+
CSS_PROPERTY_TYPE.overflow,
|
|
105
|
+
CSS_PROPERTY_TYPE.mixBlendMode,
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Margin applies to most DOM elements regardless of box/text/media
|
|
110
|
+
* semantics, so it's appended in `getCssPropertiesForTag` rather than gated
|
|
111
|
+
* to one of the trait-based sets above — except for the display-dependent
|
|
112
|
+
* carve-outs in `getMarginPropertiesForTag` below.
|
|
113
|
+
*/
|
|
114
|
+
const MARGIN_CSS_PROPERTIES = [
|
|
115
|
+
CSS_PROPERTY_TYPE.marginTop,
|
|
116
|
+
CSS_PROPERTY_TYPE.marginBottom,
|
|
117
|
+
CSS_PROPERTY_TYPE.marginInlineStart,
|
|
118
|
+
CSS_PROPERTY_TYPE.marginInlineEnd,
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
const HORIZONTAL_MARGIN_CSS_PROPERTIES = [CSS_PROPERTY_TYPE.marginInlineStart, CSS_PROPERTY_TYPE.marginInlineEnd]
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Per CSS 2.1 §17.6.1, margin does not apply to elements with these internal
|
|
125
|
+
* table display values — the table layout algorithm ignores it entirely.
|
|
126
|
+
*/
|
|
127
|
+
const MARGIN_UNSUPPORTED_DISPLAY_VALUES = new Set([
|
|
128
|
+
'table-row',
|
|
129
|
+
'table-row-group',
|
|
130
|
+
'table-header-group',
|
|
131
|
+
'table-footer-group',
|
|
132
|
+
'table-column',
|
|
133
|
+
'table-column-group',
|
|
134
|
+
'table-cell',
|
|
135
|
+
])
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Margin properties relevant to a tag's default display. Internal table
|
|
139
|
+
* display values (`tr`, `thead`/`tbody`/`tfoot`, `col`/`colgroup`, `td`/`th`)
|
|
140
|
+
* don't honor margin at all. Non-replaced inline elements (`span`, `a`, …)
|
|
141
|
+
* only honor the horizontal (inline) margins — `margin-top`/`margin-bottom`
|
|
142
|
+
* have no effect on them. Replaced inline elements (`img`, `video`, …) honor
|
|
143
|
+
* margin on every side, same as a block box.
|
|
144
|
+
*/
|
|
145
|
+
function getMarginPropertiesForTag(tag: string): string[] {
|
|
146
|
+
const normalizedTag = tag.toLowerCase()
|
|
147
|
+
const defaultDisplay = getDefaultDisplayForTag(normalizedTag)
|
|
148
|
+
|
|
149
|
+
if (MARGIN_UNSUPPORTED_DISPLAY_VALUES.has(defaultDisplay)) {
|
|
150
|
+
return []
|
|
151
|
+
}
|
|
152
|
+
if (defaultDisplay === 'inline' && !MEDIA_TAGS.has(normalizedTag)) {
|
|
153
|
+
return HORIZONTAL_MARGIN_CSS_PROPERTIES
|
|
154
|
+
}
|
|
155
|
+
return MARGIN_CSS_PROPERTIES
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Child-layout controls for flex/grid containers, added post-hoc by
|
|
160
|
+
* `enrichFlexProperties` once the element's resolved `display` is known.
|
|
161
|
+
*/
|
|
162
|
+
const FLEX_CONTAINER_CSS_PROPERTIES = [
|
|
163
|
+
CSS_PROPERTY_TYPE.flexDirection,
|
|
164
|
+
CSS_PROPERTY_TYPE.justifyContent,
|
|
165
|
+
CSS_PROPERTY_TYPE.alignItems,
|
|
102
166
|
]
|
|
103
167
|
|
|
104
168
|
/**
|
|
@@ -128,6 +192,12 @@ const MEDIA_CSS_PROPERTIES = [
|
|
|
128
192
|
CSS_PROPERTY_TYPE.borderEndStartRadius,
|
|
129
193
|
CSS_PROPERTY_TYPE.borderEndEndRadius,
|
|
130
194
|
CSS_PROPERTY_TYPE.boxShadow,
|
|
195
|
+
CSS_PROPERTY_TYPE.width,
|
|
196
|
+
CSS_PROPERTY_TYPE.height,
|
|
197
|
+
CSS_PROPERTY_TYPE.overflow,
|
|
198
|
+
CSS_PROPERTY_TYPE.objectFit,
|
|
199
|
+
CSS_PROPERTY_TYPE.objectPosition,
|
|
200
|
+
CSS_PROPERTY_TYPE.mixBlendMode,
|
|
131
201
|
]
|
|
132
202
|
|
|
133
203
|
function hasTextSemantics(tag: string, attributes: SemanticAttributes = {}): boolean {
|
|
@@ -180,6 +250,7 @@ export function getCssPropertiesForTag(tag: string, attributes: SemanticAttribut
|
|
|
180
250
|
properties.push(...BOX_CSS_PROPERTIES)
|
|
181
251
|
}
|
|
182
252
|
|
|
253
|
+
properties.push(...getMarginPropertiesForTag(tag))
|
|
183
254
|
properties.push(CSS_PROPERTY_TYPE.display)
|
|
184
255
|
return [...new Set(properties)]
|
|
185
256
|
}
|
|
@@ -219,6 +290,27 @@ export function addGapProperty(existing: string[]): string[] {
|
|
|
219
290
|
return [...existing, CSS_PROPERTY_TYPE.gap]
|
|
220
291
|
}
|
|
221
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Adds flex/grid container CSS properties to an existing property list without duplicates.
|
|
295
|
+
*/
|
|
296
|
+
export function addFlexContainerProperties(existing: string[]): string[] {
|
|
297
|
+
const result = [...existing]
|
|
298
|
+
for (const property of FLEX_CONTAINER_CSS_PROPERTIES) {
|
|
299
|
+
if (!result.includes(property)) {
|
|
300
|
+
result.push(property)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return result
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Adds the `alignSelf` CSS property to an existing property list if not already present.
|
|
308
|
+
*/
|
|
309
|
+
export function addAlignSelfProperty(existing: string[]): string[] {
|
|
310
|
+
if (existing.includes(CSS_PROPERTY_TYPE.alignSelf)) return existing
|
|
311
|
+
return [...existing, CSS_PROPERTY_TYPE.alignSelf]
|
|
312
|
+
}
|
|
313
|
+
|
|
222
314
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
223
315
|
// Display Value Resolution
|
|
224
316
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -412,7 +504,7 @@ function hasUnresolvableDisplayVar(matcherData: MatchedCssData): boolean {
|
|
|
412
504
|
return resolveCssPropertyValue(displayProperty, matcherData.customProperties) === undefined
|
|
413
505
|
}
|
|
414
506
|
|
|
415
|
-
function
|
|
507
|
+
function hasLiteralDisplayDeclaration(matcherData: MatchedCssData): boolean {
|
|
416
508
|
for (const match of matcherData.matches) {
|
|
417
509
|
for (const property of match.properties) {
|
|
418
510
|
if (property.name === 'display') return true
|
|
@@ -421,14 +513,30 @@ function hasDisplayDeclaration(matcherData: MatchedCssData): boolean {
|
|
|
421
513
|
return false
|
|
422
514
|
}
|
|
423
515
|
|
|
516
|
+
export const ROOT_DISPLAY_CUSTOM_PROPERTY = '--display'
|
|
517
|
+
|
|
518
|
+
function hasEffectiveDisplayDeclaration(matcherData: MatchedCssData): boolean {
|
|
519
|
+
return (
|
|
520
|
+
hasLiteralDisplayDeclaration(matcherData) ||
|
|
521
|
+
matcherData.customProperties[ROOT_DISPLAY_CUSTOM_PROPERTY] !== undefined
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function resolveEffectiveDisplayValue(matcherData: MatchedCssData): string | undefined {
|
|
526
|
+
const resolved = resolveDisplayValue(matcherData)
|
|
527
|
+
if (resolved !== undefined) return resolved
|
|
528
|
+
if (hasLiteralDisplayDeclaration(matcherData)) return undefined
|
|
529
|
+
return matcherData.customProperties[ROOT_DISPLAY_CUSTOM_PROPERTY]
|
|
530
|
+
}
|
|
531
|
+
|
|
424
532
|
export function hasFlexOrGridDisplay(matcherData: MatchedCssData): boolean {
|
|
425
|
-
const displayValue =
|
|
533
|
+
const displayValue = resolveEffectiveDisplayValue(matcherData)
|
|
426
534
|
if (displayValue !== undefined) return displayUsesFlexOrGridLayout(displayValue)
|
|
427
535
|
return hasUnresolvableDisplayVar(matcherData)
|
|
428
536
|
}
|
|
429
537
|
|
|
430
538
|
export function hasContainerLikeDisplay(matcherData: MatchedCssData): boolean {
|
|
431
|
-
const displayValue =
|
|
539
|
+
const displayValue = resolveEffectiveDisplayValue(matcherData)
|
|
432
540
|
if (displayValue !== undefined) return displayCreatesContainerBox(displayValue)
|
|
433
541
|
return hasUnresolvableDisplayVar(matcherData)
|
|
434
542
|
}
|
|
@@ -456,7 +564,7 @@ function hasDefaultBoxProperties(tag: string, role?: string): boolean {
|
|
|
456
564
|
}
|
|
457
565
|
|
|
458
566
|
function hasEffectiveContainerDisplay(tag: string, role?: string, matcherData?: MatchedCssData): boolean {
|
|
459
|
-
if (matcherData &&
|
|
567
|
+
if (matcherData && hasEffectiveDisplayDeclaration(matcherData)) {
|
|
460
568
|
return hasContainerLikeDisplay(matcherData)
|
|
461
569
|
}
|
|
462
570
|
|
|
@@ -488,6 +596,40 @@ export function enrichGapProperties(elements: ExtractedElement[]): ExtractedElem
|
|
|
488
596
|
})
|
|
489
597
|
}
|
|
490
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Walks the element tree and adds flex/grid layout controls to relevant CSS
|
|
601
|
+
* properties: `flexDirection`/`justifyContent`/`alignItems` on elements whose
|
|
602
|
+
* own display is flex|grid, and `alignSelf` on their direct children (the
|
|
603
|
+
* property that actually targets flex/grid items per the CSS spec).
|
|
604
|
+
* Must be called after CSS selector matching (requires css-matcher data).
|
|
605
|
+
*/
|
|
606
|
+
export function enrichFlexProperties(
|
|
607
|
+
elements: ExtractedElement[],
|
|
608
|
+
parentIsFlexOrGridContainer = false,
|
|
609
|
+
): ExtractedElement[] {
|
|
610
|
+
return elements.map((element) => {
|
|
611
|
+
const matcherData = element.extractorData.get('css-matcher') as MatchedCssData | undefined
|
|
612
|
+
const isFlexOrGridContainer = matcherData ? hasFlexOrGridDisplay(matcherData) : false
|
|
613
|
+
const cssData = element.extractorData.get('css-properties') as CssPropertiesData | undefined
|
|
614
|
+
|
|
615
|
+
if (cssData) {
|
|
616
|
+
let relevant = cssData.relevant
|
|
617
|
+
if (isFlexOrGridContainer) {
|
|
618
|
+
relevant = addFlexContainerProperties(relevant)
|
|
619
|
+
}
|
|
620
|
+
if (parentIsFlexOrGridContainer) {
|
|
621
|
+
relevant = addAlignSelfProperty(relevant)
|
|
622
|
+
}
|
|
623
|
+
element.extractorData.set('css-properties', { relevant })
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
...element,
|
|
628
|
+
children: enrichFlexProperties(element.children, isFlexOrGridContainer),
|
|
629
|
+
}
|
|
630
|
+
})
|
|
631
|
+
}
|
|
632
|
+
|
|
491
633
|
/**
|
|
492
634
|
* Walks the element tree and adds box properties to selected text tags
|
|
493
635
|
* when CSS overrides `display` or default UA display creates a box.
|
|
@@ -28,8 +28,10 @@ export {
|
|
|
28
28
|
createCssPropertiesExtractor,
|
|
29
29
|
enrichGapProperties,
|
|
30
30
|
enrichContainerProperties,
|
|
31
|
+
enrichFlexProperties,
|
|
31
32
|
resolveDisplayValue,
|
|
32
33
|
getDefaultDisplayForTag,
|
|
34
|
+
ROOT_DISPLAY_CUSTOM_PROPERTY,
|
|
33
35
|
} from './css-properties'
|
|
34
36
|
export type { CssPropertiesData } from './css-properties'
|
|
35
37
|
|
|
@@ -18,8 +18,10 @@ export {
|
|
|
18
18
|
createCssPropertiesExtractor,
|
|
19
19
|
enrichGapProperties,
|
|
20
20
|
enrichContainerProperties,
|
|
21
|
+
enrichFlexProperties,
|
|
21
22
|
resolveDisplayValue,
|
|
22
23
|
getDefaultDisplayForTag,
|
|
24
|
+
ROOT_DISPLAY_CUSTOM_PROPERTY,
|
|
23
25
|
inferSupportedNativeStates,
|
|
24
26
|
} from './extractors'
|
|
25
27
|
|
package/src/manifest-pipeline.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
createCssPropertiesExtractor,
|
|
11
11
|
createPropTrackerExtractor,
|
|
12
12
|
enrichContainerProperties,
|
|
13
|
+
enrichFlexProperties,
|
|
13
14
|
enrichGapProperties,
|
|
14
15
|
runExtractors,
|
|
15
16
|
} from './information-extractors/react'
|
|
@@ -151,9 +152,10 @@ export function processComponent(
|
|
|
151
152
|
const matchResult = matchCssSelectors(html, extractedElements, css)
|
|
152
153
|
const containerEnrichedElements = enrichContainerProperties(matchResult.elements)
|
|
153
154
|
const gapEnrichedElements = enrichGapProperties(containerEnrichedElements)
|
|
155
|
+
const flexEnrichedElements = enrichFlexProperties(gapEnrichedElements)
|
|
154
156
|
enhancedInfo = {
|
|
155
157
|
...enhancedInfo,
|
|
156
|
-
elements: convertElements(
|
|
158
|
+
elements: convertElements(flexEnrichedElements),
|
|
157
159
|
}
|
|
158
160
|
varUsedByTraceId = matchResult.varUsedByTraceId
|
|
159
161
|
} catch (thrownError) {
|