@wix/zero-config-implementation 1.61.0 → 1.63.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,83 @@
1
+ /**
2
+ * Composes a CSS shorthand value (`font`, …) from longhand declarations the
3
+ * developer wrote. Inverse of the splitters in `css-longhand-resolver.ts`:
4
+ *
5
+ * resolver splits: `padding: 1rem` → `paddingTop: "1rem"`
6
+ * composer assembles: `font-family + font-size` → `font: "16px Arial"`
7
+ *
8
+ * Strict policy: when the CSS spec marks a piece as required and it's missing
9
+ * from the map, the composer returns `undefined` rather than emit a partial
10
+ * string the editor's value parser would reject as invalid shorthand.
11
+ */
12
+
13
+ type Composer = (values: Map<string, string>) => string | undefined
14
+
15
+ /**
16
+ * Builds a `font` shorthand value from longhand declarations, per CSS spec:
17
+ * [ <font-style> || <font-variant> || <font-weight> || <font-stretch> ]?
18
+ * <font-size> [ / <line-height> ]? <font-family>
19
+ *
20
+ * Returns undefined unless both required pieces (font-size and font-family)
21
+ * are present. Modifiers with the literal value `normal` are omitted (they're
22
+ * the shorthand's implicit default and would add noise to the emitted string).
23
+ */
24
+ export function composeFontShorthand(values: Map<string, string>): string | undefined {
25
+ const size = values.get('fontSize')
26
+ const family = values.get('fontFamily')
27
+ if (size === undefined || family === undefined) return undefined
28
+
29
+ const parts: string[] = []
30
+
31
+ // Optional modifiers (style, variant, weight, stretch). Order matters per CSS
32
+ // spec but their order relative to each other is free; size always follows.
33
+ for (const key of ['fontStyle', 'fontVariant', 'fontWeight', 'fontStretch']) {
34
+ const value = values.get(key)
35
+ if (value !== undefined && value.toLowerCase() !== 'normal') parts.push(value)
36
+ }
37
+
38
+ const lineHeight = values.get('lineHeight')
39
+ if (lineHeight !== undefined && lineHeight.toLowerCase() !== 'normal') {
40
+ parts.push(`${size}/${lineHeight}`)
41
+ } else {
42
+ parts.push(size)
43
+ }
44
+
45
+ // Family names may carry CSS double-quotes (`"Helvetica Neue"`). Normalize to
46
+ // single quotes so the emitted shorthand can be embedded in JSON / snapshot
47
+ // strings without the inner `"` colliding with the outer delimiter. CSS
48
+ // accepts both quote styles equally for family names.
49
+ parts.push(family.replace(/"/g, "'"))
50
+ return parts.join(' ')
51
+ }
52
+
53
+ /**
54
+ * Builds a `gap` shorthand value from `row-gap` + `column-gap` longhands.
55
+ *
56
+ * gap: <row-gap> [<column-gap>]?
57
+ *
58
+ * Strict: both axes required. Composing from just one would lie about intent —
59
+ * `gap: 8px` sets BOTH axes to 8px, whereas the developer's `row-gap: 8px`
60
+ * alone leaves column-gap at its initial value. Collapses to a single value
61
+ * when the two axes are equal, matching how developers write it by hand.
62
+ */
63
+ export function composeGapShorthand(values: Map<string, string>): string | undefined {
64
+ const rowGap = values.get('rowGap')
65
+ const columnGap = values.get('columnGap')
66
+ if (rowGap === undefined || columnGap === undefined) return undefined
67
+
68
+ if (rowGap === columnGap) return rowGap
69
+ return `${rowGap} ${columnGap}`
70
+ }
71
+
72
+ /**
73
+ * Routing table for shorthand targets the schema asks for. Maps each target
74
+ * to the composer(s) that build its value from longhand declarations. The
75
+ * resolver in `css-longhand-resolver.ts` merges this in when dispatching
76
+ * `resolveLonghand`.
77
+ *
78
+ * Add new shorthand targets here as they're needed (background, border, …).
79
+ */
80
+ export const SHORTHAND_FALLBACKS: Record<string, Composer[]> = {
81
+ font: [composeFontShorthand],
82
+ gap: [composeGapShorthand],
83
+ }
@@ -8,6 +8,7 @@ import type {
8
8
  ElementItem,
9
9
  } from '@wix/react-component-schema'
10
10
  import { CSS_PROPERTIES, ELEMENTS } from '@wix/react-component-schema'
11
+ import { camelCase } from 'case-anything'
11
12
  import type { ComponentInfoWithCss } from '../index'
12
13
  import type { MatchedCssData } from '../information-extractors/css/types'
13
14
  import type {
@@ -19,6 +20,7 @@ import type {
19
20
  } from '../information-extractors/react'
20
21
  import { getDefaultDisplayForTag, resolveDisplayValue } from '../information-extractors/react'
21
22
  import { findPreferredSemanticClass } from '../utils/css-class'
23
+ import { resolveLonghand } from './css-longhand-resolver'
22
24
  import { buildDataItem } from './data-item-builder'
23
25
  import { formatDisplayName } from './utils'
24
26
 
@@ -305,7 +307,7 @@ function getMatchedPropertyValues(element: ExtractedElement): Map<string, string
305
307
  const values = new Map<string, string>()
306
308
  for (const match of matches) {
307
309
  for (const prop of match.properties) {
308
- values.set(prop.name, prop.value)
310
+ values.set(camelCase(prop.name), prop.value)
309
311
  }
310
312
  }
311
313
  return values
@@ -340,7 +342,7 @@ function buildCssProperties(element: ExtractedElement | undefined): Record<strin
340
342
  result[propName] = buildDisplayProperty(element)
341
343
  continue
342
344
  }
343
- const defaultValue = cssPropertyValues.get(propName)
345
+ const defaultValue = resolveLonghand(propName, cssPropertyValues)
344
346
  result[propName] = {
345
347
  ...(defaultValue !== undefined && { defaultValue }),
346
348
  }