xmlui 0.10.15 → 0.10.16

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.
Files changed (43) hide show
  1. package/dist/lib/{index-axjeT2uJ.mjs → index-D4RYJasT.mjs} +2251 -575
  2. package/dist/lib/index.css +1 -1
  3. package/dist/lib/{initMock-BoTWMs19.mjs → initMock-qzTZlH-6.mjs} +1 -1
  4. package/dist/lib/xmlui-parser.d.ts +1 -1
  5. package/dist/lib/xmlui.d.ts +4 -6
  6. package/dist/lib/xmlui.mjs +1 -1
  7. package/dist/metadata/{collectedComponentMetadata-CQywuPDB.mjs → collectedComponentMetadata-BQaefK3f.mjs} +2536 -861
  8. package/dist/metadata/{initMock-Bi5kF5Af.mjs → initMock-Cz6QssI3.mjs} +1 -1
  9. package/dist/metadata/style.css +1 -1
  10. package/dist/metadata/xmlui-metadata.mjs +1 -1
  11. package/dist/metadata/xmlui-metadata.umd.js +3 -3
  12. package/dist/scripts/package.json +1 -1
  13. package/dist/scripts/src/components/Animation/AnimationNative.js +5 -1
  14. package/dist/scripts/src/components/AutoComplete/AutoComplete.js +1 -5
  15. package/dist/scripts/src/components/AutoComplete/AutoCompleteContext.js +2 -0
  16. package/dist/scripts/src/components/AutoComplete/AutoCompleteNative.js +263 -82
  17. package/dist/scripts/src/components/Form/FormNative.js +33 -25
  18. package/dist/scripts/src/components/Icon/IconNative.js +18 -15
  19. package/dist/scripts/src/components/NestedApp/AppWithCodeViewNative.js +1 -1
  20. package/dist/scripts/src/components/NumberBox/NumberBox.js +4 -4
  21. package/dist/scripts/src/components/NumberBox/NumberBox.spec.js +109 -426
  22. package/dist/scripts/src/components/NumberBox/NumberBoxNative.js +18 -4
  23. package/dist/scripts/src/components/Option/Option.js +3 -1
  24. package/dist/scripts/src/components/Select/HiddenOption.js +1 -1
  25. package/dist/scripts/src/components/Slider/Slider.spec.js +46 -13
  26. package/dist/scripts/src/components/Slider/SliderNative.js +19 -9
  27. package/dist/scripts/src/components/Tree/Tree-dynamic.spec.js +2894 -0
  28. package/dist/scripts/src/components/Tree/Tree.spec.js +2932 -0
  29. package/dist/scripts/src/components/Tree/TreeComponent.js +266 -10
  30. package/dist/scripts/src/components/Tree/TreeNative.js +1048 -23
  31. package/dist/scripts/src/components/Tree/testData.js +272 -0
  32. package/dist/scripts/src/components-core/behaviors/CoreBehaviors.js +1 -0
  33. package/dist/scripts/src/components-core/rendering/ComponentAdapter.js +13 -14
  34. package/dist/scripts/src/components-core/utils/treeUtils.js +187 -12
  35. package/dist/scripts/src/testing/ComponentDrivers.js +77 -3
  36. package/dist/scripts/src/testing/drivers/NumberBoxDriver.js +2 -2
  37. package/dist/scripts/src/testing/drivers/TreeDriver.js +13 -0
  38. package/dist/scripts/src/testing/fixtures.js +7 -2
  39. package/dist/standalone/xmlui-standalone.es.d.ts +4 -6
  40. package/dist/standalone/xmlui-standalone.umd.js +34 -34
  41. package/package.json +1 -1
  42. package/dist/scripts/src/components/Animation/Animation.js +0 -50
  43. package/dist/scripts/src/testing/drivers/SliderDriver.js +0 -20
