@wix/zero-config-implementation 1.45.0 → 1.46.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/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.45.0",
7
+ "version": "1.46.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",
@@ -84,5 +84,5 @@
84
84
  ]
85
85
  }
86
86
  },
87
- "falconPackageHash": "351d3032ce32fe0b9f5864b3e86e133388202d091c298071ef24a7e0"
87
+ "falconPackageHash": "9f4aa3db6c672e0f49191ce43b8bf9de7c884e07c4765eef9a0ed3e7"
88
88
  }
@@ -2,11 +2,12 @@ import type {
2
2
  CssCustomPropertyItem,
3
3
  CssPropertyItem,
4
4
  DataItem,
5
+ Display,
5
6
  EditorElement,
6
7
  EditorReactComponent,
7
8
  ElementItem,
8
9
  } from '@wix/react-component-schema'
9
- import { ELEMENTS } from '@wix/react-component-schema'
10
+ import { CSS_PROPERTIES, ELEMENTS } from '@wix/react-component-schema'
10
11
  import type { ComponentInfoWithCss } from '../index'
11
12
  import type { MatchedCssData } from '../information-extractors/css/types'
12
13
  import type {
@@ -16,6 +17,7 @@ import type {
16
17
  ExtractedElement,
17
18
  TrackingStores,
18
19
  } from '../information-extractors/react'
20
+ import { getDefaultDisplayForTag, resolveDisplayValue } from '../information-extractors/react'
19
21
  import { findPreferredSemanticClass } from '../utils/css-class'
20
22
  import { buildDataItem } from './data-item-builder'
21
23
  import { formatDisplayName } from './utils'
@@ -308,10 +310,24 @@ function getMatchedPropertyValues(element: ExtractedElement): Map<string, string
308
310
  return values
309
311
  }
310
312
 
313
+ const CSS_DISPLAY_TO_ENUM: Record<string, string> = {
314
+ 'inline-block': 'inlineBlock',
315
+ 'inline-flex': 'inlineFlex',
316
+ 'inline-grid': 'inlineGrid',
317
+ 'inline-table': 'inlineTable',
318
+ 'list-item': 'listItem',
319
+ 'flow-root': 'flowRoot',
320
+ }
321
+
322
+ function toDisplayEnumValue(cssValue: string): NonNullable<Display['displayValues']>[number] {
323
+ return (CSS_DISPLAY_TO_ENUM[cssValue] ?? cssValue) as NonNullable<Display['displayValues']>[number]
324
+ }
325
+
326
+ const { CSS_PROPERTY_TYPE, DISPLAY_VALUE } = CSS_PROPERTIES
327
+
311
328
  function buildCssProperties(element: ExtractedElement | undefined): Record<string, CssPropertyItem> {
312
329
  const result: Record<string, CssPropertyItem> = {}
313
330
 
314
- // Get the CSS properties decided by the heuristic
315
331
  const cssData = element?.extractorData.get('css-properties') as CssPropertiesData | undefined
316
332
  const decidedProperties = cssData?.relevant
317
333
  if (!decidedProperties || decidedProperties.length === 0) {
@@ -319,12 +335,28 @@ function buildCssProperties(element: ExtractedElement | undefined): Record<strin
319
335
  }
320
336
  const cssPropertyValues = element ? getMatchedPropertyValues(element) : new Map<string, string>()
321
337
  for (const propName of decidedProperties) {
338
+ if (propName === CSS_PROPERTY_TYPE.display && element) {
339
+ result[propName] = buildDisplayProperty(element)
340
+ continue
341
+ }
322
342
  const defaultValue = cssPropertyValues.get(propName)
323
343
  result[propName] = {
324
- // Only include defaultValue if found in CSS files
325
344
  ...(defaultValue !== undefined && { defaultValue }),
326
345
  }
327
346
  }
328
347
 
329
348
  return result
330
349
  }
