cx 26.1.3 → 26.1.5
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/ui/exprHelpers.d.ts +12 -0
- package/build/ui/exprHelpers.js +17 -0
- package/build/ui/tpl.d.ts +5 -3
- package/build/ui/tpl.js +11 -4
- package/build.js +133 -133
- package/dist/manifest.js +782 -779
- package/dist/ui.js +26 -4
- package/package.json +100 -100
- 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 -91
- 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.scss +6 -6
- 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 +412 -379
- package/src/ui/exprHelpers.ts +18 -0
- 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.spec.ts +69 -0
- package/src/ui/tpl.ts +17 -4
- package/src/ui/variables.scss +1 -1
- package/src/util/Component.spec.ts +411 -411
- package/src/util/Component.ts +301 -301
- 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.d.ts +11 -11
- 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
package/src/data/computable.ts
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import { Binding } from "./Binding";
|
|
2
|
-
import { isString } from "../util/isString";
|
|
3
|
-
import { isFunction } from "../util/isFunction";
|
|
4
|
-
import { AccessorChain, isAccessorChain } from "./createAccessorModelProxy";
|
|
5
|
-
import { CanMemoize, MemoSelector, Selector } from "./Selector";
|
|
6
|
-
import { Ref } from "./Ref";
|
|
7
|
-
|
|
8
|
-
export type ComputableSelector<T = any> = string | Selector<T> | AccessorChain<T> | CanMemoize<T>;
|
|
9
|
-
|
|
10
|
-
// Helper type to infer the value type from a selector, string, or accessor chain
|
|
11
|
-
export type InferSelectorValue<T> =
|
|
12
|
-
T extends Selector<infer R> ? R : T extends AccessorChain<infer R> ? R : T extends string ? any : never;
|
|
13
|
-
|
|
14
|
-
// Generic function with proper type inference for selectors
|
|
15
|
-
export function computable<T extends ComputableSelector[], R>(
|
|
16
|
-
...args: [...T, (...values: { [K in keyof T]: InferSelectorValue<T[K]> }) => R]
|
|
17
|
-
): MemoSelector<R>;
|
|
18
|
-
|
|
19
|
-
export function computable(...selectorsAndCompute: any[]): MemoSelector {
|
|
20
|
-
if (selectorsAndCompute.length == 0)
|
|
21
|
-
throw new Error("computable requires at least a compute function to be passed in arguments.");
|
|
22
|
-
|
|
23
|
-
let compute = selectorsAndCompute[selectorsAndCompute.length - 1];
|
|
24
|
-
if (typeof compute != "function") throw new Error("Last argument to the computable function should be a function.");
|
|
25
|
-
|
|
26
|
-
let inputs: Selector[] = [],
|
|
27
|
-
a;
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i + 1 < selectorsAndCompute.length; i++) {
|
|
30
|
-
a = selectorsAndCompute[i];
|
|
31
|
-
if (isString(a) || isAccessorChain(a)) inputs.push(Binding.get(a.toString()).value);
|
|
32
|
-
else if (a.memoize) inputs.push(a.memoize());
|
|
33
|
-
else if (isFunction(a)) inputs.push(a);
|
|
34
|
-
else throw new Error(`Invalid selector type '${typeof a}' received.`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function memoize(warmupData: any) {
|
|
38
|
-
let lastValue: any,
|
|
39
|
-
lastArgs = warmupData && inputs.map((s) => s(warmupData));
|
|
40
|
-
|
|
41
|
-
return function (data: any) {
|
|
42
|
-
let dirty = false;
|
|
43
|
-
|
|
44
|
-
if (!lastArgs) {
|
|
45
|
-
lastArgs = Array.from({ length: inputs.length });
|
|
46
|
-
dirty = true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < inputs.length; i++) {
|
|
50
|
-
let v = inputs[i](data);
|
|
51
|
-
if (v === lastArgs[i]) continue;
|
|
52
|
-
lastArgs[i] = v;
|
|
53
|
-
dirty = true;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (dirty) lastValue = compute.apply(null, lastArgs);
|
|
57
|
-
|
|
58
|
-
return lastValue;
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let selector: Selector = (data) =>
|
|
63
|
-
compute.apply(
|
|
64
|
-
null,
|
|
65
|
-
inputs.map((s) => s(data)),
|
|
66
|
-
);
|
|
67
|
-
selector.memoize = memoize;
|
|
68
|
-
return selector as MemoSelector;
|
|
69
|
-
}
|
|
1
|
+
import { Binding } from "./Binding";
|
|
2
|
+
import { isString } from "../util/isString";
|
|
3
|
+
import { isFunction } from "../util/isFunction";
|
|
4
|
+
import { AccessorChain, isAccessorChain } from "./createAccessorModelProxy";
|
|
5
|
+
import { CanMemoize, MemoSelector, Selector } from "./Selector";
|
|
6
|
+
import { Ref } from "./Ref";
|
|
7
|
+
|
|
8
|
+
export type ComputableSelector<T = any> = string | Selector<T> | AccessorChain<T> | CanMemoize<T>;
|
|
9
|
+
|
|
10
|
+
// Helper type to infer the value type from a selector, string, or accessor chain
|
|
11
|
+
export type InferSelectorValue<T> =
|
|
12
|
+
T extends Selector<infer R> ? R : T extends AccessorChain<infer R> ? R : T extends string ? any : never;
|
|
13
|
+
|
|
14
|
+
// Generic function with proper type inference for selectors
|
|
15
|
+
export function computable<T extends ComputableSelector[], R>(
|
|
16
|
+
...args: [...T, (...values: { [K in keyof T]: InferSelectorValue<T[K]> }) => R]
|
|
17
|
+
): MemoSelector<R>;
|
|
18
|
+
|
|
19
|
+
export function computable(...selectorsAndCompute: any[]): MemoSelector {
|
|
20
|
+
if (selectorsAndCompute.length == 0)
|
|
21
|
+
throw new Error("computable requires at least a compute function to be passed in arguments.");
|
|
22
|
+
|
|
23
|
+
let compute = selectorsAndCompute[selectorsAndCompute.length - 1];
|
|
24
|
+
if (typeof compute != "function") throw new Error("Last argument to the computable function should be a function.");
|
|
25
|
+
|
|
26
|
+
let inputs: Selector[] = [],
|
|
27
|
+
a;
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i + 1 < selectorsAndCompute.length; i++) {
|
|
30
|
+
a = selectorsAndCompute[i];
|
|
31
|
+
if (isString(a) || isAccessorChain(a)) inputs.push(Binding.get(a.toString()).value);
|
|
32
|
+
else if (a.memoize) inputs.push(a.memoize());
|
|
33
|
+
else if (isFunction(a)) inputs.push(a);
|
|
34
|
+
else throw new Error(`Invalid selector type '${typeof a}' received.`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function memoize(warmupData: any) {
|
|
38
|
+
let lastValue: any,
|
|
39
|
+
lastArgs = warmupData && inputs.map((s) => s(warmupData));
|
|
40
|
+
|
|
41
|
+
return function (data: any) {
|
|
42
|
+
let dirty = false;
|
|
43
|
+
|
|
44
|
+
if (!lastArgs) {
|
|
45
|
+
lastArgs = Array.from({ length: inputs.length });
|
|
46
|
+
dirty = true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
50
|
+
let v = inputs[i](data);
|
|
51
|
+
if (v === lastArgs[i]) continue;
|
|
52
|
+
lastArgs[i] = v;
|
|
53
|
+
dirty = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (dirty) lastValue = compute.apply(null, lastArgs);
|
|
57
|
+
|
|
58
|
+
return lastValue;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let selector: Selector = (data) =>
|
|
63
|
+
compute.apply(
|
|
64
|
+
null,
|
|
65
|
+
inputs.map((s) => s(data)),
|
|
66
|
+
);
|
|
67
|
+
selector.memoize = memoize;
|
|
68
|
+
return selector as MemoSelector;
|
|
69
|
+
}
|
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
import { createAccessorModelProxy, AccessorChain } from "./createAccessorModelProxy";
|
|
2
|
-
import { Prop, ResolvePropType } from "../ui/Prop";
|
|
3
|
-
import { Widget, WidgetConfig } from "../ui/Widget";
|
|
4
|
-
import assert from "assert";
|
|
5
|
-
|
|
6
|
-
interface Model {
|
|
7
|
-
firstName: string;
|
|
8
|
-
address: {
|
|
9
|
-
city: string;
|
|
10
|
-
streetNumber: number;
|
|
11
|
-
};
|
|
12
|
-
"@crazy": string;
|
|
13
|
-
users: User[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface User {
|
|
17
|
-
id: number;
|
|
18
|
-
name: string;
|
|
19
|
-
email: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
describe("createAccessorModelProxy", () => {
|
|
23
|
-
it("generates correct paths", () => {
|
|
24
|
-
let model = createAccessorModelProxy<Model>();
|
|
25
|
-
assert.strictEqual(model.firstName.toString(), "firstName");
|
|
26
|
-
assert.strictEqual(model.address.toString(), "address");
|
|
27
|
-
assert.strictEqual(model.address.city.toString(), "address.city");
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("can be used in string templates", () => {
|
|
31
|
-
let model = createAccessorModelProxy<Model>();
|
|
32
|
-
assert.strictEqual("address.city", `${model.address.city}`);
|
|
33
|
-
assert.strictEqual("address.city", "" + model.address.city);
|
|
34
|
-
assert.strictEqual("address.city.suffix", model.address.city + ".suffix");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("nameOf returns name of the last prop ", () => {
|
|
38
|
-
let model = createAccessorModelProxy<Model>();
|
|
39
|
-
assert.strictEqual(model.firstName.nameOf(), "firstName");
|
|
40
|
-
assert.strictEqual(model.address.nameOf(), "address");
|
|
41
|
-
assert.strictEqual(model.address.city.nameOf(), "city");
|
|
42
|
-
assert.strictEqual(model.address.nameOf(), "address");
|
|
43
|
-
|
|
44
|
-
let { streetNumber, city } = model.address;
|
|
45
|
-
assert.strictEqual(streetNumber.nameOf(), "streetNumber");
|
|
46
|
-
assert.strictEqual(city.nameOf(), "city");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("allows non-standard property identifiers ", () => {
|
|
50
|
-
let model = createAccessorModelProxy<Model>();
|
|
51
|
-
assert.strictEqual(model["@crazy"].nameOf(), "@crazy");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("AccessorChain<any> allows access to any property", () => {
|
|
55
|
-
// When using an untyped model (any), all property access should be allowed
|
|
56
|
-
let model = createAccessorModelProxy<any>();
|
|
57
|
-
|
|
58
|
-
// These should all be valid - no TypeScript errors
|
|
59
|
-
assert.strictEqual(model.foo.toString(), "foo");
|
|
60
|
-
assert.strictEqual(model.bar.baz.toString(), "bar.baz");
|
|
61
|
-
assert.strictEqual(model.deeply.nested.property.toString(), "deeply.nested.property");
|
|
62
|
-
assert.strictEqual(model.anyName.anyChild.anyGrandchild.toString(), "anyName.anyChild.anyGrandchild");
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("ResolvePropType extracts correct types from AccessorChain", () => {
|
|
66
|
-
let model = createAccessorModelProxy<Model>();
|
|
67
|
-
|
|
68
|
-
// ResolvePropType should extract the inner type from AccessorChain
|
|
69
|
-
type ResolvedString = ResolvePropType<typeof model.firstName>;
|
|
70
|
-
type ResolvedNumber = ResolvePropType<typeof model.address.streetNumber>;
|
|
71
|
-
type ResolvedUsers = ResolvePropType<typeof model.users>;
|
|
72
|
-
|
|
73
|
-
// These assignments verify the types are correctly inferred
|
|
74
|
-
// If types are wrong, TypeScript will error
|
|
75
|
-
const str: ResolvedString = "test";
|
|
76
|
-
const num: ResolvedNumber = 42;
|
|
77
|
-
const users: ResolvedUsers = [{ id: 1, name: "John", email: "john@example.com" }];
|
|
78
|
-
|
|
79
|
-
// Verify array element type is preserved
|
|
80
|
-
type UserArray = ResolvePropType<AccessorChain<User[]>>;
|
|
81
|
-
const userArray: UserArray = [{ id: 1, name: "Test", email: "test@test.com" }];
|
|
82
|
-
|
|
83
|
-
// Runtime assertion to make the test meaningful
|
|
84
|
-
assert.ok(true);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("generic widget infers type from AccessorChain in JSX", () => {
|
|
88
|
-
let model = createAccessorModelProxy<Model>();
|
|
89
|
-
|
|
90
|
-
// Simulates a generic widget config like LookupFieldConfig<TOption>
|
|
91
|
-
interface GenericWidgetConfig<T = unknown> extends WidgetConfig {
|
|
92
|
-
items?: AccessorChain<T[]>;
|
|
93
|
-
onProcess?: (item: T) => void;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Simulates a CxJS widget class
|
|
97
|
-
class GenericWidget<T = unknown> extends Widget<GenericWidgetConfig<T>> {}
|
|
98
|
-
|
|
99
|
-
// T should be inferred as User from model.users (AccessorChain<User[]>)
|
|
100
|
-
let widget = (
|
|
101
|
-
<cx>
|
|
102
|
-
<GenericWidget
|
|
103
|
-
items={model.users}
|
|
104
|
-
onProcess={(user) => {
|
|
105
|
-
// user should be typed as User
|
|
106
|
-
const id: number = user.id;
|
|
107
|
-
const name: string = user.name;
|
|
108
|
-
const email: string = user.email;
|
|
109
|
-
}}
|
|
110
|
-
/>
|
|
111
|
-
</cx>
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
assert.ok(true);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("generic widget infers type from Prop<T[]> in JSX", () => {
|
|
118
|
-
let model = createAccessorModelProxy<Model>();
|
|
119
|
-
|
|
120
|
-
// Uses Prop<T[]> like LookupFieldConfig does
|
|
121
|
-
interface GenericWidgetConfig<T = unknown> extends WidgetConfig {
|
|
122
|
-
items?: Prop<T[]>;
|
|
123
|
-
onProcess?: (item: T) => void;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
class GenericWidget<T = unknown> extends Widget<GenericWidgetConfig<T>> {}
|
|
127
|
-
|
|
128
|
-
// T should be inferred as User from model.users (AccessorChain<User[]>)
|
|
129
|
-
let widget = (
|
|
130
|
-
<cx>
|
|
131
|
-
<GenericWidget
|
|
132
|
-
items={model.users}
|
|
133
|
-
onProcess={(user) => {
|
|
134
|
-
// user should be typed as User
|
|
135
|
-
const id: number = user.id;
|
|
136
|
-
const name: string = user.name;
|
|
137
|
-
const email: string = user.email;
|
|
138
|
-
}}
|
|
139
|
-
/>
|
|
140
|
-
</cx>
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
assert.ok(true);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
1
|
+
import { createAccessorModelProxy, AccessorChain } from "./createAccessorModelProxy";
|
|
2
|
+
import { Prop, ResolvePropType } from "../ui/Prop";
|
|
3
|
+
import { Widget, WidgetConfig } from "../ui/Widget";
|
|
4
|
+
import assert from "assert";
|
|
5
|
+
|
|
6
|
+
interface Model {
|
|
7
|
+
firstName: string;
|
|
8
|
+
address: {
|
|
9
|
+
city: string;
|
|
10
|
+
streetNumber: number;
|
|
11
|
+
};
|
|
12
|
+
"@crazy": string;
|
|
13
|
+
users: User[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface User {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
email: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("createAccessorModelProxy", () => {
|
|
23
|
+
it("generates correct paths", () => {
|
|
24
|
+
let model = createAccessorModelProxy<Model>();
|
|
25
|
+
assert.strictEqual(model.firstName.toString(), "firstName");
|
|
26
|
+
assert.strictEqual(model.address.toString(), "address");
|
|
27
|
+
assert.strictEqual(model.address.city.toString(), "address.city");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("can be used in string templates", () => {
|
|
31
|
+
let model = createAccessorModelProxy<Model>();
|
|
32
|
+
assert.strictEqual("address.city", `${model.address.city}`);
|
|
33
|
+
assert.strictEqual("address.city", "" + model.address.city);
|
|
34
|
+
assert.strictEqual("address.city.suffix", model.address.city + ".suffix");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("nameOf returns name of the last prop ", () => {
|
|
38
|
+
let model = createAccessorModelProxy<Model>();
|
|
39
|
+
assert.strictEqual(model.firstName.nameOf(), "firstName");
|
|
40
|
+
assert.strictEqual(model.address.nameOf(), "address");
|
|
41
|
+
assert.strictEqual(model.address.city.nameOf(), "city");
|
|
42
|
+
assert.strictEqual(model.address.nameOf(), "address");
|
|
43
|
+
|
|
44
|
+
let { streetNumber, city } = model.address;
|
|
45
|
+
assert.strictEqual(streetNumber.nameOf(), "streetNumber");
|
|
46
|
+
assert.strictEqual(city.nameOf(), "city");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("allows non-standard property identifiers ", () => {
|
|
50
|
+
let model = createAccessorModelProxy<Model>();
|
|
51
|
+
assert.strictEqual(model["@crazy"].nameOf(), "@crazy");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("AccessorChain<any> allows access to any property", () => {
|
|
55
|
+
// When using an untyped model (any), all property access should be allowed
|
|
56
|
+
let model = createAccessorModelProxy<any>();
|
|
57
|
+
|
|
58
|
+
// These should all be valid - no TypeScript errors
|
|
59
|
+
assert.strictEqual(model.foo.toString(), "foo");
|
|
60
|
+
assert.strictEqual(model.bar.baz.toString(), "bar.baz");
|
|
61
|
+
assert.strictEqual(model.deeply.nested.property.toString(), "deeply.nested.property");
|
|
62
|
+
assert.strictEqual(model.anyName.anyChild.anyGrandchild.toString(), "anyName.anyChild.anyGrandchild");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("ResolvePropType extracts correct types from AccessorChain", () => {
|
|
66
|
+
let model = createAccessorModelProxy<Model>();
|
|
67
|
+
|
|
68
|
+
// ResolvePropType should extract the inner type from AccessorChain
|
|
69
|
+
type ResolvedString = ResolvePropType<typeof model.firstName>;
|
|
70
|
+
type ResolvedNumber = ResolvePropType<typeof model.address.streetNumber>;
|
|
71
|
+
type ResolvedUsers = ResolvePropType<typeof model.users>;
|
|
72
|
+
|
|
73
|
+
// These assignments verify the types are correctly inferred
|
|
74
|
+
// If types are wrong, TypeScript will error
|
|
75
|
+
const str: ResolvedString = "test";
|
|
76
|
+
const num: ResolvedNumber = 42;
|
|
77
|
+
const users: ResolvedUsers = [{ id: 1, name: "John", email: "john@example.com" }];
|
|
78
|
+
|
|
79
|
+
// Verify array element type is preserved
|
|
80
|
+
type UserArray = ResolvePropType<AccessorChain<User[]>>;
|
|
81
|
+
const userArray: UserArray = [{ id: 1, name: "Test", email: "test@test.com" }];
|
|
82
|
+
|
|
83
|
+
// Runtime assertion to make the test meaningful
|
|
84
|
+
assert.ok(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("generic widget infers type from AccessorChain in JSX", () => {
|
|
88
|
+
let model = createAccessorModelProxy<Model>();
|
|
89
|
+
|
|
90
|
+
// Simulates a generic widget config like LookupFieldConfig<TOption>
|
|
91
|
+
interface GenericWidgetConfig<T = unknown> extends WidgetConfig {
|
|
92
|
+
items?: AccessorChain<T[]>;
|
|
93
|
+
onProcess?: (item: T) => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Simulates a CxJS widget class
|
|
97
|
+
class GenericWidget<T = unknown> extends Widget<GenericWidgetConfig<T>> {}
|
|
98
|
+
|
|
99
|
+
// T should be inferred as User from model.users (AccessorChain<User[]>)
|
|
100
|
+
let widget = (
|
|
101
|
+
<cx>
|
|
102
|
+
<GenericWidget
|
|
103
|
+
items={model.users}
|
|
104
|
+
onProcess={(user) => {
|
|
105
|
+
// user should be typed as User
|
|
106
|
+
const id: number = user.id;
|
|
107
|
+
const name: string = user.name;
|
|
108
|
+
const email: string = user.email;
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
</cx>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
assert.ok(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("generic widget infers type from Prop<T[]> in JSX", () => {
|
|
118
|
+
let model = createAccessorModelProxy<Model>();
|
|
119
|
+
|
|
120
|
+
// Uses Prop<T[]> like LookupFieldConfig does
|
|
121
|
+
interface GenericWidgetConfig<T = unknown> extends WidgetConfig {
|
|
122
|
+
items?: Prop<T[]>;
|
|
123
|
+
onProcess?: (item: T) => void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class GenericWidget<T = unknown> extends Widget<GenericWidgetConfig<T>> {}
|
|
127
|
+
|
|
128
|
+
// T should be inferred as User from model.users (AccessorChain<User[]>)
|
|
129
|
+
let widget = (
|
|
130
|
+
<cx>
|
|
131
|
+
<GenericWidget
|
|
132
|
+
items={model.users}
|
|
133
|
+
onProcess={(user) => {
|
|
134
|
+
// user should be typed as User
|
|
135
|
+
const id: number = user.id;
|
|
136
|
+
const name: string = user.name;
|
|
137
|
+
const email: string = user.email;
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
</cx>
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
assert.ok(true);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
interface AccessorChainMethods {
|
|
2
|
-
toString(): string;
|
|
3
|
-
valueOf(): unknown;
|
|
4
|
-
nameOf(): string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type AccessorChainMap<M extends object> = {
|
|
8
|
-
[prop in Exclude<keyof M, keyof AccessorChainMethods>]: AccessorChain<M[prop]>;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
// Check if a type is `any` using the intersection trick
|
|
12
|
-
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
13
|
-
|
|
14
|
-
export type AccessorChain<M> = {
|
|
15
|
-
toString(): string;
|
|
16
|
-
valueOf(): M | undefined;
|
|
17
|
-
nameOf(): string;
|
|
18
|
-
} & (IsAny<M> extends true
|
|
19
|
-
? { [key: string]: any } // Allow any property access for `any` type
|
|
20
|
-
: M extends object
|
|
21
|
-
? AccessorChainMap<M>
|
|
22
|
-
: {});
|
|
23
|
-
|
|
24
|
-
const emptyFn = () => {};
|
|
25
|
-
|
|
26
|
-
export function createAccessorModelProxy<M>(chain: string = ""): AccessorChain<M> {
|
|
27
|
-
let lastOp: string | null = null;
|
|
28
|
-
|
|
29
|
-
const proxy = new Proxy(emptyFn, {
|
|
30
|
-
get: (_, name: string | symbol) => {
|
|
31
|
-
if (typeof name !== "string") return proxy;
|
|
32
|
-
|
|
33
|
-
switch (name) {
|
|
34
|
-
case "isAccessorChain":
|
|
35
|
-
return true;
|
|
36
|
-
|
|
37
|
-
case "toString":
|
|
38
|
-
case "valueOf":
|
|
39
|
-
case "nameOf":
|
|
40
|
-
lastOp = name;
|
|
41
|
-
return proxy;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let newChain = chain;
|
|
45
|
-
if (newChain.length > 0) newChain += ".";
|
|
46
|
-
newChain += name;
|
|
47
|
-
return createAccessorModelProxy(newChain);
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
apply(): string {
|
|
51
|
-
switch (lastOp) {
|
|
52
|
-
case "nameOf":
|
|
53
|
-
const lastDotIndex = chain.lastIndexOf(".");
|
|
54
|
-
return lastDotIndex > 0 ? chain.substring(lastDotIndex + 1) : chain;
|
|
55
|
-
|
|
56
|
-
default:
|
|
57
|
-
return chain;
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
return proxy as unknown as AccessorChain<M>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function isAccessorChain<M>(value: unknown): value is AccessorChain<M> {
|
|
65
|
-
return value != null && !!(value as any).isAccessorChain;
|
|
66
|
-
}
|
|
1
|
+
interface AccessorChainMethods {
|
|
2
|
+
toString(): string;
|
|
3
|
+
valueOf(): unknown;
|
|
4
|
+
nameOf(): string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type AccessorChainMap<M extends object> = {
|
|
8
|
+
[prop in Exclude<keyof M, keyof AccessorChainMethods>]: AccessorChain<M[prop]>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Check if a type is `any` using the intersection trick
|
|
12
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
13
|
+
|
|
14
|
+
export type AccessorChain<M> = {
|
|
15
|
+
toString(): string;
|
|
16
|
+
valueOf(): M | undefined;
|
|
17
|
+
nameOf(): string;
|
|
18
|
+
} & (IsAny<M> extends true
|
|
19
|
+
? { [key: string]: any } // Allow any property access for `any` type
|
|
20
|
+
: M extends object
|
|
21
|
+
? AccessorChainMap<M>
|
|
22
|
+
: {});
|
|
23
|
+
|
|
24
|
+
const emptyFn = () => {};
|
|
25
|
+
|
|
26
|
+
export function createAccessorModelProxy<M>(chain: string = ""): AccessorChain<M> {
|
|
27
|
+
let lastOp: string | null = null;
|
|
28
|
+
|
|
29
|
+
const proxy = new Proxy(emptyFn, {
|
|
30
|
+
get: (_, name: string | symbol) => {
|
|
31
|
+
if (typeof name !== "string") return proxy;
|
|
32
|
+
|
|
33
|
+
switch (name) {
|
|
34
|
+
case "isAccessorChain":
|
|
35
|
+
return true;
|
|
36
|
+
|
|
37
|
+
case "toString":
|
|
38
|
+
case "valueOf":
|
|
39
|
+
case "nameOf":
|
|
40
|
+
lastOp = name;
|
|
41
|
+
return proxy;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let newChain = chain;
|
|
45
|
+
if (newChain.length > 0) newChain += ".";
|
|
46
|
+
newChain += name;
|
|
47
|
+
return createAccessorModelProxy(newChain);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
apply(): string {
|
|
51
|
+
switch (lastOp) {
|
|
52
|
+
case "nameOf":
|
|
53
|
+
const lastDotIndex = chain.lastIndexOf(".");
|
|
54
|
+
return lastDotIndex > 0 ? chain.substring(lastDotIndex + 1) : chain;
|
|
55
|
+
|
|
56
|
+
default:
|
|
57
|
+
return chain;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
return proxy as unknown as AccessorChain<M>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isAccessorChain<M>(value: unknown): value is AccessorChain<M> {
|
|
65
|
+
return value != null && !!(value as any).isAccessorChain;
|
|
66
|
+
}
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import { createStructuredSelector } from "./createStructuredSelector";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
import { getSelector } from "./getSelector";
|
|
4
|
-
import { computable } from "./computable";
|
|
5
|
-
|
|
6
|
-
describe("createStructuredSelector", function () {
|
|
7
|
-
it("works", function () {
|
|
8
|
-
let structure = {
|
|
9
|
-
name: getSelector({ bind: "name" }),
|
|
10
|
-
};
|
|
11
|
-
let state = { name: "Joe" };
|
|
12
|
-
let selector = createStructuredSelector(structure);
|
|
13
|
-
assert.deepEqual(selector(state), { name: "Joe" });
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("does not memoize by default", function () {
|
|
17
|
-
let computes = 0;
|
|
18
|
-
let structure = {
|
|
19
|
-
name: computable("name", (name) => {
|
|
20
|
-
computes++;
|
|
21
|
-
return name;
|
|
22
|
-
}),
|
|
23
|
-
};
|
|
24
|
-
let state = { name: "Joe" };
|
|
25
|
-
let selector = createStructuredSelector(structure);
|
|
26
|
-
assert.deepEqual(selector(state), { name: "Joe" });
|
|
27
|
-
selector(state);
|
|
28
|
-
assert.deepEqual(computes, 2);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("supports memoize", function () {
|
|
32
|
-
let computes = 0;
|
|
33
|
-
let structure = {
|
|
34
|
-
name: computable("name", (name) => {
|
|
35
|
-
computes++;
|
|
36
|
-
return name;
|
|
37
|
-
}),
|
|
38
|
-
};
|
|
39
|
-
let state = { name: "Joe" };
|
|
40
|
-
let selector = createStructuredSelector(structure).memoize();
|
|
41
|
-
assert.deepEqual(selector(state), { name: "Joe" });
|
|
42
|
-
selector(state);
|
|
43
|
-
assert.deepEqual(computes, 1);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
1
|
+
import { createStructuredSelector } from "./createStructuredSelector";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
import { getSelector } from "./getSelector";
|
|
4
|
+
import { computable } from "./computable";
|
|
5
|
+
|
|
6
|
+
describe("createStructuredSelector", function () {
|
|
7
|
+
it("works", function () {
|
|
8
|
+
let structure = {
|
|
9
|
+
name: getSelector({ bind: "name" }),
|
|
10
|
+
};
|
|
11
|
+
let state = { name: "Joe" };
|
|
12
|
+
let selector = createStructuredSelector(structure);
|
|
13
|
+
assert.deepEqual(selector(state), { name: "Joe" });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("does not memoize by default", function () {
|
|
17
|
+
let computes = 0;
|
|
18
|
+
let structure = {
|
|
19
|
+
name: computable("name", (name) => {
|
|
20
|
+
computes++;
|
|
21
|
+
return name;
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
let state = { name: "Joe" };
|
|
25
|
+
let selector = createStructuredSelector(structure);
|
|
26
|
+
assert.deepEqual(selector(state), { name: "Joe" });
|
|
27
|
+
selector(state);
|
|
28
|
+
assert.deepEqual(computes, 2);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("supports memoize", function () {
|
|
32
|
+
let computes = 0;
|
|
33
|
+
let structure = {
|
|
34
|
+
name: computable("name", (name) => {
|
|
35
|
+
computes++;
|
|
36
|
+
return name;
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
let state = { name: "Joe" };
|
|
40
|
+
let selector = createStructuredSelector(structure).memoize();
|
|
41
|
+
assert.deepEqual(selector(state), { name: "Joe" });
|
|
42
|
+
selector(state);
|
|
43
|
+
assert.deepEqual(computes, 1);
|
|
44
|
+
});
|
|
45
|
+
});
|