@wix/zero-config-implementation 1.81.0 → 1.83.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.d.ts CHANGED
@@ -2395,6 +2395,8 @@ export declare interface PropInfo {
2395
2395
  resolvedType: ResolvedType;
2396
2396
  description?: string;
2397
2397
  deprecated?: boolean;
2398
+ min?: string;
2399
+ max?: string;
2398
2400
  isStateTrigger?: boolean;
2399
2401
  }
2400
2402
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-CqoYtob0.js";
1
+ import { B as t, D as e, E as o, I as n, N as c, P as l, R as i, a as p, V as E, b as m, c as x, d as f, e as d, f as u, h as C, i as I, j as k, k as y, l as A, m as D, n as P, o as R, p as h, q as B, r as M, s as T, t as b, w } from "./index-nLqobONA.js";
2
2
  import "react";
3
3
  export {
4
4
  t as BaseError,
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "1.81.0",
7
+ "version": "1.83.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",
@@ -82,5 +82,5 @@
82
82
  ]
83
83
  }
84
84
  },
85
- "falconPackageHash": "a62684e6a36b7c409927242d6d286817a3aa7b2ef5601dac8e42ab5f"
85
+ "falconPackageHash": "f80ca8596a9188b6f45fa139c17ea7ed3637fceffaddcb566b22d2db"
86
86
  }
@@ -169,7 +169,10 @@ function handlePrimitiveType(
169
169
  }
170
170
  } else if (typeValue.includes('number')) {
171
171
  dataItem.dataType = DATA_TYPE.number
172
- dataItem.number = {}
172
+ dataItem.number =
173
+ propInfo.min != null || propInfo.max != null
174
+ ? { ...(propInfo.min != null && { min: propInfo.min }), ...(propInfo.max != null && { max: propInfo.max }) }
175
+ : {}
173
176
  } else if (typeValue.includes('boolean')) {
174
177
  dataItem.dataType = DATA_TYPE.booleanValue
175
178
  } else {
@@ -54,6 +54,27 @@ function createComponent(rootElement: ExtractedElement): ComponentInfoWithCss {
54
54
  }
55
55
  }
56
56
 
57
+ function createSemanticElement({
58
+ traceId,
59
+ name,
60
+ className,
61
+ children = [],
62
+ }: {
63
+ traceId: string
64
+ name: string
65
+ className: string
66
+ children?: ExtractedElement[]
67
+ }): ExtractedElement {
68
+ return {
69
+ traceId,
70
+ name,
71
+ tag: 'div',
72
+ attributes: { class: className },
73
+ extractorData: new Map<string, unknown>(),
74
+ children,
75
+ }
76
+ }
77
+
57
78
  describe('toEditorReactComponent display conversion', () => {
58
79
  it('resolves local display fallback chains before emitting the manifest display value', () => {
59
80
  const rootElement = createElementWithDisplayMatcher(
@@ -85,6 +106,64 @@ describe('toEditorReactComponent display conversion', () => {
85
106
  },
86
107
  })
87
108
  })
109
+
110
+ it('omits the nearest matching ancestor class prefix from inner element display names', () => {
111
+ const rootElement = createSemanticElement({
112
+ traceId: 'trace-root',
113
+ name: 'root',
114
+ className: 'testimonials-slider',
115
+ children: [
116
+ createSemanticElement({
117
+ traceId: 'trace-play-pause-button',
118
+ name: 'playPauseButton',
119
+ className: 'play-pause-button',
120
+ }),
121
+ createSemanticElement({
122
+ traceId: 'trace-slide',
123
+ name: 'testimonialsSliderSlide',
124
+ className: 'testimonials-slider-slide',
125
+ children: [
126
+ createSemanticElement({
127
+ traceId: 'trace-quote',
128
+ name: 'testimonialsSliderQuote',
129
+ className: 'testimonials-slider-slide-quote',
130
+ }),
131
+ createSemanticElement({
132
+ traceId: 'trace-author',
133
+ name: 'testimonialsSliderAuthor',
134
+ className: 'testimonials-slider__author',
135
+ }),
136
+ ],
137
+ }),
138
+ ],
139
+ })
140
+
141
+ const elements = toEditorReactComponent({
142
+ ...createComponent(rootElement),
143
+ componentName: 'TestimonialsSlider',
144
+ }).editorElement?.elements
145
+
146
+ expect(elements?.playPauseButton?.inlineElement).toMatchObject({
147
+ selector: '.play-pause-button',
148
+ displayName: 'Play Pause Button',
149
+ })
150
+ expect(elements?.testimonialsSliderSlide?.inlineElement).toMatchObject({
151
+ selector: '.testimonials-slider-slide',
152
+ displayName: 'Slide',
153
+ })
154
+ expect(
155
+ elements?.testimonialsSliderSlide?.inlineElement?.elements?.testimonialsSliderQuote?.inlineElement,
156
+ ).toMatchObject({
157
+ selector: '.testimonials-slider-slide-quote',
158
+ displayName: 'Quote',
159
+ })
160
+ expect(
161
+ elements?.testimonialsSliderSlide?.inlineElement?.elements?.testimonialsSliderAuthor?.inlineElement,
162
+ ).toMatchObject({
163
+ selector: '.testimonials-slider__author',
164
+ displayName: 'Author',
165
+ })
166
+ })
88
167
  })