350
+
351
+ function buildDisplayProperty(element: ExtractedElement): CssPropertyItem {
352
+ const matcherData = element.extractorData.get('css-matcher') as MatchedCssData | undefined
353
+ const resolvedFromCss = matcherData ? resolveDisplayValue(matcherData) : undefined
354
+ const currentValue = resolvedFromCss ?? getDefaultDisplayForTag(element.tag)
355
+ const currentEnumValue = toDisplayEnumValue(currentValue)
356
+
357
+ return {
358
+ display: {
359
+ displayValues: [DISPLAY_VALUE.none, currentEnumValue],
360
+ },
361
+ }
362
+ }
@@ -0,0 +1,44 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { parseCss } from '../../css/parse'
3
+ import type { MatchedCssData } from '../../css/types'
4
+ import { hasFlexOrGridDisplay } from './css-properties'
5
+
6
+ function matcherDataFromCss(declarations: string): MatchedCssData {
7
+ const properties = parseCss(`.test { ${declarations} }`).getPropertiesForSelector('.test')
8
+ const customProperties: Record<string, string> = {}
9
+ for (const property of properties) {
10
+ if (property.name.startsWith('--')) {
11
+ customProperties[property.name] = property.value
12
+ }
13
+ }
14
+ return {
15
+ matches: [{ selector: '.test', properties: properties.filter((property) => !property.name.startsWith('--')) }],
16
+ customProperties,
17
+ }
18
+ }
19
+
20
+ describe('hasFlexOrGridDisplay', () => {
21
+ it('returns true for display: flex', () => {
22
+ expect(hasFlexOrGridDisplay(matcherDataFromCss('display: flex'))).toBe(true)
23
+ })
24
+
25
+ it('returns false for display: block', () => {
26
+ expect(hasFlexOrGridDisplay(matcherDataFromCss('display: block'))).toBe(false)
27
+ })
28
+
29
+ it('returns false when no properties', () => {
30
+ expect(hasFlexOrGridDisplay(matcherDataFromCss(''))).toBe(false)
31
+ })
32
+
33
+ it('returns false when var resolves to a non-flex/grid value', () => {
34
+ expect(hasFlexOrGridDisplay(matcherDataFromCss('display: var(--d); --d: block'))).toBe(false)
35
+ })
36
+
37
+ it('returns true when var resolves to grid', () => {
38
+ expect(hasFlexOrGridDisplay(matcherDataFromCss('display: var(--d); --d: grid'))).toBe(true)
39
+ })
40
+
41
+ it('returns true when var cannot be resolved', () => {
42
+ expect(hasFlexOrGridDisplay(matcherDataFromCss('display: var(--d)'))).toBe(true)
43
+ })
44
+ })
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { CSS_PROPERTIES } from '@wix/react-component-schema'
9
- import type { CssSelectorMatch, MatchedCssData } from '../../css/types'
9
+ import type { MatchedCssData } from '../../css/types'
10
10
  import type { ExtractedElement } from './core/tree-builder'
11
11
  import type { CreateElementEvent, ReactExtractor } from './core/types'
12
12
 
@@ -186,6 +186,7 @@ export function getCssPropertiesForTag(tag: string, role?: string): string[] {
186
186
  break
187
187
  }
188
188
 
189
+ properties.push(CSS_PROPERTY_TYPE.display)
189
190
  return properties
190
191
  }
191
192
 
@@ -211,23 +212,85 @@ export function addGapProperty(existing: string[]): string[] {
211
212
  return [...existing, CSS_PROPERTY_TYPE.gap]
212
213
  }
213
214
 
215
+ // ─────────────────────────────────────────────────────────────────────────────
216
+ // Display Value Resolution
217
+ // ─────────────────────────────────────────────────────────────────────────────
218
+
219
+ const TAG_DEFAULT_DISPLAY: Record<string, string> = {
220
+ span: 'inline',
221
+ a: 'inline',
222
+ strong: 'inline',
223
+ em: 'inline',
224
+ b: 'inline',
225
+ i: 'inline',
226
+ label: 'inline',
227
+ img: 'inline',
228
+ input: 'inline',
229
+ select: 'inline',
230
+ textarea: 'inline',
231
+ button: 'inline-block',
232
+ li: 'list-item',
233
+ table: 'table',
234
+ }
235
+
236
+ export function getDefaultDisplayForTag(tag: string): string {
237
+ return TAG_DEFAULT_DISPLAY[tag.toLowerCase()] ?? 'block'
238
+ }
239
+
240
+ /**
241
+ * Resolves the current `display` value from matched CSS data, handling both
242
+ * literal values and CSS variable references.
243
+ * Returns the resolved value, or `undefined` if `display` is not declared
244
+ * or uses a variable that cannot be resolved.
245
+ */
246
+ export function resolveDisplayValue(matcherData: MatchedCssData): string | undefined {
247
+ for (const match of matcherData.matches) {
248
+ for (const property of match.properties) {
249
+ if (property.name !== 'display') continue
250
+
251
+ if (!property.varRefs || property.varRefs.length === 0) {
252
+ return property.value
253
+ }
254
+
255
+ for (const varName of property.varRefs) {
256
+ const resolvedValue = matcherData.customProperties[varName]
257
+ if (resolvedValue !== undefined) return resolvedValue
258
+ }
259
+ }
260
+ }
261
+ return undefined
262
+ }
263
+
214
264
  // ─────────────────────────────────────────────────────────────────────────────
