cx 26.1.1 → 26.1.2
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/.mocharc.json +5 -5
- package/LICENSE-THIRD-PARTY.md +91 -91
- package/LICENSE.md +7 -7
- package/README.md +46 -46
- package/build/data/ArrayElementView.d.ts +4 -3
- package/build/ui/adapter/ArrayAdapter.js +0 -2
- package/build/ui/adapter/DataAdapter.d.ts +3 -3
- package/build.js +133 -133
- package/dist/manifest.js +826 -826
- package/dist/ui.js +0 -2
- package/package.json +100 -99
- package/src/charts/Bar.scss +28 -28
- package/src/charts/Bar.ts +114 -114
- package/src/charts/BarGraph.scss +28 -28
- package/src/charts/BarGraph.tsx +145 -145
- package/src/charts/BubbleGraph.scss +31 -31
- package/src/charts/BubbleGraph.tsx +165 -165
- package/src/charts/Chart.ts +108 -108
- package/src/charts/ColorMap.ts +150 -150
- package/src/charts/Column.scss +28 -28
- package/src/charts/Column.ts +124 -124
- package/src/charts/ColumnBarBase.tsx +284 -284
- package/src/charts/ColumnBarGraphBase.tsx +229 -229
- package/src/charts/ColumnGraph.scss +29 -29
- package/src/charts/ColumnGraph.tsx +153 -153
- package/src/charts/Grid.ts +5 -5
- package/src/charts/Gridlines.scss +24 -24
- package/src/charts/Gridlines.tsx +88 -88
- package/src/charts/Legend.scss +50 -50
- package/src/charts/Legend.tsx +270 -270
- package/src/charts/LegendEntry.scss +29 -29
- package/src/charts/LegendEntry.tsx +197 -197
- package/src/charts/LineGraph.scss +24 -24
- package/src/charts/LineGraph.tsx +455 -455
- package/src/charts/Marker.scss +43 -43
- package/src/charts/Marker.tsx +483 -483
- package/src/charts/MarkerLine.scss +19 -19
- package/src/charts/MarkerLine.tsx +214 -214
- package/src/charts/MouseTracker.tsx +112 -112
- package/src/charts/Pie.ts +8 -8
- package/src/charts/PieChart.scss +28 -28
- package/src/charts/PieChart.tsx +717 -717
- package/src/charts/PieLabel.tsx +106 -106
- package/src/charts/PieLabelsContainer.ts +68 -68
- package/src/charts/Range.scss +19 -19
- package/src/charts/Range.tsx +318 -318
- package/src/charts/RangeMarker.scss +17 -17
- package/src/charts/RangeMarker.tsx +233 -233
- package/src/charts/ScatterGraph.scss +23 -23
- package/src/charts/ScatterGraph.tsx +245 -245
- package/src/charts/Swimlane.scss +16 -16
- package/src/charts/Swimlane.tsx +195 -195
- package/src/charts/Swimlanes.scss +16 -16
- package/src/charts/Swimlanes.tsx +179 -179
- package/src/charts/axis/Axis.scss +22 -22
- package/src/charts/axis/Axis.tsx +444 -444
- package/src/charts/axis/CategoryAxis.scss +34 -34
- package/src/charts/axis/CategoryAxis.tsx +313 -313
- package/src/charts/axis/NumericAxis.scss +34 -34
- package/src/charts/axis/NumericAxis.tsx +437 -437
- package/src/charts/axis/Stack.ts +61 -61
- package/src/charts/axis/TimeAxis.scss +33 -33
- package/src/charts/axis/TimeAxis.tsx +718 -718
- package/src/charts/axis/index.scss +5 -5
- package/src/charts/axis/index.ts +3 -3
- package/src/charts/axis/variables.scss +2 -2
- package/src/charts/helpers/MinMaxFinder.ts +66 -66
- package/src/charts/helpers/PointReducer.ts +135 -135
- package/src/charts/helpers/SnapPointFinder.ts +136 -136
- package/src/charts/helpers/ValueAtFinder.ts +72 -72
- package/src/charts/helpers/index.ts +4 -4
- package/src/charts/index.scss +22 -22
- package/src/charts/index.ts +34 -34
- package/src/charts/palette.scss +97 -97
- package/src/charts/shapes.tsx +86 -86
- package/src/charts/variables.scss +22 -22
- package/src/core.d.ts +182 -182
- package/src/data/AggregateFunction.ts +171 -171
- package/src/data/ArrayElementView.spec.ts +88 -88
- package/src/data/ArrayElementView.ts +91 -90
- package/src/data/ArrayRef.ts +34 -34
- package/src/data/AugmentedViewBase.ts +88 -88
- package/src/data/Binding.spec.ts +69 -69
- 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.spec.ts +79 -79
- package/src/data/Ref.ts +104 -104
- package/src/data/Selector.ts +10 -10
- package/src/data/Store.spec.ts +22 -22
- package/src/data/Store.ts +52 -52
- package/src/data/StoreProxy.ts +19 -19
- package/src/data/StoreRef.spec.ts +24 -24
- 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/View.spec.ts +60 -60
- package/src/data/View.ts +289 -289
- package/src/data/ZoomIntoPropertyView.spec.ts +64 -64
- package/src/data/ZoomIntoPropertyView.ts +45 -45
- package/src/data/comparer.spec.ts +60 -60
- package/src/data/comparer.ts +78 -78
- package/src/data/computable.spec.ts +87 -87
- package/src/data/computable.ts +69 -69
- package/src/data/createAccessorModelProxy.spec.tsx +145 -145
- package/src/data/createAccessorModelProxy.ts +66 -66
- package/src/data/createStructuredSelector.spec.ts +45 -45
- package/src/data/createStructuredSelector.ts +62 -62
- package/src/data/defaultCompare.ts +14 -14
- package/src/data/diff/diffArrays.ts +49 -49
- package/src/data/diff/diffs.spec.ts +49 -49
- package/src/data/diff/index.ts +1 -1
- package/src/data/enableFatArrowExpansion.ts +6 -6
- 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/index.ts +30 -30
- package/src/data/isSelector.ts +26 -26
- package/src/data/ops/append.spec.ts +28 -28
- package/src/data/ops/append.ts +5 -5
- package/src/data/ops/filter.spec.ts +35 -35
- package/src/data/ops/filter.ts +9 -9
- package/src/data/ops/findTreeNode.spec.ts +23 -23
- package/src/data/ops/findTreeNode.ts +14 -14
- package/src/data/ops/findTreePath.ts +23 -23
- package/src/data/ops/index.ts +11 -11
- package/src/data/ops/insertElement.ts +3 -3
- package/src/data/ops/merge.spec.ts +27 -27
- package/src/data/ops/merge.ts +13 -13
- package/src/data/ops/moveElement.ts +21 -21
- package/src/data/ops/removeTreeNodes.spec.ts +37 -37
- package/src/data/ops/removeTreeNodes.ts +15 -15
- package/src/data/ops/updateArray.spec.ts +69 -69
- package/src/data/ops/updateArray.ts +31 -31
- package/src/data/ops/updateTree.spec.ts +54 -54
- package/src/data/ops/updateTree.ts +23 -23
- package/src/data/test-types.ts +7 -7
- package/src/global.scss +13 -13
- package/src/hooks/createLocalStorageRef.ts +21 -21
- package/src/hooks/index.ts +8 -8
- package/src/hooks/invokeCallback.spec.tsx +59 -59
- package/src/hooks/invokeCallback.ts +8 -8
- package/src/hooks/resolveCallback.spec.tsx +71 -71
- package/src/hooks/resolveCallback.ts +16 -16
- package/src/hooks/store.spec.tsx +67 -67
- package/src/hooks/store.ts +46 -46
- package/src/hooks/useEffect.ts +14 -14
- package/src/hooks/useInterval.ts +8 -8
- package/src/hooks/useState.ts +20 -20
- package/src/hooks/useTrigger.spec.tsx +105 -105
- package/src/hooks/useTrigger.ts +26 -26
- package/src/index.ts +7 -7
- package/src/jsx-dev-runtime.ts +4 -4
- package/src/jsx-runtime.spec.tsx +431 -431
- package/src/jsx-runtime.ts +79 -79
- package/src/locale/de-de.ts +76 -76
- package/src/locale/en-us.ts +75 -75
- package/src/locale/es-es.ts +76 -76
- package/src/locale/fr-fr.ts +76 -76
- package/src/locale/nl-nl.ts +76 -76
- package/src/locale/pt-pt.ts +76 -76
- package/src/locale/sr-latn-ba.ts +76 -76
- package/src/svg/BoundedObject.ts +101 -101
- package/src/svg/ClipRect.tsx +29 -29
- package/src/svg/Ellipse.tsx +68 -68
- package/src/svg/Line.tsx +58 -58
- package/src/svg/NonOverlappingRect.ts +26 -26
- package/src/svg/NonOverlappingRectGroup.ts +49 -49
- package/src/svg/Rectangle.tsx +90 -90
- package/src/svg/Svg.scss +27 -27
- package/src/svg/Svg.tsx +241 -241
- package/src/svg/Text.tsx +134 -134
- package/src/svg/TextualBoundedObject.ts +35 -35
- package/src/svg/index.scss +8 -8
- package/src/svg/index.ts +17 -17
- package/src/svg/util/Rect.ts +105 -105
- package/src/ui/CSS.ts +87 -87
- package/src/ui/CSSHelper.ts +17 -17
- package/src/ui/Container.tsx +216 -216
- package/src/ui/ContentResolver.spec.tsx +585 -585
- package/src/ui/ContentResolver.ts +132 -132
- package/src/ui/Controller.spec.tsx +574 -574
- package/src/ui/Controller.ts +202 -202
- package/src/ui/Culture.ts +159 -159
- package/src/ui/Cx.spec.tsx +210 -210
- package/src/ui/Cx.tsx +386 -386
- package/src/ui/DataProxy.spec.tsx +337 -337
- package/src/ui/DataProxy.ts +55 -55
- package/src/ui/DetachedScope.tsx +159 -159
- package/src/ui/FocusManager.ts +171 -171
- package/src/ui/Format.ts +108 -108
- package/src/ui/HoverSync.tsx +189 -189
- package/src/ui/Instance.ts +866 -866
- package/src/ui/IsolatedScope.spec.tsx +62 -62
- package/src/ui/IsolatedScope.ts +50 -50
- package/src/ui/Localization.ts +70 -70
- package/src/ui/Prop.ts +140 -140
- package/src/ui/PureContainer.spec.tsx +232 -232
- package/src/ui/PureContainer.tsx +19 -19
- package/src/ui/RenderingContext.ts +99 -99
- package/src/ui/Repeater.spec.tsx +143 -143
- package/src/ui/Repeater.ts +194 -194
- package/src/ui/Rescope.spec.tsx +199 -199
- package/src/ui/Rescope.ts +49 -49
- package/src/ui/ResizeManager.ts +30 -30
- package/src/ui/Restate.spec.tsx +422 -422
- package/src/ui/Restate.tsx +217 -217
- package/src/ui/StaticText.ts +11 -11
- package/src/ui/StructuredInstanceDataAccessor.ts +32 -32
- package/src/ui/Text.ts +49 -49
- package/src/ui/VDOM.ts +1 -1
- package/src/ui/Widget.spec.tsx +53 -53
- package/src/ui/Widget.tsx +301 -301
- package/src/ui/ZIndexManager.ts +11 -11
- package/src/ui/adapter/ArrayAdapter.spec.ts +55 -55
- package/src/ui/adapter/ArrayAdapter.ts +229 -229
- package/src/ui/adapter/DataAdapter.ts +52 -52
- package/src/ui/adapter/GroupAdapter.ts +235 -235
- package/src/ui/adapter/TreeAdapter.spec.ts +76 -76
- package/src/ui/adapter/TreeAdapter.ts +185 -185
- package/src/ui/adapter/index.ts +4 -4
- package/src/ui/app/History.ts +133 -133
- package/src/ui/app/Url.spec.ts +50 -50
- package/src/ui/app/Url.ts +102 -102
- package/src/ui/app/index.ts +5 -5
- package/src/ui/app/startAppLoop.tsx +71 -71
- package/src/ui/app/startHotAppLoop.ts +41 -41
- package/src/ui/batchUpdates.ts +77 -77
- package/src/ui/bind.ts +10 -10
- package/src/ui/createFunctionalComponent.spec.tsx +454 -454
- package/src/ui/createFunctionalComponent.ts +86 -86
- package/src/ui/expr.ts +47 -47
- package/src/ui/exprHelpers.spec.ts +379 -379
- package/src/ui/exprHelpers.ts +78 -78
- package/src/ui/flattenProps.ts +21 -21
- package/src/ui/index.scss +2 -2
- package/src/ui/index.ts +47 -47
- package/src/ui/keyboardShortcuts.ts +40 -40
- package/src/ui/layout/Content.ts +30 -30
- package/src/ui/layout/ContentPlaceholder.spec.tsx +599 -599
- package/src/ui/layout/ContentPlaceholder.ts +133 -133
- package/src/ui/layout/FirstVisibleChildLayout.spec.tsx +207 -207
- package/src/ui/layout/FirstVisibleChildLayout.ts +60 -60
- package/src/ui/layout/LabelsLeftLayout.scss +46 -46
- package/src/ui/layout/LabelsLeftLayout.tsx +76 -76
- package/src/ui/layout/LabelsTopLayout.scss +64 -64
- package/src/ui/layout/LabelsTopLayout.tsx +156 -156
- package/src/ui/layout/UseParentLayout.ts +8 -8
- package/src/ui/layout/exploreChildren.ts +38 -38
- package/src/ui/layout/index.scss +3 -3
- package/src/ui/layout/index.ts +10 -10
- package/src/ui/layout/variables.scss +2 -2
- package/src/ui/selection/KeySelection.ts +153 -153
- package/src/ui/selection/PropertySelection.ts +87 -87
- package/src/ui/selection/Selection.ts +128 -128
- package/src/ui/selection/index.ts +3 -3
- package/src/ui/tpl.ts +4 -4
- package/src/ui/variables.scss +1 -1
- package/src/util/Component.spec.ts +411 -411
- package/src/util/Console.ts +13 -13
- package/src/util/DOM.ts +88 -88
- package/src/util/Debug.ts +71 -71
- package/src/util/Format.spec.ts +69 -69
- package/src/util/Format.ts +267 -267
- package/src/util/GlobalCacheIdentifier.ts +11 -11
- package/src/util/KeyCode.ts +21 -21
- package/src/util/SubscriberList.ts +86 -86
- package/src/util/Timing.ts +58 -58
- package/src/util/TraversalStack.spec.ts +53 -53
- package/src/util/TraversalStack.ts +47 -47
- package/src/util/addEventListenerWithOptions.ts +41 -41
- package/src/util/browserSupportsPassiveEventHandlers.ts +20 -20
- package/src/util/calculateNaturalElementHeight.ts +22 -22
- package/src/util/call-once.scss +6 -6
- package/src/util/capitalize.ts +4 -4
- package/src/util/coalesce.ts +6 -6
- package/src/util/color/hslToRgb.ts +34 -34
- package/src/util/color/index.ts +4 -4
- package/src/util/color/parseColor.ts +173 -173
- package/src/util/color/rgbToHex.ts +14 -14
- package/src/util/color/rgbToHsl.ts +35 -35
- package/src/util/date/dateDiff.ts +9 -9
- package/src/util/date/diff.ts +13 -13
- package/src/util/date/encodeDate.ts +8 -8
- package/src/util/date/encodeDateWithTimezoneOffset.ts +18 -18
- package/src/util/date/index.ts +11 -11
- package/src/util/date/lowerBoundCheck.ts +13 -13
- package/src/util/date/maxDate.ts +14 -14
- package/src/util/date/minDate.ts +14 -14
- package/src/util/date/monthStart.ts +8 -8
- package/src/util/date/parseDateInvariant.ts +20 -20
- package/src/util/date/sameDate.ts +11 -11
- package/src/util/date/upperBoundCheck.spec.ts +30 -30
- package/src/util/date/upperBoundCheck.ts +13 -13
- package/src/util/date/zeroTime.ts +9 -9
- package/src/util/debounce.ts +26 -26
- package/src/util/dummyCallback.ts +1 -1
- package/src/util/escapeSpecialRegexCharacters.ts +8 -8
- package/src/util/eventCallbacks.ts +12 -12
- package/src/util/expandFatArrows.ts +118 -118
- package/src/util/findScrollableParent.ts +15 -15
- package/src/util/getActiveElement.ts +4 -4
- package/src/util/getParentFrameBoundingClientRect.ts +13 -13
- package/src/util/getScrollerBoundingClientRect.ts +12 -12
- package/src/util/getSearchQueryPredicate.spec.ts +40 -40
- package/src/util/getSearchQueryPredicate.ts +58 -58
- package/src/util/getTopLevelBoundingClientRect.ts +7 -7
- package/src/util/getVendorPrefix.ts +33 -33
- package/src/util/hasKey.ts +18 -18
- package/src/util/index.scss +10 -10
- 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/isDigit.ts +8 -8
- package/src/util/isFunction.ts +3 -3
- package/src/util/isNonEmptyArray.ts +3 -3
- package/src/util/isNumber.ts +3 -3
- package/src/util/isObject.ts +3 -3
- package/src/util/isPromise.ts +6 -6
- package/src/util/isString.ts +3 -3
- package/src/util/isTextInputElement.ts +2 -2
- package/src/util/isTouchDevice.ts +7 -7
- package/src/util/isTouchEvent.ts +64 -64
- package/src/util/isUndefined.ts +3 -3
- package/src/util/isValidIdentifierName.spec.ts +33 -33
- package/src/util/isValidIdentifierName.ts +5 -5
- package/src/util/onIdleCallback.ts +10 -10
- package/src/util/parseStyle.ts +29 -29
- package/src/util/quote.ts +6 -6
- package/src/util/reverseSlice.ts +9 -9
- package/src/util/routeAppend.spec.ts +19 -19
- package/src/util/routeAppend.ts +15 -15
- package/src/util/scrollElementIntoView.ts +40 -40
- package/src/util/scss/add-rules.scss +40 -40
- package/src/util/scss/calc.scss +44 -44
- package/src/util/scss/call-once.scss +12 -12
- package/src/util/scss/clockwise.scss +49 -49
- package/src/util/scss/colors.scss +9 -9
- package/src/util/scss/deep-get.scss +11 -11
- package/src/util/scss/deep-merge.scss +21 -21
- package/src/util/scss/divide.scss +3 -3
- package/src/util/scss/include.scss +48 -48
- package/src/util/scss/index.scss +9 -9
- package/src/util/shallowEquals.ts +43 -43
- package/src/util/test/createTestRenderer.tsx +19 -19
- package/src/util/throttle.ts +21 -21
- package/src/util/validatedDebounce.ts +23 -23
- package/src/variables.scss +217 -217
- package/src/widgets/AccessorBindings.spec.tsx +90 -90
- package/src/widgets/Button.scss +119 -119
- package/src/widgets/Button.tsx +189 -189
- package/src/widgets/Button.variables.scss +117 -117
- package/src/widgets/CxCredit.scss +39 -39
- package/src/widgets/CxCredit.tsx +46 -46
- package/src/widgets/DocumentTitle.ts +95 -95
- package/src/widgets/FlexBox.scss +148 -148
- package/src/widgets/FlexBox.tsx +168 -168
- package/src/widgets/Heading.scss +40 -40
- package/src/widgets/Heading.ts +42 -42
- package/src/widgets/HighlightedSearchText.scss +20 -20
- package/src/widgets/HighlightedSearchText.tsx +54 -54
- package/src/widgets/HtmlElement.spec.helpers.tsx +108 -108
- package/src/widgets/HtmlElement.spec.tsx +89 -89
- package/src/widgets/HtmlElement.tsx +407 -407
- package/src/widgets/Icon.scss +22 -22
- package/src/widgets/Icon.ts +64 -64
- package/src/widgets/List.scss +93 -93
- package/src/widgets/List.tsx +793 -793
- package/src/widgets/ProgressBar.scss +50 -50
- package/src/widgets/ProgressBar.tsx +66 -66
- package/src/widgets/ReactElementWrapper.spec.tsx +452 -452
- package/src/widgets/ReactElementWrapper.tsx +108 -108
- package/src/widgets/Resizer.scss +43 -43
- package/src/widgets/Resizer.tsx +200 -200
- package/src/widgets/Sandbox.ts +103 -103
- package/src/widgets/Section.scss +55 -55
- package/src/widgets/Section.tsx +187 -187
- package/src/widgets/animations.scss +10 -10
- package/src/widgets/autoFocus.ts +9 -9
- package/src/widgets/cx.ts +63 -63
- package/src/widgets/drag-drop/DragClone.scss +35 -35
- package/src/widgets/drag-drop/DragHandle.scss +18 -18
- package/src/widgets/drag-drop/DragHandle.tsx +47 -47
- package/src/widgets/drag-drop/DragSource.scss +26 -26
- package/src/widgets/drag-drop/DragSource.tsx +237 -237
- package/src/widgets/drag-drop/DropZone.scss +76 -76
- package/src/widgets/drag-drop/DropZone.tsx +353 -353
- package/src/widgets/drag-drop/index.scss +3 -3
- package/src/widgets/drag-drop/index.ts +4 -4
- package/src/widgets/drag-drop/ops.tsx +422 -422
- package/src/widgets/drag-drop/variables.scss +14 -14
- package/src/widgets/enableAllInternalDependencies.ts +11 -11
- package/src/widgets/form/Calendar.scss +199 -199
- package/src/widgets/form/Calendar.tsx +760 -760
- package/src/widgets/form/Calendar.variables.scss +63 -63
- package/src/widgets/form/Checkbox.scss +129 -129
- package/src/widgets/form/Checkbox.tsx +287 -287
- package/src/widgets/form/Checkbox.variables.scss +39 -39
- package/src/widgets/form/ColorField.scss +98 -98
- package/src/widgets/form/ColorField.tsx +497 -497
- package/src/widgets/form/ColorPicker.scss +285 -285
- package/src/widgets/form/ColorPicker.tsx +544 -544
- package/src/widgets/form/ColorPicker.variables.scss +22 -22
- package/src/widgets/form/DateField.ts +21 -21
- package/src/widgets/form/DateTimeField.scss +92 -92
- package/src/widgets/form/DateTimeField.tsx +726 -726
- package/src/widgets/form/DateTimePicker.scss +46 -46
- package/src/widgets/form/DateTimePicker.tsx +429 -429
- package/src/widgets/form/Field.scss +164 -164
- package/src/widgets/form/Field.tsx +608 -608
- package/src/widgets/form/FieldGroup.ts +10 -10
- package/src/widgets/form/FieldIcon.ts +61 -61
- package/src/widgets/form/HelpText.scss +24 -24
- package/src/widgets/form/HelpText.ts +15 -15
- package/src/widgets/form/Label.scss +37 -37
- package/src/widgets/form/Label.tsx +117 -117
- package/src/widgets/form/LabeledContainer.ts +77 -77
- package/src/widgets/form/LookupField.scss +221 -221
- package/src/widgets/form/LookupField.spec.tsx +93 -93
- package/src/widgets/form/LookupField.tsx +1421 -1421
- package/src/widgets/form/MonthField.scss +100 -100
- package/src/widgets/form/MonthField.tsx +670 -670
- package/src/widgets/form/MonthPicker.scss +125 -125
- package/src/widgets/form/MonthPicker.tsx +822 -822
- package/src/widgets/form/NumberField.scss +63 -63
- package/src/widgets/form/NumberField.tsx +543 -543
- package/src/widgets/form/Radio.scss +123 -123
- package/src/widgets/form/Radio.tsx +249 -249
- package/src/widgets/form/Radio.variables.scss +45 -45
- package/src/widgets/form/Select.scss +101 -101
- package/src/widgets/form/Select.tsx +327 -327
- package/src/widgets/form/Slider.scss +121 -121
- package/src/widgets/form/Slider.tsx +473 -473
- package/src/widgets/form/Switch.scss +142 -142
- package/src/widgets/form/Switch.tsx +176 -176
- package/src/widgets/form/TextArea.scss +45 -45
- package/src/widgets/form/TextArea.tsx +229 -229
- package/src/widgets/form/TextField.scss +57 -57
- package/src/widgets/form/TextField.tsx +407 -407
- package/src/widgets/form/TimeField.ts +10 -10
- package/src/widgets/form/TimeList.tsx +105 -105
- package/src/widgets/form/UploadButton.scss +49 -49
- package/src/widgets/form/UploadButton.tsx +307 -307
- package/src/widgets/form/ValidationError.scss +22 -22
- package/src/widgets/form/ValidationError.tsx +72 -72
- package/src/widgets/form/ValidationGroup.spec.tsx +147 -147
- package/src/widgets/form/ValidationGroup.ts +141 -141
- package/src/widgets/form/Validator.ts +60 -60
- package/src/widgets/form/Wheel.scss +152 -152
- package/src/widgets/form/Wheel.tsx +314 -314
- package/src/widgets/form/index.scss +24 -24
- package/src/widgets/form/index.ts +28 -28
- package/src/widgets/form/variables.scss +355 -355
- package/src/widgets/grid/Grid.scss +640 -640
- package/src/widgets/grid/Grid.tsx +4243 -4243
- package/src/widgets/grid/GridCell.ts +143 -143
- package/src/widgets/grid/GridCellEditor.tsx +58 -58
- package/src/widgets/grid/GridRow.ts +302 -302
- package/src/widgets/grid/GridRowLine.ts +49 -49
- package/src/widgets/grid/Pagination.scss +115 -115
- package/src/widgets/grid/Pagination.tsx +126 -126
- package/src/widgets/grid/TreeNode.scss +90 -90
- package/src/widgets/grid/TreeNode.tsx +154 -154
- package/src/widgets/grid/createGridCellEditor.tsx +18 -18
- package/src/widgets/grid/index.scss +3 -3
- package/src/widgets/grid/index.ts +16 -16
- package/src/widgets/grid/variables.scss +137 -137
- package/src/widgets/icons/arrow-down.svg +3 -3
- package/src/widgets/icons/arrow-right.svg +2 -2
- package/src/widgets/icons/base.svg +104 -104
- package/src/widgets/icons/calendar-old.svg +169 -169
- package/src/widgets/icons/calendar.svg +187 -187
- package/src/widgets/icons/calendar.tsx +22 -22
- package/src/widgets/icons/check.tsx +14 -14
- package/src/widgets/icons/clear.svg +74 -74
- package/src/widgets/icons/clear.tsx +16 -16
- package/src/widgets/icons/close.svg +74 -74
- package/src/widgets/icons/close.tsx +20 -20
- package/src/widgets/icons/cx.tsx +39 -39
- package/src/widgets/icons/drop-down.tsx +16 -16
- package/src/widgets/icons/dropdown-arrow.svg +61 -61
- package/src/widgets/icons/file.svg +4 -4
- package/src/widgets/icons/file.tsx +14 -14
- package/src/widgets/icons/folder-open.svg +5 -5
- package/src/widgets/icons/folder-open.tsx +16 -16
- package/src/widgets/icons/folder.svg +58 -58
- package/src/widgets/icons/folder.tsx +14 -14
- package/src/widgets/icons/forward.svg +67 -67
- package/src/widgets/icons/forward.tsx +23 -23
- package/src/widgets/icons/index.ts +14 -14
- package/src/widgets/icons/loading.svg +4 -4
- package/src/widgets/icons/loading.tsx +25 -25
- package/src/widgets/icons/menu.tsx +18 -18
- package/src/widgets/icons/pixel-picker.tsx +18 -18
- package/src/widgets/icons/registry.ts +56 -56
- package/src/widgets/icons/search.svg +107 -107
- package/src/widgets/icons/search.tsx +14 -14
- package/src/widgets/icons/sort-asc.svg +3 -3
- package/src/widgets/icons/sort-asc.tsx +15 -15
- package/src/widgets/icons/square.tsx +19 -19
- package/src/widgets/index.d.ts +55 -55
- package/src/widgets/index.scss +16 -16
- package/src/widgets/index.ts +58 -58
- package/src/widgets/nav/Link.scss +20 -20
- package/src/widgets/nav/Link.ts +11 -11
- package/src/widgets/nav/LinkButton.ts +176 -176
- package/src/widgets/nav/Menu.scss +76 -76
- package/src/widgets/nav/Menu.tsx +489 -489
- package/src/widgets/nav/Menu.variables.scss +25 -25
- package/src/widgets/nav/MenuItem.scss +130 -130
- package/src/widgets/nav/MenuItem.tsx +525 -525
- package/src/widgets/nav/MenuSpacer.ts +18 -18
- package/src/widgets/nav/RedirectRoute.ts +49 -49
- package/src/widgets/nav/Route.spec.tsx +24 -24
- package/src/widgets/nav/Route.ts +142 -142
- package/src/widgets/nav/Scroller.scss +148 -148
- package/src/widgets/nav/Scroller.tsx +252 -252
- package/src/widgets/nav/Submenu.ts +6 -6
- package/src/widgets/nav/Tab.scss +82 -82
- package/src/widgets/nav/Tab.ts +120 -120
- package/src/widgets/nav/Tab.variables.scss +84 -84
- package/src/widgets/nav/cover.scss +22 -22
- package/src/widgets/nav/index.scss +5 -5
- package/src/widgets/nav/index.ts +10 -10
- package/src/widgets/nav/variables.scss +27 -27
- package/src/widgets/overlay/ContextMenu.ts +42 -42
- package/src/widgets/overlay/Dropdown.scss +186 -186
- package/src/widgets/overlay/Dropdown.tsx +762 -762
- package/src/widgets/overlay/FlyweightTooltipTracker.ts +57 -57
- package/src/widgets/overlay/MsgBox.tsx +141 -141
- package/src/widgets/overlay/Overlay.scss +68 -68
- package/src/widgets/overlay/Overlay.tsx +947 -947
- package/src/widgets/overlay/Toast.scss +163 -163
- package/src/widgets/overlay/Toast.ts +111 -111
- package/src/widgets/overlay/Tooltip.scss +177 -177
- package/src/widgets/overlay/Tooltip.tsx +393 -393
- package/src/widgets/overlay/Window.scss +129 -129
- package/src/widgets/overlay/Window.tsx +299 -299
- package/src/widgets/overlay/Window.variables.scss +62 -62
- package/src/widgets/overlay/alerts.ts +46 -46
- package/src/widgets/overlay/captureMouse.scss +13 -13
- package/src/widgets/overlay/captureMouse.ts +195 -195
- package/src/widgets/overlay/createHotPromiseWindowFactory.ts +71 -71
- package/src/widgets/overlay/index.scss +15 -15
- package/src/widgets/overlay/index.ts +11 -11
- package/src/widgets/overlay/tooltip-ops.ts +173 -173
- package/src/widgets/overlay/variables.scss +85 -85
- package/src/widgets/variables.scss +146 -146
- package/tsconfig.compile.json +4 -4
- package/tsconfig.json +34 -34
- package/tsconfig.mocha.json +14 -14
|
@@ -1,452 +1,452 @@
|
|
|
1
|
-
import { Store } from "../data/Store";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
import { createTestRenderer, act } from "../util/test/createTestRenderer";
|
|
4
|
-
import { VDOM } from "../ui/Widget";
|
|
5
|
-
import {
|
|
6
|
-
ReactFunctionComponent,
|
|
7
|
-
ReactCounterComponent,
|
|
8
|
-
ReactClassComponent,
|
|
9
|
-
ReactPureComponent,
|
|
10
|
-
ReactRefEffectComponent,
|
|
11
|
-
ReactEffectStateComponent,
|
|
12
|
-
ReactPropsComponent,
|
|
13
|
-
} from "./HtmlElement.spec.helpers";
|
|
14
|
-
import { Controller } from "../ui/Controller";
|
|
15
|
-
import { createAccessorModelProxy } from "../data/createAccessorModelProxy";
|
|
16
|
-
import { ReactElementWrapper } from "./ReactElementWrapper";
|
|
17
|
-
|
|
18
|
-
describe("ReactElementWrapper", () => {
|
|
19
|
-
it("renders React components as tag", async () => {
|
|
20
|
-
class MyReactComponent extends VDOM.Component<any> {
|
|
21
|
-
render() {
|
|
22
|
-
return VDOM.createElement("div", { className: "my-component" }, this.props.children);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let store = new Store();
|
|
27
|
-
|
|
28
|
-
const component = await createTestRenderer(
|
|
29
|
-
store,
|
|
30
|
-
<cx>
|
|
31
|
-
<MyReactComponent>
|
|
32
|
-
<span>Child content</span>
|
|
33
|
-
</MyReactComponent>
|
|
34
|
-
</cx>,
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
let tree = component.toJSON();
|
|
38
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
39
|
-
assert.equal(tree.type, "div");
|
|
40
|
-
assert.equal(tree.props.className, "my-component");
|
|
41
|
-
assert(tree.children && tree.children.length === 1, "Expected one child");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("renders React function components with props", async () => {
|
|
45
|
-
let store = new Store();
|
|
46
|
-
|
|
47
|
-
const component = await createTestRenderer(
|
|
48
|
-
store,
|
|
49
|
-
<cx>
|
|
50
|
-
<ReactFunctionComponent title="Test Title">
|
|
51
|
-
<span>Child content</span>
|
|
52
|
-
</ReactFunctionComponent>
|
|
53
|
-
</cx>,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
let tree = component.toJSON();
|
|
57
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
58
|
-
assert.equal(tree.type, "div");
|
|
59
|
-
assert.equal(tree.props.className, "react-function-component");
|
|
60
|
-
assert(tree.children && tree.children.length === 2, "Expected two children (h3 and div)");
|
|
61
|
-
|
|
62
|
-
let h3 = tree.children[0] as any;
|
|
63
|
-
assert.equal(h3.type, "h3");
|
|
64
|
-
assert.deepEqual(h3.children, ["Test Title"]);
|
|
65
|
-
|
|
66
|
-
let contentDiv = tree.children[1] as any;
|
|
67
|
-
assert.equal(contentDiv.type, "div");
|
|
68
|
-
assert.equal(contentDiv.props.className, "content");
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("renders React function components with hooks", async () => {
|
|
72
|
-
let store = new Store();
|
|
73
|
-
|
|
74
|
-
const component = await createTestRenderer(
|
|
75
|
-
store,
|
|
76
|
-
<cx>
|
|
77
|
-
<ReactCounterComponent initialCount={5} />
|
|
78
|
-
</cx>,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
let tree = component.toJSON();
|
|
82
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
83
|
-
assert.equal(tree.type, "div");
|
|
84
|
-
assert.equal(tree.props.className, "react-counter");
|
|
85
|
-
assert(tree.children && tree.children.length === 2, "Expected two children (span and button)");
|
|
86
|
-
|
|
87
|
-
let span = tree.children[0] as any;
|
|
88
|
-
assert.equal(span.type, "span");
|
|
89
|
-
assert.equal(span.props.className, "count");
|
|
90
|
-
assert.deepEqual(span.children, ["5"]);
|
|
91
|
-
|
|
92
|
-
let button = tree.children[1] as any;
|
|
93
|
-
assert.equal(button.type, "button");
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("renders React class components with props", async () => {
|
|
97
|
-
let store = new Store();
|
|
98
|
-
|
|
99
|
-
const component = await createTestRenderer(
|
|
100
|
-
store,
|
|
101
|
-
<cx>
|
|
102
|
-
<ReactClassComponent label="Test Label">
|
|
103
|
-
<span>Class child content</span>
|
|
104
|
-
</ReactClassComponent>
|
|
105
|
-
</cx>,
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
let tree = component.toJSON();
|
|
109
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
110
|
-
assert.equal(tree.type, "div");
|
|
111
|
-
assert(tree.props.className.includes("react-class-component"), "Expected react-class-component class");
|
|
112
|
-
|
|
113
|
-
assert(tree.children && tree.children.length === 2, "Expected two children (label and div)");
|
|
114
|
-
|
|
115
|
-
let label = tree.children[0] as any;
|
|
116
|
-
assert.equal(label.type, "label");
|
|
117
|
-
assert.deepEqual(label.children, ["Test Label"]);
|
|
118
|
-
|
|
119
|
-
let bodyDiv = tree.children[1] as any;
|
|
120
|
-
assert.equal(bodyDiv.type, "div");
|
|
121
|
-
assert.equal(bodyDiv.props.className, "body");
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("renders React PureComponent", async () => {
|
|
125
|
-
let store = new Store();
|
|
126
|
-
|
|
127
|
-
const component = await createTestRenderer(
|
|
128
|
-
store,
|
|
129
|
-
<cx>
|
|
130
|
-
<ReactPureComponent value="Pure Value" />
|
|
131
|
-
</cx>,
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
let tree = component.toJSON();
|
|
135
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
136
|
-
assert.equal(tree.type, "span");
|
|
137
|
-
assert.equal(tree.props.className, "react-pure-component");
|
|
138
|
-
assert.deepEqual(tree.children, ["Pure Value"]);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("renders React function component with useRef and useEffect", async () => {
|
|
142
|
-
let store = new Store();
|
|
143
|
-
let mountedElement: HTMLDivElement | null = null;
|
|
144
|
-
|
|
145
|
-
const component = await createTestRenderer(
|
|
146
|
-
store,
|
|
147
|
-
<cx>
|
|
148
|
-
<ReactRefEffectComponent
|
|
149
|
-
onMount={(el) => {
|
|
150
|
-
mountedElement = el;
|
|
151
|
-
}}
|
|
152
|
-
/>
|
|
153
|
-
</cx>,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
let tree = component.toJSON();
|
|
157
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
158
|
-
assert.equal(tree.type, "div");
|
|
159
|
-
assert.equal(tree.props.className, "react-ref-effect-component");
|
|
160
|
-
assert.deepEqual(tree.children, ["Component with ref and effect"]);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("renders React function component with useEffect that updates state", async () => {
|
|
164
|
-
let store = new Store();
|
|
165
|
-
|
|
166
|
-
const component = await createTestRenderer(
|
|
167
|
-
store,
|
|
168
|
-
<cx>
|
|
169
|
-
<ReactEffectStateComponent value="Test" />
|
|
170
|
-
</cx>,
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
let tree = component.toJSON();
|
|
174
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
175
|
-
assert.equal(tree.type, "div");
|
|
176
|
-
assert.equal(tree.props.className, "react-effect-state-component");
|
|
177
|
-
assert(tree.children && tree.children.length === 2, "Expected two children");
|
|
178
|
-
|
|
179
|
-
let processedSpan = tree.children[0] as any;
|
|
180
|
-
assert.equal(processedSpan.type, "span");
|
|
181
|
-
assert.equal(processedSpan.props.className, "processed");
|
|
182
|
-
// After act(), useEffect should have run and updated state
|
|
183
|
-
assert.deepEqual(processedSpan.children, ["Processed: Test"]);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("translates CxJS accessor bindings to React component props", async () => {
|
|
187
|
-
interface StoreModel {
|
|
188
|
-
text: string;
|
|
189
|
-
count: number;
|
|
190
|
-
enabled: boolean;
|
|
191
|
-
tags: string[];
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
let $store = createAccessorModelProxy<StoreModel>();
|
|
195
|
-
|
|
196
|
-
// First verify jsx transform output
|
|
197
|
-
const widget = (
|
|
198
|
-
<cx>
|
|
199
|
-
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} tags={$store.tags} />
|
|
200
|
-
</cx>
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
assert.equal(widget.$type, ReactElementWrapper, "React component should use ReactElementWrapper as $type");
|
|
204
|
-
assert.equal(widget.componentType, ReactPropsComponent, "React component should be set as componentType");
|
|
205
|
-
assert.equal(typeof widget.text, "function", "Accessor chain text should be a function");
|
|
206
|
-
assert.equal(widget.text.toString(), "text", "Accessor chain text should resolve to path");
|
|
207
|
-
|
|
208
|
-
// Now verify rendering
|
|
209
|
-
let store = new Store<StoreModel>({
|
|
210
|
-
data: {
|
|
211
|
-
text: "Bound Text",
|
|
212
|
-
count: 42,
|
|
213
|
-
enabled: true,
|
|
214
|
-
tags: ["a", "b", "c"],
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
const component = await createTestRenderer(store, widget);
|
|
219
|
-
|
|
220
|
-
let tree = component.toJSON();
|
|
221
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
222
|
-
assert.equal(tree.type, "div");
|
|
223
|
-
|
|
224
|
-
let textSpan = tree.children![0] as any;
|
|
225
|
-
assert.deepEqual(textSpan.children, ["Bound Text"]);
|
|
226
|
-
|
|
227
|
-
let countSpan = tree.children![1] as any;
|
|
228
|
-
assert.deepEqual(countSpan.children, ["42"]);
|
|
229
|
-
|
|
230
|
-
let enabledSpan = tree.children![2] as any;
|
|
231
|
-
assert.deepEqual(enabledSpan.children, ["yes"]);
|
|
232
|
-
|
|
233
|
-
let tagsSpan = tree.children![3] as any;
|
|
234
|
-
assert.deepEqual(tagsSpan.children, ["a, b, c"]);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it("supports visible prop on React components", async () => {
|
|
238
|
-
interface StoreModel {
|
|
239
|
-
show: boolean;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let $store = createAccessorModelProxy<StoreModel>();
|
|
243
|
-
|
|
244
|
-
let store = new Store<StoreModel>({
|
|
245
|
-
data: {
|
|
246
|
-
show: false,
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const component = await createTestRenderer(
|
|
251
|
-
store,
|
|
252
|
-
<cx>
|
|
253
|
-
<div>
|
|
254
|
-
<ReactFunctionComponent title="Visible Test" visible={$store.show} />
|
|
255
|
-
<span>Always visible</span>
|
|
256
|
-
</div>
|
|
257
|
-
</cx>,
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
let tree = component.toJSON();
|
|
261
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
262
|
-
// When visible=false, the React component should not render
|
|
263
|
-
assert.equal(tree.children!.length, 1, "Expected only the span to be visible");
|
|
264
|
-
assert.equal((tree.children![0] as any).type, "span");
|
|
265
|
-
|
|
266
|
-
// Update store to make component visible
|
|
267
|
-
await act(async () => {
|
|
268
|
-
store.set("show", true);
|
|
269
|
-
});
|
|
270
|
-
let tree2 = component.toJSON();
|
|
271
|
-
assert(tree2 && !Array.isArray(tree2), "Expected single element");
|
|
272
|
-
assert.equal(tree2.children!.length, 2, "Expected both children to be visible");
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it("supports controller prop on React components", async () => {
|
|
276
|
-
let controllerInitialized = false;
|
|
277
|
-
|
|
278
|
-
class TestController extends Controller {
|
|
279
|
-
onInit() {
|
|
280
|
-
controllerInitialized = true;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
interface StoreModel {
|
|
285
|
-
text: string;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
let $store = createAccessorModelProxy<StoreModel>();
|
|
289
|
-
|
|
290
|
-
let store = new Store<StoreModel>({
|
|
291
|
-
data: {
|
|
292
|
-
text: "Controller Test",
|
|
293
|
-
},
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
const component = await createTestRenderer(
|
|
297
|
-
store,
|
|
298
|
-
<cx>
|
|
299
|
-
<ReactPropsComponent text={$store.text} count={10} enabled={true} controller={TestController} />
|
|
300
|
-
</cx>,
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
let tree = component.toJSON();
|
|
304
|
-
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
305
|
-
assert.equal(controllerInitialized, true, "Controller should be initialized");
|
|
306
|
-
|
|
307
|
-
let textSpan = tree.children![0] as any;
|
|
308
|
-
assert.deepEqual(textSpan.children, ["Controller Test"]);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
it("updates React component when bound store data changes", async () => {
|
|
312
|
-
interface StoreModel {
|
|
313
|
-
text: string;
|
|
314
|
-
count: number;
|
|
315
|
-
enabled: boolean;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
let $store = createAccessorModelProxy<StoreModel>();
|
|
319
|
-
|
|
320
|
-
let store = new Store<StoreModel>({
|
|
321
|
-
data: {
|
|
322
|
-
text: "Initial",
|
|
323
|
-
count: 1,
|
|
324
|
-
enabled: false,
|
|
325
|
-
},
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
const component = await createTestRenderer(
|
|
329
|
-
store,
|
|
330
|
-
<cx>
|
|
331
|
-
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} />
|
|
332
|
-
</cx>,
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
let tree1 = component.toJSON() as any;
|
|
336
|
-
assert.deepEqual(tree1.children[0].children, ["Initial"]);
|
|
337
|
-
assert.deepEqual(tree1.children[1].children, ["1"]);
|
|
338
|
-
assert.deepEqual(tree1.children[2].children, ["no"]);
|
|
339
|
-
|
|
340
|
-
// Update store
|
|
341
|
-
await act(async () => {
|
|
342
|
-
store.set("text", "Updated");
|
|
343
|
-
store.set("count", 99);
|
|
344
|
-
store.set("enabled", true);
|
|
345
|
-
});
|
|
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
|
-
});
|
|
1
|
+
import { Store } from "../data/Store";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
import { createTestRenderer, act } from "../util/test/createTestRenderer";
|
|
4
|
+
import { VDOM } from "../ui/Widget";
|
|
5
|
+
import {
|
|
6
|
+
ReactFunctionComponent,
|
|
7
|
+
ReactCounterComponent,
|
|
8
|
+
ReactClassComponent,
|
|
9
|
+
ReactPureComponent,
|
|
10
|
+
ReactRefEffectComponent,
|
|
11
|
+
ReactEffectStateComponent,
|
|
12
|
+
ReactPropsComponent,
|
|
13
|
+
} from "./HtmlElement.spec.helpers";
|
|
14
|
+
import { Controller } from "../ui/Controller";
|
|
15
|
+
import { createAccessorModelProxy } from "../data/createAccessorModelProxy";
|
|
16
|
+
import { ReactElementWrapper } from "./ReactElementWrapper";
|
|
17
|
+
|
|
18
|
+
describe("ReactElementWrapper", () => {
|
|
19
|
+
it("renders React components as tag", async () => {
|
|
20
|
+
class MyReactComponent extends VDOM.Component<any> {
|
|
21
|
+
render() {
|
|
22
|
+
return VDOM.createElement("div", { className: "my-component" }, this.props.children);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let store = new Store();
|
|
27
|
+
|
|
28
|
+
const component = await createTestRenderer(
|
|
29
|
+
store,
|
|
30
|
+
<cx>
|
|
31
|
+
<MyReactComponent>
|
|
32
|
+
<span>Child content</span>
|
|
33
|
+
</MyReactComponent>
|
|
34
|
+
</cx>,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
let tree = component.toJSON();
|
|
38
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
39
|
+
assert.equal(tree.type, "div");
|
|
40
|
+
assert.equal(tree.props.className, "my-component");
|
|
41
|
+
assert(tree.children && tree.children.length === 1, "Expected one child");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("renders React function components with props", async () => {
|
|
45
|
+
let store = new Store();
|
|
46
|
+
|
|
47
|
+
const component = await createTestRenderer(
|
|
48
|
+
store,
|
|
49
|
+
<cx>
|
|
50
|
+
<ReactFunctionComponent title="Test Title">
|
|
51
|
+
<span>Child content</span>
|
|
52
|
+
</ReactFunctionComponent>
|
|
53
|
+
</cx>,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
let tree = component.toJSON();
|
|
57
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
58
|
+
assert.equal(tree.type, "div");
|
|
59
|
+
assert.equal(tree.props.className, "react-function-component");
|
|
60
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (h3 and div)");
|
|
61
|
+
|
|
62
|
+
let h3 = tree.children[0] as any;
|
|
63
|
+
assert.equal(h3.type, "h3");
|
|
64
|
+
assert.deepEqual(h3.children, ["Test Title"]);
|
|
65
|
+
|
|
66
|
+
let contentDiv = tree.children[1] as any;
|
|
67
|
+
assert.equal(contentDiv.type, "div");
|
|
68
|
+
assert.equal(contentDiv.props.className, "content");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("renders React function components with hooks", async () => {
|
|
72
|
+
let store = new Store();
|
|
73
|
+
|
|
74
|
+
const component = await createTestRenderer(
|
|
75
|
+
store,
|
|
76
|
+
<cx>
|
|
77
|
+
<ReactCounterComponent initialCount={5} />
|
|
78
|
+
</cx>,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
let tree = component.toJSON();
|
|
82
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
83
|
+
assert.equal(tree.type, "div");
|
|
84
|
+
assert.equal(tree.props.className, "react-counter");
|
|
85
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (span and button)");
|
|
86
|
+
|
|
87
|
+
let span = tree.children[0] as any;
|
|
88
|
+
assert.equal(span.type, "span");
|
|
89
|
+
assert.equal(span.props.className, "count");
|
|
90
|
+
assert.deepEqual(span.children, ["5"]);
|
|
91
|
+
|
|
92
|
+
let button = tree.children[1] as any;
|
|
93
|
+
assert.equal(button.type, "button");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("renders React class components with props", async () => {
|
|
97
|
+
let store = new Store();
|
|
98
|
+
|
|
99
|
+
const component = await createTestRenderer(
|
|
100
|
+
store,
|
|
101
|
+
<cx>
|
|
102
|
+
<ReactClassComponent label="Test Label">
|
|
103
|
+
<span>Class child content</span>
|
|
104
|
+
</ReactClassComponent>
|
|
105
|
+
</cx>,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
let tree = component.toJSON();
|
|
109
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
110
|
+
assert.equal(tree.type, "div");
|
|
111
|
+
assert(tree.props.className.includes("react-class-component"), "Expected react-class-component class");
|
|
112
|
+
|
|
113
|
+
assert(tree.children && tree.children.length === 2, "Expected two children (label and div)");
|
|
114
|
+
|
|
115
|
+
let label = tree.children[0] as any;
|
|
116
|
+
assert.equal(label.type, "label");
|
|
117
|
+
assert.deepEqual(label.children, ["Test Label"]);
|
|
118
|
+
|
|
119
|
+
let bodyDiv = tree.children[1] as any;
|
|
120
|
+
assert.equal(bodyDiv.type, "div");
|
|
121
|
+
assert.equal(bodyDiv.props.className, "body");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("renders React PureComponent", async () => {
|
|
125
|
+
let store = new Store();
|
|
126
|
+
|
|
127
|
+
const component = await createTestRenderer(
|
|
128
|
+
store,
|
|
129
|
+
<cx>
|
|
130
|
+
<ReactPureComponent value="Pure Value" />
|
|
131
|
+
</cx>,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
let tree = component.toJSON();
|
|
135
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
136
|
+
assert.equal(tree.type, "span");
|
|
137
|
+
assert.equal(tree.props.className, "react-pure-component");
|
|
138
|
+
assert.deepEqual(tree.children, ["Pure Value"]);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("renders React function component with useRef and useEffect", async () => {
|
|
142
|
+
let store = new Store();
|
|
143
|
+
let mountedElement: HTMLDivElement | null = null;
|
|
144
|
+
|
|
145
|
+
const component = await createTestRenderer(
|
|
146
|
+
store,
|
|
147
|
+
<cx>
|
|
148
|
+
<ReactRefEffectComponent
|
|
149
|
+
onMount={(el) => {
|
|
150
|
+
mountedElement = el;
|
|
151
|
+
}}
|
|
152
|
+
/>
|
|
153
|
+
</cx>,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
let tree = component.toJSON();
|
|
157
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
158
|
+
assert.equal(tree.type, "div");
|
|
159
|
+
assert.equal(tree.props.className, "react-ref-effect-component");
|
|
160
|
+
assert.deepEqual(tree.children, ["Component with ref and effect"]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("renders React function component with useEffect that updates state", async () => {
|
|
164
|
+
let store = new Store();
|
|
165
|
+
|
|
166
|
+
const component = await createTestRenderer(
|
|
167
|
+
store,
|
|
168
|
+
<cx>
|
|
169
|
+
<ReactEffectStateComponent value="Test" />
|
|
170
|
+
</cx>,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
let tree = component.toJSON();
|
|
174
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
175
|
+
assert.equal(tree.type, "div");
|
|
176
|
+
assert.equal(tree.props.className, "react-effect-state-component");
|
|
177
|
+
assert(tree.children && tree.children.length === 2, "Expected two children");
|
|
178
|
+
|
|
179
|
+
let processedSpan = tree.children[0] as any;
|
|
180
|
+
assert.equal(processedSpan.type, "span");
|
|
181
|
+
assert.equal(processedSpan.props.className, "processed");
|
|
182
|
+
// After act(), useEffect should have run and updated state
|
|
183
|
+
assert.deepEqual(processedSpan.children, ["Processed: Test"]);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("translates CxJS accessor bindings to React component props", async () => {
|
|
187
|
+
interface StoreModel {
|
|
188
|
+
text: string;
|
|
189
|
+
count: number;
|
|
190
|
+
enabled: boolean;
|
|
191
|
+
tags: string[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
195
|
+
|
|
196
|
+
// First verify jsx transform output
|
|
197
|
+
const widget = (
|
|
198
|
+
<cx>
|
|
199
|
+
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} tags={$store.tags} />
|
|
200
|
+
</cx>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
assert.equal(widget.$type, ReactElementWrapper, "React component should use ReactElementWrapper as $type");
|
|
204
|
+
assert.equal(widget.componentType, ReactPropsComponent, "React component should be set as componentType");
|
|
205
|
+
assert.equal(typeof widget.text, "function", "Accessor chain text should be a function");
|
|
206
|
+
assert.equal(widget.text.toString(), "text", "Accessor chain text should resolve to path");
|
|
207
|
+
|
|
208
|
+
// Now verify rendering
|
|
209
|
+
let store = new Store<StoreModel>({
|
|
210
|
+
data: {
|
|
211
|
+
text: "Bound Text",
|
|
212
|
+
count: 42,
|
|
213
|
+
enabled: true,
|
|
214
|
+
tags: ["a", "b", "c"],
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const component = await createTestRenderer(store, widget);
|
|
219
|
+
|
|
220
|
+
let tree = component.toJSON();
|
|
221
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
222
|
+
assert.equal(tree.type, "div");
|
|
223
|
+
|
|
224
|
+
let textSpan = tree.children![0] as any;
|
|
225
|
+
assert.deepEqual(textSpan.children, ["Bound Text"]);
|
|
226
|
+
|
|
227
|
+
let countSpan = tree.children![1] as any;
|
|
228
|
+
assert.deepEqual(countSpan.children, ["42"]);
|
|
229
|
+
|
|
230
|
+
let enabledSpan = tree.children![2] as any;
|
|
231
|
+
assert.deepEqual(enabledSpan.children, ["yes"]);
|
|
232
|
+
|
|
233
|
+
let tagsSpan = tree.children![3] as any;
|
|
234
|
+
assert.deepEqual(tagsSpan.children, ["a, b, c"]);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("supports visible prop on React components", async () => {
|
|
238
|
+
interface StoreModel {
|
|
239
|
+
show: boolean;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
243
|
+
|
|
244
|
+
let store = new Store<StoreModel>({
|
|
245
|
+
data: {
|
|
246
|
+
show: false,
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const component = await createTestRenderer(
|
|
251
|
+
store,
|
|
252
|
+
<cx>
|
|
253
|
+
<div>
|
|
254
|
+
<ReactFunctionComponent title="Visible Test" visible={$store.show} />
|
|
255
|
+
<span>Always visible</span>
|
|
256
|
+
</div>
|
|
257
|
+
</cx>,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
let tree = component.toJSON();
|
|
261
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
262
|
+
// When visible=false, the React component should not render
|
|
263
|
+
assert.equal(tree.children!.length, 1, "Expected only the span to be visible");
|
|
264
|
+
assert.equal((tree.children![0] as any).type, "span");
|
|
265
|
+
|
|
266
|
+
// Update store to make component visible
|
|
267
|
+
await act(async () => {
|
|
268
|
+
store.set("show", true);
|
|
269
|
+
});
|
|
270
|
+
let tree2 = component.toJSON();
|
|
271
|
+
assert(tree2 && !Array.isArray(tree2), "Expected single element");
|
|
272
|
+
assert.equal(tree2.children!.length, 2, "Expected both children to be visible");
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("supports controller prop on React components", async () => {
|
|
276
|
+
let controllerInitialized = false;
|
|
277
|
+
|
|
278
|
+
class TestController extends Controller {
|
|
279
|
+
onInit() {
|
|
280
|
+
controllerInitialized = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
interface StoreModel {
|
|
285
|
+
text: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
289
|
+
|
|
290
|
+
let store = new Store<StoreModel>({
|
|
291
|
+
data: {
|
|
292
|
+
text: "Controller Test",
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const component = await createTestRenderer(
|
|
297
|
+
store,
|
|
298
|
+
<cx>
|
|
299
|
+
<ReactPropsComponent text={$store.text} count={10} enabled={true} controller={TestController} />
|
|
300
|
+
</cx>,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
let tree = component.toJSON();
|
|
304
|
+
assert(tree && !Array.isArray(tree), "Expected single element");
|
|
305
|
+
assert.equal(controllerInitialized, true, "Controller should be initialized");
|
|
306
|
+
|
|
307
|
+
let textSpan = tree.children![0] as any;
|
|
308
|
+
assert.deepEqual(textSpan.children, ["Controller Test"]);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it("updates React component when bound store data changes", async () => {
|
|
312
|
+
interface StoreModel {
|
|
313
|
+
text: string;
|
|
314
|
+
count: number;
|
|
315
|
+
enabled: boolean;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let $store = createAccessorModelProxy<StoreModel>();
|
|
319
|
+
|
|
320
|
+
let store = new Store<StoreModel>({
|
|
321
|
+
data: {
|
|
322
|
+
text: "Initial",
|
|
323
|
+
count: 1,
|
|
324
|
+
enabled: false,
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const component = await createTestRenderer(
|
|
329
|
+
store,
|
|
330
|
+
<cx>
|
|
331
|
+
<ReactPropsComponent text={$store.text} count={$store.count} enabled={$store.enabled} />
|
|
332
|
+
</cx>,
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
let tree1 = component.toJSON() as any;
|
|
336
|
+
assert.deepEqual(tree1.children[0].children, ["Initial"]);
|
|
337
|
+
assert.deepEqual(tree1.children[1].children, ["1"]);
|
|
338
|
+
assert.deepEqual(tree1.children[2].children, ["no"]);
|
|
339
|
+
|
|
340
|
+
// Update store
|
|
341
|
+
await act(async () => {
|
|
342
|
+
store.set("text", "Updated");
|
|
343
|
+
store.set("count", 99);
|
|
344
|
+
store.set("enabled", true);
|
|
345
|
+
});
|
|
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
|
+
});
|