cx 26.0.11 → 26.0.13
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/build/charts/ScatterGraph.d.ts +4 -4
- package/build/charts/ScatterGraph.js +2 -2
- package/build/data/ArrayElementView.spec.d.ts +1 -0
- package/build/data/ArrayElementView.spec.js +81 -0
- package/build/data/Binding.spec.d.ts +1 -0
- package/build/data/Binding.spec.js +61 -0
- package/build/data/Expression.spec.d.ts +1 -0
- package/build/data/Expression.spec.js +196 -0
- package/build/data/Grouper.spec.d.ts +1 -0
- package/build/data/Grouper.spec.js +48 -0
- package/build/data/Ref.spec.d.ts +1 -0
- package/build/data/Ref.spec.js +72 -0
- package/build/data/Selector.d.ts +1 -1
- package/build/data/Store.spec.d.ts +1 -0
- package/build/data/Store.spec.js +19 -0
- package/build/data/StoreRef.spec.d.ts +1 -0
- package/build/data/StoreRef.spec.js +22 -0
- package/build/data/StringTemplate.spec.d.ts +1 -0
- package/build/data/StringTemplate.spec.js +112 -0
- package/build/data/StructuredSelector.spec.d.ts +1 -0
- package/build/data/StructuredSelector.spec.js +102 -0
- package/build/data/View.spec.d.ts +1 -0
- package/build/data/View.spec.js +44 -0
- package/build/data/ZoomIntoPropertyView.spec.d.ts +1 -0
- package/build/data/ZoomIntoPropertyView.spec.js +54 -0
- package/build/data/comparer.spec.d.ts +1 -0
- package/build/data/comparer.spec.js +50 -0
- package/build/data/computable.d.ts +3 -6
- package/build/data/computable.spec.d.ts +1 -0
- package/build/data/computable.spec.js +56 -0
- package/build/data/createAccessorModelProxy.d.ts +5 -3
- package/build/data/createAccessorModelProxy.spec.d.ts +1 -0
- package/build/data/createAccessorModelProxy.spec.js +30 -0
- package/build/data/createStructuredSelector.spec.d.ts +1 -0
- package/build/data/createStructuredSelector.spec.js +42 -0
- package/build/data/diff/diffs.spec.d.ts +1 -0
- package/build/data/diff/diffs.spec.js +45 -0
- package/build/data/getAccessor.spec.d.ts +1 -0
- package/build/data/getAccessor.spec.js +10 -0
- package/build/data/getSelector.spec.d.ts +1 -0
- package/build/data/getSelector.spec.js +36 -0
- package/build/data/ops/append.spec.d.ts +1 -0
- package/build/data/ops/append.spec.js +24 -0
- package/build/data/ops/filter.spec.d.ts +1 -0
- package/build/data/ops/filter.spec.js +25 -0
- package/build/data/ops/findTreeNode.d.ts +1 -1
- package/build/data/ops/findTreeNode.js +1 -1
- package/build/data/ops/findTreeNode.spec.d.ts +1 -0
- package/build/data/ops/findTreeNode.spec.js +20 -0
- package/build/data/ops/findTreePath.d.ts +1 -1
- package/build/data/ops/merge.spec.d.ts +1 -0
- package/build/data/ops/merge.spec.js +23 -0
- package/build/data/ops/removeTreeNodes.d.ts +1 -1
- package/build/data/ops/removeTreeNodes.js +1 -1
- package/build/data/ops/removeTreeNodes.spec.d.ts +1 -0
- package/build/data/ops/removeTreeNodes.spec.js +35 -0
- package/build/data/ops/updateArray.spec.d.ts +1 -0
- package/build/data/ops/updateArray.spec.js +33 -0
- package/build/data/ops/updateTree.d.ts +1 -1
- package/build/data/ops/updateTree.spec.d.ts +1 -0
- package/build/data/ops/updateTree.spec.js +44 -0
- package/build/hooks/invokeCallback.spec.d.ts +1 -0
- package/build/hooks/invokeCallback.spec.js +44 -0
- package/build/hooks/resolveCallback.spec.d.ts +1 -0
- package/build/hooks/resolveCallback.spec.js +35 -0
- package/build/hooks/store.spec.d.ts +1 -0
- package/build/hooks/store.spec.js +48 -0
- package/build/hooks/useTrigger.spec.d.ts +1 -0
- package/build/hooks/useTrigger.spec.js +59 -0
- package/build/jsx-runtime.d.ts +10 -10
- package/build/jsx-runtime.js +6 -0
- package/build/svg/util/Rect.d.ts +1 -1
- package/build/ui/ContentResolver.d.ts +16 -6
- package/build/ui/Controller.d.ts +7 -0
- package/build/ui/Controller.js +2 -1
- package/build/ui/Controller.spec.d.ts +1 -0
- package/build/ui/Controller.spec.js +247 -0
- package/build/ui/Cx.spec.d.ts +1 -0
- package/build/ui/Cx.spec.js +153 -0
- package/build/ui/DataProxy.spec.d.ts +1 -0
- package/build/ui/DataProxy.spec.js +208 -0
- package/build/ui/Instance.d.ts +1 -1
- package/build/ui/Instance.js +10 -10
- package/build/ui/IsolatedScope.spec.d.ts +1 -0
- package/build/ui/IsolatedScope.spec.js +42 -0
- package/build/ui/Prop.d.ts +12 -1
- package/build/ui/PureContainer.spec.d.ts +1 -0
- package/build/ui/PureContainer.spec.js +149 -0
- package/build/ui/Repeater.d.ts +3 -3
- package/build/ui/Repeater.spec.d.ts +1 -0
- package/build/ui/Repeater.spec.js +109 -0
- package/build/ui/Rescope.spec.d.ts +1 -0
- package/build/ui/Rescope.spec.js +134 -0
- package/build/ui/Restate.spec.d.ts +1 -0
- package/build/ui/Restate.spec.js +257 -0
- package/build/ui/Text.d.ts +14 -2
- package/build/ui/Text.js +3 -0
- package/build/ui/adapter/ArrayAdapter.js +4 -1
- package/build/ui/adapter/ArrayAdapter.spec.d.ts +1 -0
- package/build/ui/adapter/ArrayAdapter.spec.js +44 -0
- package/build/ui/adapter/TreeAdapter.spec.d.ts +1 -0
- package/build/ui/adapter/TreeAdapter.spec.js +71 -0
- package/build/ui/app/Url.spec.d.ts +1 -0
- package/build/ui/app/Url.spec.js +43 -0
- package/build/ui/app/startHotAppLoop.js +1 -1
- package/build/ui/createFunctionalComponent.d.ts +14 -1
- package/build/ui/createFunctionalComponent.js +7 -4
- package/build/ui/createFunctionalComponent.spec.d.ts +1 -0
- package/build/ui/createFunctionalComponent.spec.js +272 -0
- package/build/ui/expr.d.ts +3 -1
- package/build/ui/exprHelpers.d.ts +32 -0
- package/build/ui/exprHelpers.js +61 -0
- package/build/ui/index.d.ts +1 -0
- package/build/ui/index.js +1 -0
- package/build/ui/layout/ContentPlaceholder.spec.d.ts +1 -0
- package/build/ui/layout/ContentPlaceholder.spec.js +333 -0
- package/build/ui/layout/FirstVisibleChildLayout.spec.d.ts +1 -0
- package/build/ui/layout/FirstVisibleChildLayout.spec.js +101 -0
- package/build/ui/selection/KeySelection.d.ts +0 -8
- package/build/ui/selection/Selection.d.ts +9 -3
- package/build/util/Console.d.ts +1 -0
- package/build/util/Console.js +7 -3
- package/build/util/Format.spec.d.ts +1 -0
- package/build/util/Format.spec.js +58 -0
- package/build/util/TraversalStack.spec.d.ts +1 -0
- package/build/util/TraversalStack.spec.js +43 -0
- package/build/util/date/upperBoundCheck.spec.d.ts +1 -0
- package/build/util/date/upperBoundCheck.spec.js +22 -0
- package/build/util/getSearchQueryPredicate.spec.d.ts +1 -0
- package/build/util/getSearchQueryPredicate.spec.js +33 -0
- package/build/util/isValidIdentifierName.spec.d.ts +1 -0
- package/build/util/isValidIdentifierName.spec.js +28 -0
- package/build/util/routeAppend.spec.d.ts +1 -0
- package/build/util/routeAppend.spec.js +14 -0
- package/build/widgets/AccessorBindings.spec.d.ts +1 -0
- package/build/widgets/AccessorBindings.spec.js +40 -0
- package/build/widgets/Button.d.ts +3 -6
- package/build/widgets/Button.js +1 -1
- package/build/widgets/DocumentTitle.d.ts +2 -0
- package/build/widgets/Heading.d.ts +2 -2
- package/build/widgets/HtmlElement.d.ts +33 -8
- package/build/widgets/HtmlElement.js +7 -9
- package/build/widgets/HtmlElement.spec.d.ts +1 -0
- package/build/widgets/HtmlElement.spec.js +38 -0
- package/build/widgets/Icon.d.ts +3 -13
- package/build/widgets/List.d.ts +4 -0
- package/build/widgets/ReactElementWrapper.d.ts +29 -0
- package/build/widgets/ReactElementWrapper.js +59 -0
- package/build/widgets/drag-drop/DragSource.d.ts +3 -3
- package/build/widgets/drag-drop/DragSource.js +2 -3
- package/build/widgets/drag-drop/DropZone.d.ts +3 -3
- package/build/widgets/drag-drop/DropZone.js +2 -3
- package/build/widgets/form/Checkbox.d.ts +2 -0
- package/build/widgets/form/ColorField.d.ts +2 -0
- package/build/widgets/form/DateTimeField.d.ts +2 -0
- package/build/widgets/form/Field.d.ts +0 -2
- package/build/widgets/form/LabeledContainer.d.ts +9 -8
- package/build/widgets/form/LabeledContainer.js +9 -9
- package/build/widgets/form/LookupField.d.ts +57 -9
- package/build/widgets/form/MonthField.d.ts +2 -0
- package/build/widgets/form/NumberField.d.ts +2 -0
- package/build/widgets/form/Radio.d.ts +2 -0
- package/build/widgets/form/Select.d.ts +2 -0
- package/build/widgets/form/Slider.d.ts +3 -0
- package/build/widgets/form/Switch.d.ts +2 -0
- package/build/widgets/form/TextField.d.ts +34 -0
- package/build/widgets/form/TimeList.d.ts +16 -1
- package/build/widgets/form/TimeList.js +34 -62
- package/build/widgets/form/UploadButton.d.ts +34 -2
- package/build/widgets/form/UploadButton.js +3 -1
- package/build/widgets/form/ValidationGroup.spec.d.ts +1 -0
- package/build/widgets/form/ValidationGroup.spec.js +62 -0
- package/build/widgets/form/Validator.d.ts +33 -2
- package/build/widgets/form/Validator.js +3 -0
- package/build/widgets/grid/Grid.d.ts +9 -9
- package/build/widgets/grid/TreeNode.d.ts +6 -0
- package/build/widgets/index.d.ts +1 -0
- package/build/widgets/index.js +1 -0
- package/build/widgets/nav/MenuItem.d.ts +3 -2
- package/build/widgets/nav/Route.spec.d.ts +1 -0
- package/build/widgets/nav/Route.spec.js +15 -0
- package/build/widgets/nav/Scroller.d.ts +4 -6
- package/build/widgets/nav/Scroller.js +6 -3
- package/build/widgets/nav/Tab.d.ts +2 -2
- package/build/widgets/overlay/ContextMenu.d.ts +3 -3
- package/build/widgets/overlay/Overlay.d.ts +2 -1
- package/build/widgets/overlay/Overlay.js +1 -1
- package/build.js +133 -133
- package/dist/data.js +2 -2
- package/dist/jsx-runtime.js +6 -1
- package/dist/manifest.d.ts +1443 -0
- package/dist/manifest.js +852 -804
- package/dist/ui.js +91 -5
- package/dist/util.js +3 -0
- package/dist/widgets.js +520 -161
- package/package.json +46 -20
- package/src/charts/Chart.ts +108 -108
- package/src/charts/ScatterGraph.tsx +6 -6
- package/src/data/ArrayElementView.ts +90 -90
- package/src/data/AugmentedViewBase.ts +88 -88
- package/src/data/Binding.ts +104 -104
- package/src/data/ExposedRecordView.ts +95 -95
- package/src/data/ExposedValueView.ts +89 -89
- package/src/data/Expression.spec.ts +229 -229
- package/src/data/Expression.ts +233 -233
- package/src/data/Grouper.spec.ts +57 -57
- package/src/data/Grouper.ts +158 -158
- package/src/data/NestedDataView.ts +43 -43
- package/src/data/ReadOnlyDataView.ts +39 -39
- package/src/data/Ref.ts +104 -104
- package/src/data/Selector.ts +10 -10
- package/src/data/Store.ts +52 -52
- package/src/data/StoreProxy.ts +19 -19
- package/src/data/StoreRef.ts +66 -66
- package/src/data/StringTemplate.spec.ts +132 -132
- package/src/data/StringTemplate.ts +93 -93
- package/src/data/StructuredSelector.spec.ts +113 -113
- package/src/data/StructuredSelector.ts +146 -146
- package/src/data/SubscribableView.ts +63 -63
- package/src/data/ZoomIntoPropertyView.spec.ts +64 -64
- package/src/data/ZoomIntoPropertyView.ts +45 -45
- package/src/data/computable.spec.ts +87 -62
- package/src/data/computable.ts +3 -6
- package/src/data/createAccessorModelProxy.spec.tsx +102 -1
- package/src/data/createAccessorModelProxy.ts +9 -3
- package/src/data/createStructuredSelector.ts +62 -62
- package/src/data/getAccessor.spec.ts +11 -11
- package/src/data/getAccessor.ts +74 -74
- package/src/data/getSelector.spec.ts +43 -43
- package/src/data/getSelector.ts +66 -66
- package/src/data/ops/filter.spec.ts +35 -35
- package/src/data/ops/filter.ts +9 -9
- package/src/data/ops/findTreeNode.ts +1 -5
- package/src/data/ops/findTreePath.ts +1 -1
- package/src/data/ops/merge.ts +13 -13
- package/src/data/ops/removeTreeNodes.spec.ts +37 -37
- package/src/data/ops/removeTreeNodes.ts +2 -2
- package/src/data/ops/updateArray.spec.ts +69 -69
- package/src/data/ops/updateArray.ts +31 -31
- package/src/data/ops/updateTree.ts +1 -1
- package/src/data/test-types.ts +7 -7
- package/src/hooks/resolveCallback.spec.tsx +30 -7
- package/src/hooks/useTrigger.ts +26 -26
- package/src/index.scss +6 -6
- package/src/jsx-dev-runtime.ts +4 -4
- package/src/jsx-runtime.spec.tsx +402 -0
- package/src/jsx-runtime.ts +26 -22
- package/src/svg/BoundedObject.ts +101 -101
- package/src/svg/util/Rect.ts +105 -105
- package/src/ui/CSSHelper.ts +17 -17
- package/src/ui/ContentResolver.spec.tsx +172 -19
- package/src/ui/ContentResolver.ts +16 -8
- package/src/ui/Controller.ts +15 -2
- package/src/ui/Culture.ts +159 -159
- package/src/ui/DataProxy.ts +55 -55
- package/src/ui/FocusManager.ts +171 -171
- package/src/ui/Instance.ts +866 -868
- package/src/ui/Prop.ts +140 -112
- package/src/ui/RenderingContext.ts +99 -99
- package/src/ui/Repeater.ts +3 -12
- package/src/ui/Rescope.ts +49 -49
- package/src/ui/StructuredInstanceDataAccessor.ts +32 -32
- package/src/ui/Text.ts +21 -2
- package/src/ui/VDOM.ts +34 -34
- package/src/ui/adapter/ArrayAdapter.spec.ts +55 -55
- package/src/ui/adapter/ArrayAdapter.ts +4 -1
- package/src/ui/adapter/TreeAdapter.spec.ts +76 -76
- package/src/ui/adapter/TreeAdapter.ts +185 -185
- package/src/ui/app/History.ts +133 -133
- package/src/ui/app/Url.spec.ts +50 -50
- package/src/ui/app/startHotAppLoop.ts +41 -41
- package/src/ui/createFunctionalComponent.spec.tsx +53 -0
- package/src/ui/createFunctionalComponent.ts +86 -65
- package/src/ui/expr.ts +4 -1
- package/src/ui/exprHelpers.spec.ts +379 -0
- package/src/ui/exprHelpers.ts +78 -0
- package/src/ui/index.ts +47 -46
- package/src/ui/layout/Content.ts +30 -30
- package/src/ui/layout/FirstVisibleChildLayout.spec.tsx +1 -1
- package/src/ui/layout/FirstVisibleChildLayout.ts +60 -60
- package/src/ui/selection/KeySelection.ts +0 -12
- package/src/ui/selection/PropertySelection.ts +87 -87
- package/src/ui/selection/Selection.ts +13 -3
- package/src/util/Console.ts +13 -11
- package/src/util/Format.ts +267 -267
- package/src/util/addEventListenerWithOptions.ts +41 -41
- package/src/util/browserSupportsPassiveEventHandlers.ts +20 -20
- package/src/util/color/rgbToHsl.ts +35 -35
- package/src/util/getActiveElement.ts +4 -4
- package/src/util/hasKey.ts +18 -18
- package/src/util/index.ts +55 -55
- package/src/util/innerTextTrim.ts +10 -10
- package/src/util/isArray.ts +3 -3
- package/src/util/isDataRecord.ts +5 -5
- package/src/util/isDefined.ts +3 -3
- package/src/util/isString.ts +3 -3
- package/src/widgets/AccessorBindings.spec.tsx +26 -0
- package/src/widgets/Button.tsx +5 -17
- package/src/widgets/DocumentTitle.ts +95 -92
- package/src/widgets/Heading.ts +2 -2
- package/src/widgets/HtmlElement.spec.helpers.tsx +108 -0
- package/src/widgets/HtmlElement.spec.tsx +20 -12
- package/src/widgets/HtmlElement.tsx +82 -24
- package/src/widgets/Icon.ts +3 -17
- package/src/widgets/List.tsx +6 -0
- package/src/widgets/ReactElementWrapper.spec.tsx +452 -0
- package/src/widgets/ReactElementWrapper.tsx +108 -0
- package/src/widgets/Sandbox.ts +103 -103
- package/src/widgets/autoFocus.ts +9 -9
- package/src/widgets/cx.ts +63 -63
- package/src/widgets/drag-drop/DragSource.tsx +3 -4
- package/src/widgets/drag-drop/DropZone.tsx +3 -4
- package/src/widgets/form/Checkbox.tsx +3 -0
- package/src/widgets/form/ColorField.tsx +3 -0
- package/src/widgets/form/DateTimeField.tsx +5 -0
- package/src/widgets/form/Field.tsx +0 -3
- package/src/widgets/form/Label.tsx +1 -0
- package/src/widgets/form/LabeledContainer.ts +22 -26
- package/src/widgets/form/LookupField.spec.tsx +93 -0
- package/src/widgets/form/LookupField.tsx +104 -9
- package/src/widgets/form/MonthField.tsx +5 -0
- package/src/widgets/form/NumberField.tsx +3 -0
- package/src/widgets/form/Radio.tsx +5 -0
- package/src/widgets/form/Select.tsx +5 -0
- package/src/widgets/form/Slider.tsx +4 -0
- package/src/widgets/form/Switch.tsx +3 -0
- package/src/widgets/form/TextField.tsx +62 -0
- package/src/widgets/form/TimeList.tsx +84 -73
- package/src/widgets/form/UploadButton.tsx +53 -2
- package/src/widgets/form/Validator.ts +40 -3
- package/src/widgets/grid/Grid.tsx +9 -12
- package/src/widgets/grid/GridCell.ts +143 -143
- package/src/widgets/grid/TreeNode.tsx +9 -0
- package/src/widgets/icons/calendar.tsx +17 -17
- package/src/widgets/icons/check.tsx +13 -13
- package/src/widgets/icons/clear.tsx +15 -15
- package/src/widgets/icons/close.tsx +20 -20
- package/src/widgets/icons/cx.tsx +38 -38
- package/src/widgets/icons/drop-down.tsx +15 -15
- package/src/widgets/icons/file.tsx +13 -13
- package/src/widgets/icons/folder-open.tsx +15 -15
- package/src/widgets/icons/folder.tsx +13 -13
- package/src/widgets/icons/forward.tsx +22 -22
- package/src/widgets/icons/loading.tsx +24 -24
- package/src/widgets/icons/menu.tsx +17 -17
- package/src/widgets/icons/pixel-picker.tsx +18 -18
- package/src/widgets/icons/search.tsx +13 -13
- package/src/widgets/icons/sort-asc.tsx +14 -14
- package/src/widgets/icons/square.tsx +18 -18
- package/src/widgets/index.ts +1 -0
- package/src/widgets/nav/MenuItem.tsx +3 -2
- package/src/widgets/nav/Route.ts +142 -142
- package/src/widgets/nav/Scroller.tsx +8 -9
- package/src/widgets/nav/Tab.ts +2 -2
- package/src/widgets/overlay/ContextMenu.ts +42 -42
- package/src/widgets/overlay/Dropdown.tsx +762 -762
- package/src/widgets/overlay/MsgBox.tsx +141 -141
- package/src/widgets/overlay/Overlay.tsx +5 -4
- package/src/widgets/overlay/Toast.ts +111 -111
- package/src/widgets/overlay/Window.tsx +299 -299
- package/src/widgets/overlay/alerts.ts +46 -46
- package/src/widgets/overlay/captureMouse.ts +195 -195
- package/src/widgets/overlay/createHotPromiseWindowFactory.ts +72 -72
- package/src/widgets/overlay/index.d.ts +11 -11
- package/src/widgets/overlay/index.ts +11 -11
- package/src/widgets/overlay/tooltip-ops.ts +173 -173
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { Store } from "../data/Store";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
import { createTestRenderer } from "../util/test/createTestRenderer";
|
|
4
|
+
import { VDOM } from "../ui/Widget";
|
|
5
|
+
import { act } from "react-test-renderer";
|
|
6
|
+
import {
|
|
7
|
+
ReactFunctionComponent,
|
|
8
|
+
ReactCounterComponent,
|
|
9
|
+
ReactClassComponent,
|
|
10
|
+
ReactPureComponent,
|
|
11
|
+
ReactRefEffectComponent,
|
|
12
|
+
ReactEffectStateComponent,
|
|
13
|
+
ReactPropsComponent,
|
|
14
|
+
} from "./HtmlElement.spec.helpers";
|
|
15
|
+
import { Controller } from "../ui/Controller";
|
|
16
|
+
import { createAccessorModelProxy } from "../data/createAccessorModelProxy";
|
|
17
|
+
import { ReactElementWrapper } from "./ReactElementWrapper";
|
|
18
|
+
|
|
19
|
+
describe("ReactElementWrapper", () => {
|
|
20
|
+
it("renders React components as tag", () => {
|
|
21
|
+
class MyReactComponent extends VDOM.Component<any> {
|
|
22
|
+
render() {
|
|
23
|
+
return VDOM.createElement("div", { className: "my-component" }, this.props.children);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let store = new Store();
|
|
28
|
+
|
|
29
|
+
const component = createTestRenderer(
|
|
30
|
+
store,
|
|
31
|
+
<cx>
|
|
32
|
+
<MyReactComponent>
|
|
33
|
+
<span>Child content</span>
|
|
34
|
+
</MyReactComponent>
|
|
35
|
+
</cx>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
let tree = component.toJSON();
|
|
39
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
40
|
+
assert.equal(tree.type, "div");
|
|
41
|
+
assert.equal(tree.props.className, "my-component");
|
|
42
|
+
assert(tree.children && tree.children.length === 1, "Expected one child");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("renders React function components with props", () => {
|
|
46
|
+
let store = new Store();
|
|
47
|
+
|
|
48
|
+
const component = createTestRenderer(
|
|
49
|
+
store,
|
|
50
|
+
<cx>
|
|
51
|
+
<ReactFunctionComponent title="Test Title">
|
|
52
|
+
<span>Child content</span>
|
|
53
|
+
</ReactFunctionComponent>
|
|
54
|
+
</cx>,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
let tree = component.toJSON();
|
|
58
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
59
|
+
assert.equal(tree.type, "div");
|
|
60
|
+
assert.equal(tree.props.className, "react-function-component");
|
|
61
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (h3 and div)");
|
|
62
|
+
|
|
63
|
+
let h3 = tree.children[0] as any;
|
|
64
|
+
assert.equal(h3.type, "h3");
|
|
65
|
+
assert.deepEqual(h3.children, ["Test Title"]);
|
|
66
|
+
|
|
67
|
+
let contentDiv = tree.children[1] as any;
|
|
68
|
+
assert.equal(contentDiv.type, "div");
|
|
69
|
+
assert.equal(contentDiv.props.className, "content");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("renders React function components with hooks", () => {
|
|
73
|
+
let store = new Store();
|
|
74
|
+
|
|
75
|
+
const component = createTestRenderer(
|
|
76
|
+
store,
|
|
77
|
+
<cx>
|
|
78
|
+
<ReactCounterComponent initialCount={5} />
|
|
79
|
+
</cx>,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let tree = component.toJSON();
|
|
83
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
84
|
+
assert.equal(tree.type, "div");
|
|
85
|
+
assert.equal(tree.props.className, "react-counter");
|
|
86
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (span and button)");
|
|
87
|
+
|
|
88
|
+
let span = tree.children[0] as any;
|
|
89
|
+
assert.equal(span.type, "span");
|
|
90
|
+
assert.equal(span.props.className, "count");
|
|
91
|
+
assert.deepEqual(span.children, ["5"]);
|
|
92
|
+
|
|
93
|
+
let button = tree.children[1] as any;
|
|
94
|
+
assert.equal(button.type, "button");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("renders React class components with props", () => {
|
|
98
|
+
let store = new Store();
|
|
99
|
+
|
|
100
|
+
const component = createTestRenderer(
|
|
101
|
+
store,
|
|
102
|
+
<cx>
|
|
103
|
+
<ReactClassComponent label="Test Label">
|
|
104
|
+
<span>Class child content</span>
|
|
105
|
+
</ReactClassComponent>
|
|
106
|
+
</cx>,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
let tree = component.toJSON();
|
|
110
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
111
|
+
assert.equal(tree.type, "div");
|
|
112
|
+
assert(tree.props.className.includes("react-class-component"), "Expected react-class-component class");
|
|
113
|
+
|
|
114
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (label and div)");
|
|
115
|
+
|
|
116
|
+
let label = tree.children[0] as any;
|
|
117
|
+
assert.equal(label.type, "label");
|
|
118
|
+
assert.deepEqual(label.children, ["Test Label"]);
|
|
119
|
+
|
|
120
|
+
let bodyDiv = tree.children[1] as any;
|
|
121
|
+
assert.equal(bodyDiv.type, "div");
|
|
122
|
+
assert.equal(bodyDiv.props.className, "body");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("renders React PureComponent", () => {
|
|
126
|
+
let store = new Store();
|
|
127
|
+
|
|
128
|
+
const component = createTestRenderer(
|
|
129
|
+
store,
|
|
130
|
+
<cx>
|
|
131
|
+
<ReactPureComponent value="Pure Value" />
|
|
132
|
+
</cx>,
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
let tree = component.toJSON();
|
|
136
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
137
|
+
assert.equal(tree.type, "span");
|
|
138
|
+
assert.equal(tree.props.className, "react-pure-component");
|
|
139
|
+
assert.deepEqual(tree.children, ["Pure Value"]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("renders React function component with useRef and useEffect", () => {
|
|
143
|
+
let store = new Store();
|
|
144
|
+
let mountedElement: HTMLDivElement | null = null;
|
|
145
|
+
|
|
146
|
+
const component = createTestRenderer(
|
|
147
|
+
store,
|
|
148
|
+
<cx>
|
|
149
|
+
<ReactRefEffectComponent
|
|
150
|
+
onMount={(el) => {
|
|
151
|
+
mountedElement = el;
|
|
152
|
+
}}
|
|
153
|
+
/>
|
|
154
|
+
</cx>,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
let tree = component.toJSON();
|
|
158
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
159
|
+
assert.equal(tree.type, "div");
|
|
160
|
+
assert.equal(tree.props.className, "react-ref-effect-component");
|
|
161
|
+
assert.deepEqual(tree.children, ["Component with ref and effect"]);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("renders React function component with useEffect that updates state", () => {
|
|
165
|
+
let store = new Store();
|
|
166
|
+
let component: ReturnType<typeof createTestRenderer>;
|
|
167
|
+
|
|
168
|
+
act(() => {
|
|
169
|
+
component = createTestRenderer(
|
|
170
|
+
store,
|
|
171
|
+
<cx>
|
|
172
|
+
<ReactEffectStateComponent value="Test" />
|
|
173
|
+
</cx>,
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
let tree = component!.toJSON();
|
|
178
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
179
|
+
assert.equal(tree.type, "div");
|
|
180
|
+
assert.equal(tree.props.className, "react-effect-state-component");
|
|
181
|
+
assert(tree.children && tree.children.length === 2, "Expected two children");
|
|
182
|
+
|
|
183
|
+
let processedSpan = tree.children[0] as any;
|
|
184
|
+
assert.equal(processedSpan.type, "span");
|
|
185
|
+
assert.equal(processedSpan.props.className, "processed");
|
|
186
|
+
// After act(), useEffect should have run and updated state
|
|
187
|
+
assert.deepEqual(processedSpan.children, ["Processed: Test"]);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("translates CxJS accessor bindings to React component props", () => {
|
|
191
|
+
interface StoreModel {
|
|
192
|
+
text: string;
|
|
193
|
+
count: number;
|
|
194
|
+
enabled: boolean;
|
|
195
|
+
tags: string[];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
199
|
+
|
|
200
|
+
// First verify jsx transform output
|
|
201
|
+
const widget = (
|
|
202
|
+
<cx>
|
|
203
|
+
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} tags={$store.tags} />
|
|
204
|
+
</cx>
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
assert.equal(widget.$type, ReactElementWrapper, "React component should use ReactElementWrapper as $type");
|
|
208
|
+
assert.equal(widget.componentType, ReactPropsComponent, "React component should be set as componentType");
|
|
209
|
+
assert.equal(typeof widget.text, "function", "Accessor chain text should be a function");
|
|
210
|
+
assert.equal(widget.text.toString(), "text", "Accessor chain text should resolve to path");
|
|
211
|
+
|
|
212
|
+
// Now verify rendering
|
|
213
|
+
let store = new Store<StoreModel>({
|
|
214
|
+
data: {
|
|
215
|
+
text: "Bound Text",
|
|
216
|
+
count: 42,
|
|
217
|
+
enabled: true,
|
|
218
|
+
tags: ["a", "b", "c"],
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const component = createTestRenderer(store, widget);
|
|
223
|
+
|
|
224
|
+
let tree = component.toJSON();
|
|
225
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
226
|
+
assert.equal(tree.type, "div");
|
|
227
|
+
|
|
228
|
+
let textSpan = tree.children![0] as any;
|
|
229
|
+
assert.deepEqual(textSpan.children, ["Bound Text"]);
|
|
230
|
+
|
|
231
|
+
let countSpan = tree.children![1] as any;
|
|
232
|
+
assert.deepEqual(countSpan.children, ["42"]);
|
|
233
|
+
|
|
234
|
+
let enabledSpan = tree.children![2] as any;
|
|
235
|
+
assert.deepEqual(enabledSpan.children, ["yes"]);
|
|
236
|
+
|
|
237
|
+
let tagsSpan = tree.children![3] as any;
|
|
238
|
+
assert.deepEqual(tagsSpan.children, ["a, b, c"]);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("supports visible prop on React components", () => {
|
|
242
|
+
interface StoreModel {
|
|
243
|
+
show: boolean;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
247
|
+
|
|
248
|
+
let store = new Store<StoreModel>({
|
|
249
|
+
data: {
|
|
250
|
+
show: false,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const component = createTestRenderer(
|
|
255
|
+
store,
|
|
256
|
+
<cx>
|
|
257
|
+
<div>
|
|
258
|
+
<ReactFunctionComponent title="Visible Test" visible={$store.show} />
|
|
259
|
+
<span>Always visible</span>
|
|
260
|
+
</div>
|
|
261
|
+
</cx>,
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
let tree = component.toJSON();
|
|
265
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
266
|
+
// When visible=false, the React component should not render
|
|
267
|
+
assert.equal(tree.children!.length, 1, "Expected only the span to be visible");
|
|
268
|
+
assert.equal((tree.children![0] as any).type, "span");
|
|
269
|
+
|
|
270
|
+
// Update store to make component visible
|
|
271
|
+
store.set("show", true);
|
|
272
|
+
let tree2 = component.toJSON();
|
|
273
|
+
assert(tree2 && !Array.isArray(tree2), "Expected single element");
|
|
274
|
+
assert.equal(tree2.children!.length, 2, "Expected both children to be visible");
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("supports controller prop on React components", () => {
|
|
278
|
+
let controllerInitialized = false;
|
|
279
|
+
|
|
280
|
+
class TestController extends Controller {
|
|
281
|
+
onInit() {
|
|
282
|
+
controllerInitialized = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface StoreModel {
|
|
287
|
+
text: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
291
|
+
|
|
292
|
+
let store = new Store<StoreModel>({
|
|
293
|
+
data: {
|
|
294
|
+
text: "Controller Test",
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const component = createTestRenderer(
|
|
299
|
+
store,
|
|
300
|
+
<cx>
|
|
301
|
+
<ReactPropsComponent text={$store.text} count={10} enabled={true} controller={TestController} />
|
|
302
|
+
</cx>,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
let tree = component.toJSON();
|
|
306
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
307
|
+
assert.equal(controllerInitialized, true, "Controller should be initialized");
|
|
308
|
+
|
|
309
|
+
let textSpan = tree.children![0] as any;
|
|
310
|
+
assert.deepEqual(textSpan.children, ["Controller Test"]);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("updates React component when bound store data changes", () => {
|
|
314
|
+
interface StoreModel {
|
|
315
|
+
text: string;
|
|
316
|
+
count: number;
|
|
317
|
+
enabled: boolean;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
321
|
+
|
|
322
|
+
let store = new Store<StoreModel>({
|
|
323
|
+
data: {
|
|
324
|
+
text: "Initial",
|
|
325
|
+
count: 1,
|
|
326
|
+
enabled: false,
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const component = createTestRenderer(
|
|
331
|
+
store,
|
|
332
|
+
<cx>
|
|
333
|
+
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} />
|
|
334
|
+
</cx>,
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
let tree1 = component.toJSON() as any;
|
|
338
|
+
assert.deepEqual(tree1.children[0].children, ["Initial"]);
|
|
339
|
+
assert.deepEqual(tree1.children[1].children, ["1"]);
|
|
340
|
+
assert.deepEqual(tree1.children[2].children, ["no"]);
|
|
341
|
+
|
|
342
|
+
// Update store
|
|
343
|
+
store.set("text", "Updated");
|
|
344
|
+
store.set("count", 99);
|
|
345
|
+
store.set("enabled", true);
|
|
346
|
+
|
|
347
|
+
let tree2 = component.toJSON() as any;
|
|
348
|
+
assert.deepEqual(tree2.children[0].children, ["Updated"]);
|
|
349
|
+
assert.deepEqual(tree2.children[1].children, ["99"]);
|
|
350
|
+
assert.deepEqual(tree2.children[2].children, ["yes"]);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
describe("React component type inference", () => {
|
|
354
|
+
interface RequiredPropsComponentProps {
|
|
355
|
+
label: string;
|
|
356
|
+
value: number;
|
|
357
|
+
onChange: (value: number) => void;
|
|
358
|
+
disabled?: boolean;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function RequiredPropsComponent(_props: RequiredPropsComponentProps) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
it("accepts all required props", () => {
|
|
366
|
+
const widget = (
|
|
367
|
+
<cx>
|
|
368
|
+
<RequiredPropsComponent label="Amount" value={100} onChange={(v) => console.log(v)} />
|
|
369
|
+
</cx>
|
|
370
|
+
);
|
|
371
|
+
assert.ok(widget);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("accepts required props with optional prop", () => {
|
|
375
|
+
const widget = (
|
|
376
|
+
<cx>
|
|
377
|
+
<RequiredPropsComponent label="Amount" value={100} onChange={(v) => console.log(v)} disabled={true} />
|
|
378
|
+
</cx>
|
|
379
|
+
);
|
|
380
|
+
assert.ok(widget);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it("rejects missing required prop (label)", () => {
|
|
384
|
+
const widget = (
|
|
385
|
+
<cx>
|
|
386
|
+
{/* @ts-expect-error - label is required but missing */}
|
|
387
|
+
<RequiredPropsComponent value={100} onChange={(v) => console.log(v)} />
|
|
388
|
+
</cx>
|
|
389
|
+
);
|
|
390
|
+
assert.ok(widget);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("rejects missing required prop (onChange)", () => {
|
|
394
|
+
const widget = (
|
|
395
|
+
<cx>
|
|
396
|
+
{/* @ts-expect-error - onChange is required but missing */}
|
|
397
|
+
<RequiredPropsComponent label="Amount" value={100} />
|
|
398
|
+
</cx>
|
|
399
|
+
);
|
|
400
|
+
assert.ok(widget);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("rejects missing all required props", () => {
|
|
404
|
+
const widget = (
|
|
405
|
+
<cx>
|
|
406
|
+
{/* @ts-expect-error - label, value, and onChange are required but missing */}
|
|
407
|
+
<RequiredPropsComponent disabled={true} />
|
|
408
|
+
</cx>
|
|
409
|
+
);
|
|
410
|
+
assert.ok(widget);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it("rejects wrong prop type (string for number)", () => {
|
|
414
|
+
const widget = (
|
|
415
|
+
<cx>
|
|
416
|
+
{/* @ts-expect-error - value should be number, not string */}
|
|
417
|
+
<RequiredPropsComponent label="Amount" value="100" onChange={(v) => console.log(v)} />
|
|
418
|
+
</cx>
|
|
419
|
+
);
|
|
420
|
+
assert.ok(widget);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it("rejects wrong prop type (number for string)", () => {
|
|
424
|
+
const widget = (
|
|
425
|
+
<cx>
|
|
426
|
+
{/* @ts-expect-error - label should be string, not number */}
|
|
427
|
+
<RequiredPropsComponent label={123} value={100} onChange={(v) => console.log(v)} />
|
|
428
|
+
</cx>
|
|
429
|
+
);
|
|
430
|
+
assert.ok(widget);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("provides instance through this", () => {
|
|
434
|
+
class TestController extends Controller {
|
|
435
|
+
change(_v: number) {}
|
|
436
|
+
}
|
|
437
|
+
const widget = (
|
|
438
|
+
<cx>
|
|
439
|
+
<RequiredPropsComponent
|
|
440
|
+
label={"label"}
|
|
441
|
+
value={100}
|
|
442
|
+
controller={TestController}
|
|
443
|
+
onChange={function (v) {
|
|
444
|
+
this.getControllerByType(TestController).change(v);
|
|
445
|
+
}}
|
|
446
|
+
/>
|
|
447
|
+
</cx>
|
|
448
|
+
);
|
|
449
|
+
assert.ok(widget);
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ContainerBase, ContainerConfig } from "../ui/Container";
|
|
2
|
+
import { Instance } from "../ui/Instance";
|
|
3
|
+
import { Prop } from "../ui/Prop";
|
|
4
|
+
import type { RenderingContext } from "../ui/RenderingContext";
|
|
5
|
+
import { VDOM, Widget } from "../ui/Widget";
|
|
6
|
+
import { isFunction, isNonEmptyArray } from "../util";
|
|
7
|
+
import { isArray } from "../util/isArray";
|
|
8
|
+
|
|
9
|
+
type ReactElementWrapperConfigBase = Omit<ContainerConfig, "items">;
|
|
10
|
+
|
|
11
|
+
// CxJS callback type - can be string (controller method) or callback with Instance as this
|
|
12
|
+
type CxCallback<T> = T extends (...args: infer A) => infer R ? (this: Instance, ...args: A) => R : T;
|
|
13
|
+
|
|
14
|
+
// Transform a single prop: functions to CxCallback, data to Prop<T>
|
|
15
|
+
type TransformProp<K, V> = K extends keyof ReactElementWrapperConfigBase
|
|
16
|
+
? ReactElementWrapperConfigBase[K]
|
|
17
|
+
: NonNullable<V> extends Function
|
|
18
|
+
? CxCallback<V>
|
|
19
|
+
: Prop<V>;
|
|
20
|
+
|
|
21
|
+
// Transform React component props - functions to CxCallback, data props to Prop<T>
|
|
22
|
+
// Preserves required/optional status
|
|
23
|
+
type TransformReactElementProps<T> = {
|
|
24
|
+
[K in keyof T]: TransformProp<K, T[K]>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** ReactElementWrapper configuration with component-specific props */
|
|
28
|
+
// componentType is not included here - it's added by the jsx-runtime and declared in the class
|
|
29
|
+
export type ReactElementWrapperConfig<P> = ReactElementWrapperConfigBase & TransformReactElementProps<P>;
|
|
30
|
+
|
|
31
|
+
interface ReactElementWrapperInstance extends Instance {
|
|
32
|
+
events?: Record<string, Function>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class ReactElementWrapper<C extends React.ComponentType<any> = React.ComponentType<any>> extends ContainerBase<
|
|
36
|
+
ReactElementWrapperConfigBase & { componentType: C; jsxAttributes?: string[] },
|
|
37
|
+
ReactElementWrapperInstance
|
|
38
|
+
> {
|
|
39
|
+
declare public componentType: React.ComponentType<any>;
|
|
40
|
+
declare public jsxAttributes?: string[];
|
|
41
|
+
declare public props?: Record<string, unknown>;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
|
|
44
|
+
init(): void {
|
|
45
|
+
// Collect all props to pass to the React component
|
|
46
|
+
this.props = {};
|
|
47
|
+
|
|
48
|
+
if (this.jsxAttributes) {
|
|
49
|
+
for (const attr of this.jsxAttributes) {
|
|
50
|
+
// Skip CxJS reserved attributes and children-related attributes
|
|
51
|
+
if (
|
|
52
|
+
attr === "componentType" ||
|
|
53
|
+
attr === "visible" ||
|
|
54
|
+
attr === "if" ||
|
|
55
|
+
attr === "controller" ||
|
|
56
|
+
attr === "jsxAttributes" ||
|
|
57
|
+
attr === "layout" ||
|
|
58
|
+
attr === "outerLayout" ||
|
|
59
|
+
attr === "putInto" ||
|
|
60
|
+
attr === "contentFor" ||
|
|
61
|
+
attr === "children" ||
|
|
62
|
+
attr === "items"
|
|
63
|
+
)
|
|
64
|
+
continue;
|
|
65
|
+
|
|
66
|
+
this.props[attr] = this[attr];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
super.init();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public initInstance(_context: RenderingContext, _instance: ReactElementWrapperInstance): void {
|
|
74
|
+
let events: Record<string, Function> | undefined;
|
|
75
|
+
if (!isNonEmptyArray(this.jsxAttributes)) return;
|
|
76
|
+
events = {};
|
|
77
|
+
for (let prop of this.jsxAttributes) {
|
|
78
|
+
let f = this[prop];
|
|
79
|
+
if (prop.startsWith("on") && isFunction(f)) events[prop] = (...args: any[]) => f.apply(_instance, args);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declareData(...args: Record<string, unknown>[]): void {
|
|
84
|
+
super.declareData(
|
|
85
|
+
{
|
|
86
|
+
props: { structured: true },
|
|
87
|
+
},
|
|
88
|
+
...args,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
render(context: RenderingContext, instance: ReactElementWrapperInstance, key: string): React.ReactNode {
|
|
93
|
+
const { data } = instance;
|
|
94
|
+
|
|
95
|
+
// Render CxJS children to React elements
|
|
96
|
+
let children = this.renderChildren(context, instance);
|
|
97
|
+
if (children && isArray(children) && children.length === 0) children = undefined;
|
|
98
|
+
|
|
99
|
+
const props = {
|
|
100
|
+
key,
|
|
101
|
+
...data.props,
|
|
102
|
+
...instance.events,
|
|
103
|
+
children,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return VDOM.createElement(this.componentType, props);
|
|
107
|
+
}
|
|
108
|
+
}
|