215
265
  // Gap Enrichment
216
266
  // ─────────────────────────────────────────────────────────────────────────────
217
267
 
218
268
  const FLEX_GRID_DISPLAY_VALUES = new Set(['flex', 'grid', 'inline-flex', 'inline-grid'])
219
269
 
220
- function hasFlexOrGridDisplay(matches: CssSelectorMatch[]): boolean {
221
- for (const match of matches) {
270
+ /**
271
+ * Returns true if display uses a CSS variable that cannot be resolved --
272
+ * we optimistically assume it could be flex/grid.
273
+ */
274
+ function hasUnresolvableDisplayVar(matcherData: MatchedCssData): boolean {
275
+ for (const match of matcherData.matches) {
222
276
  for (const property of match.properties) {
223
- if (property.name === 'display' && FLEX_GRID_DISPLAY_VALUES.has(property.value)) {
224
- return true
277
+ if (property.name !== 'display') continue
278
+ if (property.varRefs && property.varRefs.length > 0) {
279
+ for (const varName of property.varRefs) {
280
+ if (matcherData.customProperties[varName] === undefined) return true
281
+ }
225
282
  }
226
283
  }
227
284
  }
228
285
  return false
229
286
  }
230
287
 
288
+ export function hasFlexOrGridDisplay(matcherData: MatchedCssData): boolean {
289
+ const displayValue = resolveDisplayValue(matcherData)
290
+ if (displayValue !== undefined) return FLEX_GRID_DISPLAY_VALUES.has(displayValue)
291
+ return hasUnresolvableDisplayVar(matcherData)
292
+ }
293
+
231
294
  /**
232
295
  * Walks the element tree and adds `gap` to relevant CSS properties
233
296
  * for elements that have display: flex|grid and more than 1 child.
@@ -237,7 +300,7 @@ export function enrichGapProperties(elements: ExtractedElement[]): ExtractedElem
237
300
  return elements.map((element) => {
238
301
  if (element.children.length > 1) {
239
302
  const matcherData = element.extractorData.get('css-matcher') as MatchedCssData | undefined
240
- if (matcherData && hasFlexOrGridDisplay(matcherData.matches)) {
303
+ if (matcherData && hasFlexOrGridDisplay(matcherData)) {
241
304
  const cssData = element.extractorData.get('css-properties') as CssPropertiesData | undefined
242
305
  if (cssData) {
243
306
  element.extractorData.set('css-properties', {
@@ -24,5 +24,10 @@ export type {
24
24
  export { createPropTrackerExtractor } from './prop-tracker'
25
25
  export type { PropTrackerData, PropTrackerExtractorState } from './prop-tracker'
26
26
 
27
- export { createCssPropertiesExtractor, enrichGapProperties } from './css-properties'
27
+ export {
28
+ createCssPropertiesExtractor,
29
+ enrichGapProperties,
30
+ resolveDisplayValue,
31
+ getDefaultDisplayForTag,
32
+ } from './css-properties'
28
33
  export type { CssPropertiesData } from './css-properties'
@@ -17,6 +17,8 @@ export {
17
17
  createPropTrackerExtractor,
18
18
  createCssPropertiesExtractor,
19
19
  enrichGapProperties,
20
+ resolveDisplayValue,
21
+ getDefaultDisplayForTag,
20
22
  } from './extractors'
21
23
 
22
24
  export type {