@@ -86,6 +86,8 @@ exports.NumberBox = (0, react_1.forwardRef)(function NumberBox(_a, forwardedRef)
86
86
  // Ensure the provided minimum is not smaller than the 0 if zeroOrPositive is set to true
87
87
  min = Math.max(zeroOrPositive ? 0 : -numberbox_abstractions_1.NUMBERBOX_MAX_VALUE, min);
88
88
  // Step must be an integer since floating point arithmetic needs a deeper dive.
89
+ // probably some way to integrate with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
90
+ // since there are footguns, like 0.1 + 0.2 = 0.0000...04
89
91
  const _step = (_b = (0, numberbox_abstractions_1.toUsableNumber)(step, true)) !== null && _b !== void 0 ? _b : numberbox_abstractions_1.DEFAULT_STEP;
90
92
  const inputRef = (0, react_1.useRef)(null);
91
93
  const upButton = (0, react_1.useRef)(null);
@@ -414,10 +416,22 @@ exports.NumberBox = (0, react_1.forwardRef)(function NumberBox(_a, forwardedRef)
414
416
  if (!integersOnly && currentInputValue.endsWith(numberbox_abstractions_1.DECIMAL_SEPARATOR)) {
415
417
  // --- Add trailing zero if the value ends with decimal separator
416
418
  finalValue = currentInputValue + "0";
417
- // --- Update the input and state with the new value
418
- if (inputRef.current) {
419
- inputRef.current.value = finalValue;
419
+ }
420
+ // --- Convert to number and clamp to min/max bounds
421
+ const numericValue = (0, numberbox_abstractions_1.toUsableNumber)(finalValue, integersOnly);
422
+ if (!(0, numberbox_abstractions_1.isEmptyLike)(numericValue)) {
423
+ const clampedValue = (0, numberbox_abstractions_1.clamp)(numericValue, min, max);
424
+ if (clampedValue !== numericValue) {
425
+ const clampedString = clampedValue.toString();
426
+ finalValue = clampedString;
427
+ // --- Update the input field immediately
428
+ if (inputRef.current) {
429
+ inputRef.current.value = clampedString;
430
+ }
420
431
  }
432
+ }
433
+ // --- Update the state if the final value is different from current input
434
+ if (finalValue !== currentInputValue) {
421
435
  updateValue(finalValue, finalValue);
422
436
  }
423
437
  else {
@@ -425,7 +439,7 @@ exports.NumberBox = (0, react_1.forwardRef)(function NumberBox(_a, forwardedRef)
425
439
  setValueStrRep((0, numberbox_abstractions_1.mapToRepresentation)(value));
426
440
  }
427
441
  onBlur === null || onBlur === void 0 ? void 0 : onBlur();
428
- }, [value, onBlur, integersOnly, updateValue]);
442
+ }, [value, onBlur, integersOnly, updateValue, min, max]);
429
443
  const focus = (0, react_1.useCallback)(() => {
430
444
  var _a;
431
445
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
@@ -25,6 +25,8 @@ exports.OptionMd = (0, metadata_helpers_1.createMetadata)({
25
25
  valueType: "boolean",
26
26
  defaultValue: OptionNative_1.defaultProps.enabled,
27
27
  },
28
+ keywords: (0, metadata_helpers_1.d)("An array of keywords that can be used for searching and filtering the option. " +
29
+ "These keywords are not displayed but help users find the option through search."),
28
30
  },
29
31
  });
