cx 26.1.0 → 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/Widget.js +0 -5
- package/build/ui/adapter/ArrayAdapter.js +0 -2
- package/build/ui/adapter/DataAdapter.d.ts +3 -3
- package/build/util/Component.js +5 -0
- package/build/util/test/createTestRenderer.d.ts +3 -1
- package/build/util/test/createTestRenderer.js +8 -2
- package/build/widgets/icons/calendar.js +4 -3
- package/build/widgets/icons/check.js +2 -2
- package/build/widgets/icons/clear.js +2 -2
- package/build/widgets/icons/close.js +2 -2
- package/build/widgets/icons/cx.js +2 -2
- package/build/widgets/icons/drop-down.js +2 -2
- package/build/widgets/icons/file.js +2 -2
- package/build/widgets/icons/folder-open.js +2 -2
- package/build/widgets/icons/folder.js +2 -2
- package/build/widgets/icons/forward.js +2 -2
- package/build/widgets/icons/loading.js +2 -2
- package/build/widgets/icons/menu.js +2 -2
- package/build/widgets/icons/pixel-picker.js +2 -2
- package/build/widgets/icons/search.js +2 -2
- package/build/widgets/icons/sort-asc.js +2 -2
- package/build/widgets/icons/square.js +2 -2
- package/build.js +133 -133
- package/dist/manifest.js +863 -863
- package/dist/ui.js +1 -10
- package/dist/util.js +4 -0
- package/dist/widgets.js +377 -313
- package/package.json +100 -97
- 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/data/AggregateFunction.ts +171 -171
- package/src/data/ArrayElementView.spec.ts +88 -88
- package/src/data/ArrayElementView.ts +4 -3
- package/src/data/ArrayRef.ts +34 -34
- package/src/data/Binding.spec.ts +69 -69
- package/src/data/Expression.spec.ts +229 -229
- package/src/data/Expression.ts +233 -233
- package/src/data/Grouper.ts +158 -158
- package/src/data/Ref.spec.ts +79 -79
- package/src/data/Selector.ts +10 -10
- package/src/data/Store.spec.ts +22 -22
- package/src/data/StoreRef.spec.ts +24 -24
- package/src/data/StringTemplate.spec.ts +132 -132
- package/src/data/StructuredSelector.ts +146 -146
- 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/comparer.spec.ts +60 -60
- 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/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 -99
- package/src/hooks/useTrigger.ts +26 -26
- package/src/index.ts +7 -7
- package/src/jsx-runtime.spec.tsx +431 -431
- 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/CSSHelper.ts +17 -17
- package/src/ui/Container.tsx +216 -216
- package/src/ui/ContentResolver.spec.tsx +585 -583
- package/src/ui/ContentResolver.ts +132 -132
- package/src/ui/Controller.spec.tsx +574 -566
- package/src/ui/Controller.ts +202 -202
- package/src/ui/Culture.ts +159 -159
- package/src/ui/Cx.spec.tsx +210 -208
- package/src/ui/Cx.tsx +386 -386
- package/src/ui/DataProxy.spec.tsx +337 -337
- package/src/ui/DetachedScope.tsx +159 -159
- 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 -55
- 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 -230
- package/src/ui/PureContainer.tsx +19 -19
- package/src/ui/RenderingContext.ts +99 -99
- package/src/ui/Repeater.spec.tsx +143 -141
- package/src/ui/Repeater.ts +194 -194
- package/src/ui/Rescope.spec.tsx +199 -199
- package/src/ui/ResizeManager.ts +30 -30
- package/src/ui/Restate.spec.tsx +422 -418
- 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/Widget.spec.tsx +53 -53
- package/src/ui/Widget.tsx +301 -308
- package/src/ui/ZIndexManager.ts +11 -11
- 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 -452
- 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/ContentPlaceholder.spec.tsx +599 -587
- package/src/ui/layout/ContentPlaceholder.ts +133 -133
- package/src/ui/layout/FirstVisibleChildLayout.spec.tsx +207 -195
- 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/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 -381
- package/src/util/Component.ts +301 -296
- package/src/util/Console.ts +13 -13
- package/src/util/Debug.ts +71 -71
- 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/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/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/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/isArray.ts +3 -3
- 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 -12
- 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/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/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 +20 -15
- package/src/widgets/icons/check.tsx +2 -1
- package/src/widgets/icons/clear.svg +74 -74
- package/src/widgets/icons/clear.tsx +2 -1
- package/src/widgets/icons/close.svg +74 -74
- package/src/widgets/icons/close.tsx +2 -2
- package/src/widgets/icons/cx.tsx +2 -1
- package/src/widgets/icons/drop-down.tsx +2 -1
- package/src/widgets/icons/dropdown-arrow.svg +61 -61
- package/src/widgets/icons/file.svg +4 -4
- package/src/widgets/icons/file.tsx +2 -1
- package/src/widgets/icons/folder-open.svg +5 -5
- package/src/widgets/icons/folder-open.tsx +2 -1
- package/src/widgets/icons/folder.svg +58 -58
- package/src/widgets/icons/folder.tsx +2 -1
- package/src/widgets/icons/forward.svg +67 -67
- package/src/widgets/icons/forward.tsx +2 -1
- package/src/widgets/icons/index.ts +14 -14
- package/src/widgets/icons/loading.svg +4 -4
- package/src/widgets/icons/loading.tsx +2 -1
- package/src/widgets/icons/menu.tsx +2 -1
- package/src/widgets/icons/pixel-picker.tsx +2 -2
- package/src/widgets/icons/registry.ts +56 -56
- package/src/widgets/icons/search.svg +107 -107
- package/src/widgets/icons/search.tsx +2 -1
- package/src/widgets/icons/sort-asc.svg +3 -3
- package/src/widgets/icons/sort-asc.tsx +2 -1
- package/src/widgets/icons/square.tsx +2 -1
- 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/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/FlyweightTooltipTracker.ts +57 -57
- 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/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.variables.scss +62 -62
- 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/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,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
|
+
});
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import { MemoSelector, Selector } from "./Selector";
|
|
2
|
-
|
|
3
|
-
export interface StructuredSelectorConfig {
|
|
4
|
-
[prop: string]: Selector;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
// Helper type to infer result type from selector config
|
|
8
|
-
type InferStructuredSelectorResult<T extends StructuredSelectorConfig, C = {}> = {
|
|
9
|
-
[K in keyof T]: T[K] extends Selector<infer R> ? R : any;
|
|
10
|
-
} & C;
|
|
11
|
-
|
|
12
|
-
export function createStructuredSelector<S extends StructuredSelectorConfig, C extends Record<string, any> = {}>(
|
|
13
|
-
selector: S,
|
|
14
|
-
constants?: C,
|
|
15
|
-
): MemoSelector<InferStructuredSelectorResult<S, C>> {
|
|
16
|
-
let keys = Object.keys(selector);
|
|
17
|
-
constants = constants ?? ({} as C);
|
|
18
|
-
if (keys.length == 0) {
|
|
19
|
-
let result: Selector = () => constants;
|
|
20
|
-
result.memoize = () => result;
|
|
21
|
-
return result as MemoSelector<InferStructuredSelectorResult<S, C>>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function memoize() {
|
|
25
|
-
let lastResult: Record<string, any> = Object.assign({}, constants);
|
|
26
|
-
|
|
27
|
-
let memoizedSelectors: Record<string, Selector> = {};
|
|
28
|
-
|
|
29
|
-
keys.forEach((key) => {
|
|
30
|
-
memoizedSelectors[key] = selector[key].memoize ? selector[key].memoize() : selector[key];
|
|
31
|
-
lastResult[key] = undefined;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
return function (data: any) {
|
|
35
|
-
let result = lastResult,
|
|
36
|
-
k,
|
|
37
|
-
v,
|
|
38
|
-
i;
|
|
39
|
-
for (i = 0; i < keys.length; i++) {
|
|
40
|
-
k = keys[i];
|
|
41
|
-
v = memoizedSelectors[k](data);
|
|
42
|
-
if (result === lastResult) {
|
|
43
|
-
if (v === lastResult[k]) continue;
|
|
44
|
-
result = Object.assign({}, lastResult);
|
|
45
|
-
}
|
|
46
|
-
result[k] = v;
|
|
47
|
-
}
|
|
48
|
-
return (lastResult = result);
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let result: Selector = function evaluate(data: any) {
|
|
53
|
-
let result: Record<string, any> = Object.assign({}, constants);
|
|
54
|
-
for (let i = 0; i < keys.length; i++) {
|
|
55
|
-
result[keys[i]] = selector[keys[i]](data);
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
result.memoize = memoize;
|
|
61
|
-
return result as MemoSelector<InferStructuredSelectorResult<S, C>>;
|
|
62
|
-
}
|
|
1
|
+
import { MemoSelector, Selector } from "./Selector";
|
|
2
|
+
|
|
3
|
+
export interface StructuredSelectorConfig {
|
|
4
|
+
[prop: string]: Selector;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Helper type to infer result type from selector config
|
|
8
|
+
type InferStructuredSelectorResult<T extends StructuredSelectorConfig, C = {}> = {
|
|
9
|
+
[K in keyof T]: T[K] extends Selector<infer R> ? R : any;
|
|
10
|
+
} & C;
|
|
11
|
+
|
|
12
|
+
export function createStructuredSelector<S extends StructuredSelectorConfig, C extends Record<string, any> = {}>(
|
|
13
|
+
selector: S,
|
|
14
|
+
constants?: C,
|
|
15
|
+
): MemoSelector<InferStructuredSelectorResult<S, C>> {
|
|
16
|
+
let keys = Object.keys(selector);
|
|
17
|
+
constants = constants ?? ({} as C);
|
|
18
|
+
if (keys.length == 0) {
|
|
19
|
+
let result: Selector = () => constants;
|
|
20
|
+
result.memoize = () => result;
|
|
21
|
+
return result as MemoSelector<InferStructuredSelectorResult<S, C>>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function memoize() {
|
|
25
|
+
let lastResult: Record<string, any> = Object.assign({}, constants);
|
|
26
|
+
|
|
27
|
+
let memoizedSelectors: Record<string, Selector> = {};
|
|
28
|
+
|
|
29
|
+
keys.forEach((key) => {
|
|
30
|
+
memoizedSelectors[key] = selector[key].memoize ? selector[key].memoize() : selector[key];
|
|
31
|
+
lastResult[key] = undefined;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return function (data: any) {
|
|
35
|
+
let result = lastResult,
|
|
36
|
+
k,
|
|
37
|
+
v,
|
|
38
|
+
i;
|
|
39
|
+
for (i = 0; i < keys.length; i++) {
|
|
40
|
+
k = keys[i];
|
|
41
|
+
v = memoizedSelectors[k](data);
|
|
42
|
+
if (result === lastResult) {
|
|
43
|
+
if (v === lastResult[k]) continue;
|
|
44
|
+
result = Object.assign({}, lastResult);
|
|
45
|
+
}
|
|
46
|
+
result[k] = v;
|
|
47
|
+
}
|
|
48
|
+
return (lastResult = result);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let result: Selector = function evaluate(data: any) {
|
|
53
|
+
let result: Record<string, any> = Object.assign({}, constants);
|
|
54
|
+
for (let i = 0; i < keys.length; i++) {
|
|
55
|
+
result[keys[i]] = selector[keys[i]](data);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
result.memoize = memoize;
|
|
61
|
+
return result as MemoSelector<InferStructuredSelectorResult<S, C>>;
|
|
62
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export function defaultCompare(av: any, bv: any): number {
|
|
2
|
-
if (av == null) {
|
|
3
|
-
if (bv == null)
|
|
4
|
-
return 0;
|
|
5
|
-
return -1;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
if (bv == null || av > bv)
|
|
9
|
-
return 1;
|
|
10
|
-
|
|
11
|
-
if (av < bv)
|
|
12
|
-
return -1;
|
|
13
|
-
|
|
14
|
-
return 0;
|
|
1
|
+
export function defaultCompare(av: any, bv: any): number {
|
|
2
|
+
if (av == null) {
|
|
3
|
+
if (bv == null)
|
|
4
|
+
return 0;
|
|
5
|
+
return -1;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (bv == null || av > bv)
|
|
9
|
+
return 1;
|
|
10
|
+
|
|
11
|
+
if (av < bv)
|
|
12
|
+
return -1;
|
|
13
|
+
|
|
14
|
+
return 0;
|
|
15
15
|
}
|