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.
- package/dist/lib/{index-axjeT2uJ.mjs → index-D4RYJasT.mjs} +2251 -575
- package/dist/lib/index.css +1 -1
- package/dist/lib/{initMock-BoTWMs19.mjs → initMock-qzTZlH-6.mjs} +1 -1
- package/dist/lib/xmlui-parser.d.ts +1 -1
- package/dist/lib/xmlui.d.ts +4 -6
- package/dist/lib/xmlui.mjs +1 -1
- package/dist/metadata/{collectedComponentMetadata-CQywuPDB.mjs → collectedComponentMetadata-BQaefK3f.mjs} +2536 -861
- package/dist/metadata/{initMock-Bi5kF5Af.mjs → initMock-Cz6QssI3.mjs} +1 -1
- package/dist/metadata/style.css +1 -1
- package/dist/metadata/xmlui-metadata.mjs +1 -1
- package/dist/metadata/xmlui-metadata.umd.js +3 -3
- package/dist/scripts/package.json +1 -1
- package/dist/scripts/src/components/Animation/AnimationNative.js +5 -1
- package/dist/scripts/src/components/AutoComplete/AutoComplete.js +1 -5
- package/dist/scripts/src/components/AutoComplete/AutoCompleteContext.js +2 -0
- package/dist/scripts/src/components/AutoComplete/AutoCompleteNative.js +263 -82
- package/dist/scripts/src/components/Form/FormNative.js +33 -25
- package/dist/scripts/src/components/Icon/IconNative.js +18 -15
- package/dist/scripts/src/components/NestedApp/AppWithCodeViewNative.js +1 -1
- package/dist/scripts/src/components/NumberBox/NumberBox.js +4 -4
- package/dist/scripts/src/components/NumberBox/NumberBox.spec.js +109 -426
- package/dist/scripts/src/components/NumberBox/NumberBoxNative.js +18 -4
- package/dist/scripts/src/components/Option/Option.js +3 -1
- package/dist/scripts/src/components/Select/HiddenOption.js +1 -1
- package/dist/scripts/src/components/Slider/Slider.spec.js +46 -13
- package/dist/scripts/src/components/Slider/SliderNative.js +19 -9
- package/dist/scripts/src/components/Tree/Tree-dynamic.spec.js +2894 -0
- package/dist/scripts/src/components/Tree/Tree.spec.js +2932 -0
- package/dist/scripts/src/components/Tree/TreeComponent.js +266 -10
- package/dist/scripts/src/components/Tree/TreeNative.js +1048 -23
- package/dist/scripts/src/components/Tree/testData.js +272 -0
- package/dist/scripts/src/components-core/behaviors/CoreBehaviors.js +1 -0
- package/dist/scripts/src/components-core/rendering/ComponentAdapter.js +13 -14
- package/dist/scripts/src/components-core/utils/treeUtils.js +187 -12
- package/dist/scripts/src/testing/ComponentDrivers.js +77 -3
- package/dist/scripts/src/testing/drivers/NumberBoxDriver.js +2 -2
- package/dist/scripts/src/testing/drivers/TreeDriver.js +13 -0
- package/dist/scripts/src/testing/fixtures.js +7 -2
- package/dist/standalone/xmlui-standalone.es.d.ts +4 -6
- package/dist/standalone/xmlui-standalone.umd.js +34 -34
- package/package.json +1 -1
- package/dist/scripts/src/components/Animation/Animation.js +0 -50
- 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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
145
|
-
yield initTestBed(`<Slider initialValue="{[2,
|
|
146
|
-
|
|
147
|
-
yield (0, fixtures_1.expect)(
|
|
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
|
|
160
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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";
|