30
32
  exports.optionComponentRenderer = (0, renderers_1.createComponentRenderer)(COMP, exports.OptionMd, ({ node, extractValue, className, renderChild, layoutContext }) => {
@@ -36,7 +38,7 @@ exports.optionComponentRenderer = (0, renderers_1.createComponentRenderer)(COMP,
36
38
  }
37
39
  const hasTextNodeChild = ((_a = node.children) === null || _a === void 0 ? void 0 : _a.length) === 1 && (node.children[0].type === "TextNode" || node.children[0].type === "TextNodeCData");
38
40
  const textNodeChild = hasTextNodeChild ? renderChild(node.children) : undefined;
39
- return ((0, jsx_runtime_1.jsx)(OptionNative_1.OptionNative, { label: label || textNodeChild, value: value !== undefined && value !== "" ? value : label, enabled: extractValue.asOptionalBoolean(node.props.enabled), className: className, optionRenderer: ((_b = node.children) === null || _b === void 0 ? void 0 : _b.length) > 0
41
+ return ((0, jsx_runtime_1.jsx)(OptionNative_1.OptionNative, { label: label || textNodeChild, value: value !== undefined && value !== "" ? value : label, enabled: extractValue.asOptionalBoolean(node.props.enabled), keywords: extractValue.asOptionalStringArray(node.props.keywords), className: className, optionRenderer: ((_b = node.children) === null || _b === void 0 ? void 0 : _b.length) > 0
40
42
  ? !hasTextNodeChild ? (contextVars) => ((0, jsx_runtime_1.jsx)(container_helpers_1.MemoizedItem, { node: node.children, renderChild: renderChild, contextVars: contextVars, layoutContext: layoutContext })) : undefined
41
43
  : undefined, children: !hasTextNodeChild && renderChild(node.children) }));
42
44
  });
@@ -10,7 +10,7 @@ function HiddenOption(option) {
10
10
  const [node, setNode] = (0, react_1.useState)(null);
11
11
  const opt = (0, react_1.useMemo)(() => {
12
12
  var _a, _b;
13
- return Object.assign(Object.assign({}, option), { label: (_a = label !== null && label !== void 0 ? label : node === null || node === void 0 ? void 0 : node.textContent) !== null && _a !== void 0 ? _a : "", keywords: [(_b = label !== null && label !== void 0 ? label : node === null || node === void 0 ? void 0 : node.textContent) !== null && _b !== void 0 ? _b : ""] });
13
+ return Object.assign(Object.assign({}, option), { label: (_a = label !== null && label !== void 0 ? label : node === null || node === void 0 ? void 0 : node.textContent) !== null && _a !== void 0 ? _a : "", keywords: option.keywords || [(_b = label !== null && label !== void 0 ? label : node === null || node === void 0 ? void 0 : node.textContent) !== null && _b !== void 0 ? _b : ""] });
14
14
  }, [option, node, label]);
15
15
  (0, react_1.useEffect)(() => {
16
16
  onOptionAdd(opt);
@@ -141,29 +141,62 @@ fixtures_1.test.describe("Basic Functionality", () => {
141
141
  yield slider.press("ArrowRight");
142
142
  yield (0, fixtures_1.expect)(page.getByTestId("slider-value")).toHaveText("0.1");
143
143
  }));
144
- fixtures_1.test.fixme("minStepsBetweenThumbs maintains thumb separation", component_test_helpers_1.SKIP_REASON.TO_BE_IMPLEMENTED("Need to test actual thumb separation logic"), (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
145
- yield initTestBed(`<Slider initialValue="{[2, 7]}" minStepsBetweenThumbs="5" />`);
146
- // Test that thumbs maintain minimum separation
147
- yield (0, fixtures_1.expect)(page.getByRole("slider")).toBeVisible();
144
+ (0, fixtures_1.test)("component handles multiple thumbs", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
145
+ yield initTestBed(`<Slider initialValue="{[2, 4]}" />`);
146
+ const thumbs = page.getByRole("slider");
147
+ yield (0, fixtures_1.expect)(thumbs).toHaveCount(2);
148
+ }));
149
+ (0, fixtures_1.test)("all thumbs are interactable via mouse", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createSliderDriver, page, }) {
150
+ yield initTestBed(`
151
+ <Fragment>
152
+ <Slider id="slider" initialValue="{[2, 4]}" minValue="0" maxValue="10" />
153
+ <Text testId="sliderValue0">{slider.value[0]}</Text>
154
+ <Text testId="sliderValue1">{slider.value[1]}</Text>
155
+ </Fragment>
156
+ `);
157
+ const driver = yield createSliderDriver("slider");
158
+ yield driver.dragThumbByMouse("start", 0);
159
+ yield driver.dragThumbByMouse("end", 1);
160
+ yield (0, fixtures_1.expect)(page.getByTestId("sliderValue0")).toHaveText("0");
161
+ yield (0, fixtures_1.expect)(page.getByTestId("sliderValue1")).toHaveText("10");
162
+ }));
163
+ (0, fixtures_1.test)("all thumbs are interactable via keyboard", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createSliderDriver, page }) {
164
+ yield initTestBed(`
165
+ <Fragment>
166
+ <Slider id="slider" initialValue="{[2, 4]}" minValue="0" maxValue="10" />
167
+ <Text testId="sliderValue0">{slider.value[0]}</Text>
168
+ <Text testId="sliderValue1">{slider.value[1]}</Text>
169
+ </Fragment>
170
+ `);
171
+ const driver = yield createSliderDriver("slider");
172
+ yield driver.stepThumbByKeyboard("ArrowLeft", 0);
173
+ yield driver.stepThumbByKeyboard("ArrowRight", 1);
174
+ yield (0, fixtures_1.expect)(page.getByTestId("sliderValue0")).toHaveText("1");
175
+ yield (0, fixtures_1.expect)(page.getByTestId("sliderValue1")).toHaveText("5");
176
+ }));
177
+ (0, fixtures_1.test)("minStepsBetweenThumbs maintains thumb separation", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, createSliderDriver, page }) {
178
+ yield initTestBed(`
179
+ <Fragment>
180
+ <Slider id="slider" initialValue="{[0, 5]}" minStepsBetweenThumbs="3" minValue="0" maxValue="10" />
181
+ <Text testId="sliderValue1">{slider.value[1]}</Text>
182
+ </Fragment>
183
+ `);
184
+ const driver = yield createSliderDriver("slider");
185
+ yield driver.stepThumbByKeyboard("ArrowLeft", 1, 3); // Try to move left by 3 steps
186
+ yield (0, fixtures_1.expect)(page.getByTestId("sliderValue1")).toHaveText("3");
148
187
  }));
