@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.
@@ -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 hasDisplayDeclaration(matcherData: MatchedCssData): boolean {
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 = resolveDisplayValue(matcherData)
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 = resolveDisplayValue(matcherData)
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 && hasDisplayDeclaration(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
 
@@ -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(gapEnrichedElements),
158
+ elements: convertElements(flexEnrichedElements),
157
159
  }
158
160
  varUsedByTraceId = matchResult.varUsedByTraceId
159
161
  } catch (thrownError) {