89
168
 
90
169
  function cssInfoFromStylesheet(cssString: string): ExtractedCssInfo {
@@ -75,6 +75,7 @@ function buildEditorElement(
75
75
  // class triggers don't (they carry the className verbatim and match the element
76
76
  // directly), so they're built even when the element resolves no semantic class.
77
77
  const rootSemanticClass = getSemanticBlockName(rootElement)
78
+ const rootSemanticClasses = rootSemanticClass ? [rootSemanticClass] : []
78
79
  const rootStates = rootElement
79
80
  ? mergeStates(
80
81
  rootSemanticClass ? buildStatesBlock(rootElement, rootSemanticClass) : undefined,
@@ -94,6 +95,7 @@ function buildEditorElement(
94
95
  childElements,
95
96
  nearestCommonAncestorCustomProps,
96
97
  customClassTriggers,
98
+ rootSemanticClasses,
97
99
  component.innerElementProps,
98
100
  component.propUsages,
99
101
  ),
@@ -116,6 +118,23 @@ function buildSelector(rootElement?: ExtractedElement): string {
116
118
  return rootElement?.tag ?? ''
117
119
  }
118
120
 
121
+ function buildInnerElementDisplayName(element: ExtractedElement, ancestorSemanticClasses: string[]): string {
122
+ const semanticClass = getSemanticBlockName(element)
123
+
124
+ if (semanticClass) {
125
+ for (const ancestorSemanticClass of [...ancestorSemanticClasses].reverse()) {
126
+ for (const separator of ['-', '__']) {
127
+ const ancestorPrefix = `${ancestorSemanticClass}${separator}`
128
+ if (semanticClass.startsWith(ancestorPrefix)) {
129
+ return formatDisplayName(semanticClass.slice(ancestorPrefix.length))
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ return formatDisplayName(element.name)
136
+ }
137
+
119
138
  function buildData(
120
139
  props: Record<string, CoupledProp>,
121
140
  propUsages: TrackingStores['propUsages'],
@@ -142,6 +161,7 @@ function buildElements(
142
161
  elements: ExtractedElement[],
143
162
  nearestCommonAncestorCustomProps: Map<string, Record<string, CssCustomPropertyItem>>,
144
163
  customClassTriggers: CustomClassTrigger[],
164
+ ancestorSemanticClasses: string[],
145
165
  innerElementProps?: CoupledComponentInfo['innerElementProps'],
146
166
  propUsages?: TrackingStores['propUsages'],
147
167
  parentElementPropsPath?: string,
@@ -180,7 +200,7 @@ function buildElements(
180
200
  elementType: ELEMENTS.ELEMENT_TYPE.inlineElement,
181
201
  inlineElement: {
182
202
  selector: buildSelector(element),
183
- displayName: formatDisplayName(element.name),
203
+ displayName: buildInnerElementDisplayName(element, ancestorSemanticClasses),
184
204
  behaviors: { removable: true, selectable: false },
185
205
  // Add data from inner element props if available
186
206
  ...(data && Object.keys(data).length > 0 && { data }),
@@ -196,6 +216,7 @@ function buildElements(
196
216
  element.children,
197
217
  nearestCommonAncestorCustomProps,
198
218
  customClassTriggers,
219
+ semanticClass ? [...ancestorSemanticClasses, semanticClass] : ancestorSemanticClasses,
199
220
  innerElementProps,
200
221
  propUsages,
201
222
  innerEntry?.elementPropsPath ?? parentElementPropsPath,
@@ -252,6 +252,8 @@ function convertComponentDoc(doc: ComponentDoc, program: ts.Program, checker: ts
252
252
  resolvedType,
253
253
  description: propItem.description || undefined,
254
254
  deprecated: tags?.deprecated !== undefined ? true : undefined,
255
+ min: parseNumericTag(tags?.min, propName, 'min'),
256
+ max: parseNumericTag(tags?.max, propName, 'max'),
255
257
  isStateTrigger: stateTrigger ? true : undefined,
256
258
  }
257
259
  }
@@ -335,6 +337,14 @@ function findPropsType(
335
337
  // Default value conversion
336
338
  // ─────────────────────────────────────────────────────────────────────────────
337
339
 
340
+ function parseNumericTag(value: string | undefined, propName: string, tag: string): string | undefined {
341
+ if (value !== undefined && Number.isNaN(Number(value))) {
342
+ console.warn(`@${tag} on prop "${propName}" is not a valid number ("${value}") — ignoring`)
343
+ return undefined
344
+ }
345
+ return value
346
+ }
347
+
338
348
  function convertDefaultValue(rdtDefault: { value: unknown } | null): DefaultValue | undefined {
339
349
  if (!rdtDefault || rdtDefault.value == null) return undefined
340
350
 
@@ -51,6 +51,9 @@ export interface PropInfo {
51
51
  description?: string
52
52
  // Whether the prop is marked as deprecated via @deprecated JSDoc tag
53
53
  deprecated?: boolean
54
+ // Numeric range constraints extracted from @min / @max JSDoc tags (decimal strings)
55
+ min?: string
56
+ max?: string
54
57
  // True when the prop is wrapped in the `ElementState<>` marker type from
55
58
  // @wix/react-component-utils, declaring it as the trigger for a custom design
56
59
  // state. `type` and `resolvedType` reflect the unwrapped inner type, so the prop