149
188
  (0, fixtures_1.test)("enabled=false disables control", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
150
189
  yield initTestBed(`<Slider enabled="false" />`);
151
190
  yield (0, fixtures_1.expect)(page.getByRole("slider")).toBeDisabled();
152
191
  }));
153
- (0, fixtures_1.test)("readOnly prevents interaction", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
192
+ (0, fixtures_1.test)("readOnly prevents interaction", (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page, createSliderDriver }) {
154
193
  yield initTestBed(`
155
194
  <Fragment>
156
195
  <Slider id="mySlider" readOnly="true" />
157
196
  <Text testId="slider-value" value="{mySlider.value}" />
158
197
  </Fragment>`);
159
- const slider = page.getByRole("slider");
160
- const sliderOffsetWidth = yield page.locator("[data-track]").evaluate((el) => {
161
- return el.getBoundingClientRect().width;
162
- });
163
- yield slider.hover();
164
- yield page.mouse.down({ button: "left" });
165
- yield page.mouse.move(sliderOffsetWidth, 0); // Attempt to drag to end
166
- yield page.mouse.up();
198
+ const driver = yield createSliderDriver("mySlider");
199
+ yield driver.dragThumbByMouse("end");
167
200
  yield (0, fixtures_1.expect)(page.getByTestId("slider-value")).toHaveText("0"); // Value should remain unchanged
168
201
  }));
169
202
  fixtures_1.test.fixme("autoFocus focuses slider on mount", component_test_helpers_1.SKIP_REASON.XMLUI_BUG("autoFocus does not seem to work with radix-ui, need to double-check"), (_a) => __awaiter(void 0, [_a], void 0, function* ({ initTestBed, page }) {
@@ -108,7 +108,7 @@ exports.Slider = (0, react_2.forwardRef)((_a, forwardedRef) => {
108
108
  id = id || _id;
109
109
  const inputRef = (0, react_1.useRef)(null);
110
110
  const tooltipRef = (0, react_1.useRef)(null);
111
- const thumbRef = (0, react_1.useRef)(null);
111
+ const thumbsRef = (0, react_1.useRef)([]);
112
112
  min = parseValue(min, exports.defaultProps.min);
113
113
  max = parseValue(max, exports.defaultProps.max);
114
114
  // Initialize localValue properly
@@ -181,18 +181,22 @@ exports.Slider = (0, react_2.forwardRef)((_a, forwardedRef) => {
181
181
  }, [updateValue, readOnly]);
182
182
  // Component APIs
183
183
  const handleOnFocus = (0, react_1.useCallback)((ev) => {
184
- var _a;
185
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
184
+ onShowTooltip();
186
185
  onFocus === null || onFocus === void 0 ? void 0 : onFocus(ev);
187
- }, [onFocus]);
186
+ }, [onFocus, onShowTooltip]);
188
187
  const handleOnBlur = (0, react_1.useCallback)((ev) => {
189
- var _a;
190
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
191
188
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(ev);
192
189
  }, [onBlur]);
193
190
  const focus = (0, react_1.useCallback)(() => {
194
191
  var _a;
195
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
192
+ // Focus the first available thumb
193
+ const firstThumb = thumbsRef.current.find(thumb => thumb !== null);
194
+ if (firstThumb) {
195
+ firstThumb.focus();
196
+ }
197
+ else {
198
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
199
+ }
196
200
  }, []);
197
201
  const setValue = (0, misc_1.useEvent)((newValue) => {
198
202
  if (readOnly || !enabled) {
@@ -210,6 +214,10 @@ exports.Slider = (0, react_2.forwardRef)((_a, forwardedRef) => {
210
214
  }, [focus, registerComponentApi, setValue]);
211
215
  // Ensure we always have at least one thumb
212
216
  const displayValue = localValue.length > 0 ? localValue : formatValue(undefined, min, min, max);
217
+ // Clean up thumbs ref array when number of thumbs changes
218
+ (0, react_1.useEffect)(() => {
219
+ thumbsRef.current = thumbsRef.current.slice(0, displayValue.length);
220
+ }, [displayValue.length]);
213
221
  return ((0, jsx_runtime_1.jsx)(ItemWithLabel_1.ItemWithLabel, Object.assign({}, rest, { labelPosition: labelPosition, label: label, labelWidth: labelWidth, labelBreak: labelBreak, required: required, enabled: enabled, onFocus: onFocus, onBlur: onBlur, style: style, className: className, ref: forwardedRef, id: id, isInputTemplateUsed: true, children: (0, jsx_runtime_1.jsx)("div", { className: Slider_module_scss_1.default.sliderContainer, "data-slider-container": true, children: (0, jsx_runtime_1.jsxs)(react_slider_1.Root, { minStepsBetweenThumbs: minStepsBetweenThumbs, ref: inputRef, tabIndex: tabIndex, "aria-readonly": readOnly, className: (0, classnames_1.default)(className, Slider_module_scss_1.default.sliderRoot, {
214
222
  [Slider_module_scss_1.default.disabled]: !enabled,
215
223
  [Slider_module_scss_1.default.readOnly]: readOnly,
@@ -221,8 +229,10 @@ exports.Slider = (0, react_2.forwardRef)((_a, forwardedRef) => {
221
229
  [Slider_module_scss_1.default.valid]: validationStatus === "valid",
222
230
  }), style: rangeStyle ? Object.assign({}, rangeStyle) : undefined, children: (0, jsx_runtime_1.jsx)(react_slider_1.Range, { "data-range": true, className: (0, classnames_1.default)(Slider_module_scss_1.default.sliderRange, {
223
231
  [Slider_module_scss_1.default.disabled]: !enabled,
224
- }) }) }), displayValue.map((_, index) => ((0, jsx_runtime_1.jsx)(TooltipNative_1.Tooltip, { ref: tooltipRef, text: valueFormat(displayValue[index]), delayDuration: 100, open: showValues && showTooltip, children: (0, jsx_runtime_1.jsx)(react_slider_1.Thumb, { id: id, "aria-required": required, ref: index === 0 ? thumbRef : null, className: (0, classnames_1.default)(Slider_module_scss_1.default.sliderThumb, {
232
+ }) }) }), displayValue.map((_, index) => ((0, jsx_runtime_1.jsx)(TooltipNative_1.Tooltip, { ref: tooltipRef, text: valueFormat(displayValue[index]), delayDuration: 100, open: showValues && showTooltip, children: (0, jsx_runtime_1.jsx)(react_slider_1.Thumb, { id: id, "aria-required": required, ref: (el) => {
233
+ thumbsRef.current[index] = el;
234
+ }, className: (0, classnames_1.default)(Slider_module_scss_1.default.sliderThumb, {
225
235
  [Slider_module_scss_1.default.disabled]: !enabled,
226
- }), style: thumbStyle ? Object.assign({}, thumbStyle) : undefined, "data-thumb-index": index, autoFocus: autoFocus }) }, index)))] }) }) })));
236
+ }), style: thumbStyle ? Object.assign({}, thumbStyle) : undefined, "data-thumb-index": index, autoFocus: autoFocus && index === 0 }) }, index)))] }) }) })));
227
237
  });
228
238
  exports.Slider.displayName = "Slider";