cx 26.0.4 → 26.0.6

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.
Files changed (127) hide show
  1. package/build/data/ArrayElementView.spec.js +1 -1
  2. package/build/hooks/store.spec.js +1 -1
  3. package/build/hooks/useTrigger.spec.js +1 -1
  4. package/build/ui/Controller.spec.js +6 -2
  5. package/build/ui/app/startAppLoop.d.ts +3 -2
  6. package/build/ui/app/startHotAppLoop.d.ts +3 -2
  7. package/build/ui/layout/ContentPlaceholder.spec.js +12 -12
  8. package/build.js +129 -129
  9. package/dist/manifest.js +844 -844
  10. package/package.json +3 -2
  11. package/src/charts/Chart.ts +108 -108
  12. package/src/data/ArrayElementView.ts +90 -90
  13. package/src/data/AugmentedViewBase.ts +88 -88
  14. package/src/data/Binding.ts +104 -104
  15. package/src/data/ExposedRecordView.ts +95 -95
  16. package/src/data/ExposedValueView.ts +89 -89
  17. package/src/data/Expression.spec.ts +229 -229
  18. package/src/data/Expression.ts +233 -233
  19. package/src/data/Grouper.spec.ts +57 -57
  20. package/src/data/Grouper.ts +158 -158
  21. package/src/data/NestedDataView.ts +43 -43
  22. package/src/data/ReadOnlyDataView.ts +39 -39
  23. package/src/data/Ref.ts +104 -104
  24. package/src/data/Selector.ts +10 -10
  25. package/src/data/Store.ts +52 -52
  26. package/src/data/StoreProxy.ts +19 -19
  27. package/src/data/StoreRef.ts +66 -66
  28. package/src/data/StringTemplate.spec.ts +132 -132
  29. package/src/data/StringTemplate.ts +93 -93
  30. package/src/data/StructuredSelector.spec.ts +113 -113
  31. package/src/data/StructuredSelector.ts +146 -146
  32. package/src/data/SubscribableView.ts +63 -63
  33. package/src/data/ZoomIntoPropertyView.spec.ts +64 -64
  34. package/src/data/ZoomIntoPropertyView.ts +45 -45
  35. package/src/data/computable.spec.ts +62 -62
  36. package/src/data/createAccessorModelProxy.ts +60 -60
  37. package/src/data/createStructuredSelector.ts +62 -62
  38. package/src/data/getAccessor.spec.ts +11 -11
  39. package/src/data/getAccessor.ts +74 -74
  40. package/src/data/getSelector.spec.ts +43 -43
  41. package/src/data/getSelector.ts +66 -66
  42. package/src/data/ops/filter.spec.ts +35 -35
  43. package/src/data/ops/filter.ts +9 -9
  44. package/src/data/ops/merge.ts +13 -13
  45. package/src/data/ops/removeTreeNodes.spec.ts +37 -37
  46. package/src/data/ops/removeTreeNodes.ts +15 -15
  47. package/src/data/ops/updateArray.spec.ts +69 -69
  48. package/src/data/ops/updateArray.ts +31 -31
  49. package/src/data/ops/updateTree.ts +23 -23
  50. package/src/data/test-types.ts +7 -7
  51. package/src/hooks/useTrigger.ts +26 -26
  52. package/src/index.scss +6 -6
  53. package/src/jsx-runtime.ts +72 -72
  54. package/src/svg/BoundedObject.ts +101 -101
  55. package/src/ui/CSSHelper.ts +17 -17
  56. package/src/ui/ContentResolver.ts +124 -124
  57. package/src/ui/Controller.ts +189 -189
  58. package/src/ui/Culture.ts +159 -159
  59. package/src/ui/DataProxy.ts +55 -55
  60. package/src/ui/FocusManager.ts +171 -171
  61. package/src/ui/Instance.ts +868 -868
  62. package/src/ui/RenderingContext.ts +99 -99
  63. package/src/ui/Rescope.ts +49 -49
  64. package/src/ui/StructuredInstanceDataAccessor.ts +32 -32
  65. package/src/ui/VDOM.ts +34 -34
  66. package/src/ui/adapter/ArrayAdapter.spec.ts +55 -55
  67. package/src/ui/adapter/ArrayAdapter.ts +226 -226
  68. package/src/ui/adapter/TreeAdapter.spec.ts +76 -76
  69. package/src/ui/adapter/TreeAdapter.ts +185 -185
  70. package/src/ui/app/History.ts +133 -133
  71. package/src/ui/app/Url.spec.ts +50 -50
  72. package/src/ui/app/startAppLoop.tsx +2 -1
  73. package/src/ui/app/startHotAppLoop.ts +2 -1
  74. package/src/ui/createFunctionalComponent.ts +65 -65
  75. package/src/ui/index.ts +45 -45
  76. package/src/ui/layout/Content.ts +30 -30
  77. package/src/ui/layout/FirstVisibleChildLayout.ts +60 -60
  78. package/src/ui/selection/KeySelection.ts +165 -165
  79. package/src/ui/selection/PropertySelection.ts +87 -87
  80. package/src/ui/selection/Selection.ts +118 -118
  81. package/src/util/Format.ts +267 -267
  82. package/src/util/browserSupportsPassiveEventHandlers.ts +20 -20
  83. package/src/util/color/rgbToHsl.ts +35 -35
  84. package/src/util/getActiveElement.ts +4 -4
  85. package/src/util/hasKey.ts +18 -18
  86. package/src/util/index.ts +55 -55
  87. package/src/util/innerTextTrim.ts +10 -10
  88. package/src/util/isArray.ts +3 -3
  89. package/src/util/isDataRecord.ts +5 -5
  90. package/src/util/isDefined.ts +3 -3
  91. package/src/util/isString.ts +3 -3
  92. package/src/widgets/Sandbox.ts +103 -103
  93. package/src/widgets/autoFocus.ts +9 -9
  94. package/src/widgets/cx.ts +63 -63
  95. package/src/widgets/drag-drop/ops.tsx +1 -1
  96. package/src/widgets/grid/GridCell.ts +143 -143
  97. package/src/widgets/icons/calendar.tsx +17 -17
  98. package/src/widgets/icons/check.tsx +13 -13
  99. package/src/widgets/icons/clear.tsx +15 -15
  100. package/src/widgets/icons/close.tsx +20 -20
  101. package/src/widgets/icons/cx.tsx +38 -38
  102. package/src/widgets/icons/drop-down.tsx +15 -15
  103. package/src/widgets/icons/file.tsx +13 -13
  104. package/src/widgets/icons/folder-open.tsx +15 -15
  105. package/src/widgets/icons/folder.tsx +13 -13
  106. package/src/widgets/icons/forward.tsx +22 -22
  107. package/src/widgets/icons/loading.tsx +24 -24
  108. package/src/widgets/icons/menu.tsx +17 -17
  109. package/src/widgets/icons/pixel-picker.tsx +18 -18
  110. package/src/widgets/icons/search.tsx +13 -13
  111. package/src/widgets/icons/sort-asc.tsx +14 -14
  112. package/src/widgets/icons/square.tsx +18 -18
  113. package/src/widgets/nav/Route.ts +142 -142
  114. package/src/widgets/overlay/ContextMenu.ts +42 -42
  115. package/src/widgets/overlay/Dropdown.tsx +762 -762
  116. package/src/widgets/overlay/MsgBox.tsx +141 -141
  117. package/src/widgets/overlay/Toast.ts +111 -111
  118. package/src/widgets/overlay/Window.tsx +299 -299
  119. package/src/widgets/overlay/alerts.ts +46 -46
  120. package/src/widgets/overlay/captureMouse.ts +195 -195
  121. package/src/widgets/overlay/createHotPromiseWindowFactory.ts +72 -72
  122. package/src/widgets/overlay/index.d.ts +11 -11
  123. package/src/widgets/overlay/index.ts +11 -11
  124. package/src/widgets/overlay/tooltip-ops.ts +173 -173
  125. package/build/ui/PureContainer.spec.d.ts +0 -1
  126. package/build/ui/PureContainer.spec.js +0 -149
  127. package/dist/manifest.d.ts +0 -1443
@@ -1,22 +1,22 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('forward', (props: any) => {
6
- return <svg
7
- {...props}
8
- viewBox="0 0 20 20">
9
-
10
- <path fill="currentColor"
11
- strokeWidth="0"
12
- stroke="currentColor"
13
- d="M10.15 15.5L14.5 10l-4.33-5.47-.65.47 3.98 5-4 5z" />
14
-
15
- <path fill="currentColor"
16
- strokeWidth="0"
17
- stroke="currentColor"
18
- d="M6.15 15.5L10.5 10 6.17 4.53 5.52 5l3.98 5-4 5z" />
19
-
20
- </svg>
21
- }, true);
22
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('forward', (props: any) => {
6
+ return <svg
7
+ {...props}
8
+ viewBox="0 0 20 20">
9
+
10
+ <path fill="currentColor"
11
+ strokeWidth="0"
12
+ stroke="currentColor"
13
+ d="M10.15 15.5L14.5 10l-4.33-5.47-.65.47 3.98 5-4 5z" />
14
+
15
+ <path fill="currentColor"
16
+ strokeWidth="0"
17
+ stroke="currentColor"
18
+ d="M6.15 15.5L10.5 10 6.17 4.53 5.52 5l3.98 5-4 5z" />
19
+
20
+ </svg>
21
+ }, true);
22
+
@@ -1,24 +1,24 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('loading', (props: any) => {
6
- let style = {
7
- animation: 'linear infinite 0.5s cx-rotate'
8
- };
9
-
10
- if (props && props.style)
11
- Object.assign(style, props.style);
12
-
13
- props = {
14
- ...props,
15
- style
16
- };
17
-
18
- return <svg
19
- {...props}
20
- viewBox="0 0 50 50">
21
- <path fill="currentColor" d="M43.94 25.14c0-10.3-8.37-18.68-18.7-18.68-10.3 0-18.67 8.37-18.67 18.68h4.07c0-8.07 6.54-14.6 14.6-14.6 8.08 0 14.63 6.53 14.63 14.6h4.07z" />
22
- </svg>
23
- }, true);
24
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('loading', (props: any) => {
6
+ let style = {
7
+ animation: 'linear infinite 0.5s cx-rotate'
8
+ };
9
+
10
+ if (props && props.style)
11
+ Object.assign(style, props.style);
12
+
13
+ props = {
14
+ ...props,
15
+ style
16
+ };
17
+
18
+ return <svg
19
+ {...props}
20
+ viewBox="0 0 50 50">
21
+ <path fill="currentColor" d="M43.94 25.14c0-10.3-8.37-18.68-18.7-18.68-10.3 0-18.67 8.37-18.67 18.68h4.07c0-8.07 6.54-14.6 14.6-14.6 8.08 0 14.63 6.53 14.63 14.6h4.07z" />
22
+ </svg>
23
+ }, true);
24
+
@@ -1,17 +1,17 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('menu', (props: any) => {
6
- return <svg
7
- {...props}
8
- viewBox="0 0 24 24">
9
-
10
- <path d="M0 0h24v24H0z"
11
- fill="none" />
12
- <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
13
- fill="currentColor" />
14
-
15
- </svg>
16
- }, true);
17
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('menu', (props: any) => {
6
+ return <svg
7
+ {...props}
8
+ viewBox="0 0 24 24">
9
+
10
+ <path d="M0 0h24v24H0z"
11
+ fill="none" />
12
+ <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
13
+ fill="currentColor" />
14
+
15
+ </svg>
16
+ }, true);
17
+
@@ -1,18 +1,18 @@
1
- /** @jsxImportSource react */
2
- import { VDOM } from "../../ui/Widget";
3
- import { registerIcon } from "./registry";
4
-
5
- export default registerIcon(
6
- "pixel-picker",
7
- (props: any) => {
8
- return (
9
- <svg {...props} viewBox="0 0 30 30">
10
- <path
11
- d="M27.7,3.3c-1.5-1.5-3.9-1.5-5.4,0L17,8.6l-1.3-1.3c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l1.3,1.3L5,20.6 c-0.6,0.6-1,1.4-1.1,2.3C3.3,23.4,3,24.2,3,25c0,1.7,1.3,3,3,3c0.8,0,1.6-0.3,2.2-0.9C9,27,9.8,26.6,10.4,26L21,15.4l1.3,1.3 c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L22.4,14l5.3-5.3C29.2,7.2,29.2,4.8,27.7,3.3z M9,24.6 c-0.4,0.4-0.8,0.6-1.3,0.5c-0.4,0-0.7,0.2-0.9,0.5C6.7,25.8,6.3,26,6,26c-0.6,0-1-0.4-1-1c0-0.3,0.2-0.7,0.5-0.8 c0.3-0.2,0.5-0.5,0.5-0.9c0-0.5,0.2-1,0.5-1.3L17,11.4l2.6,2.6L9,24.6z"
12
- fill="currentColor"
13
- />
14
- </svg>
15
- );
16
- },
17
- true
18
- );
1
+ /** @jsxImportSource react */
2
+ import { VDOM } from "../../ui/Widget";
3
+ import { registerIcon } from "./registry";
4
+
5
+ export default registerIcon(
6
+ "pixel-picker",
7
+ (props: any) => {
8
+ return (
9
+ <svg {...props} viewBox="0 0 30 30">
10
+ <path
11
+ d="M27.7,3.3c-1.5-1.5-3.9-1.5-5.4,0L17,8.6l-1.3-1.3c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l1.3,1.3L5,20.6 c-0.6,0.6-1,1.4-1.1,2.3C3.3,23.4,3,24.2,3,25c0,1.7,1.3,3,3,3c0.8,0,1.6-0.3,2.2-0.9C9,27,9.8,26.6,10.4,26L21,15.4l1.3,1.3 c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L22.4,14l5.3-5.3C29.2,7.2,29.2,4.8,27.7,3.3z M9,24.6 c-0.4,0.4-0.8,0.6-1.3,0.5c-0.4,0-0.7,0.2-0.9,0.5C6.7,25.8,6.3,26,6,26c-0.6,0-1-0.4-1-1c0-0.3,0.2-0.7,0.5-0.8 c0.3-0.2,0.5-0.5,0.5-0.9c0-0.5,0.2-1,0.5-1.3L17,11.4l2.6,2.6L9,24.6z"
12
+ fill="currentColor"
13
+ />
14
+ </svg>
15
+ );
16
+ },
17
+ true
18
+ );
@@ -1,13 +1,13 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('search', (props: any) => {
6
- return <svg
7
- {...props}
8
- viewBox="0 0 32 32">
9
- <path fill="currentColor"
10
- d="M25.595 22.036l-5.26-5.075c.75-1.18 1.206-2.56 1.206-4.05 0-4.32-3.63-7.82-8.103-7.82-4.477 0-8.107 3.503-8.107 7.82 0 4.32 3.63 7.825 8.106 7.825 1.544 0 2.972-.44 4.198-1.162l5.26 5.074c.37.356.98.354 1.35 0l1.352-1.304c.37-.357.37-.947 0-1.304zm-12.16-3.91c-2.985 0-5.405-2.336-5.405-5.216 0-2.88 2.42-5.214 5.405-5.214 2.984 0 5.404 2.335 5.404 5.214 0 2.88-2.42 5.215-5.407 5.215z" />
11
- </svg>
12
- }, true);
13
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('search', (props: any) => {
6
+ return <svg
7
+ {...props}
8
+ viewBox="0 0 32 32">
9
+ <path fill="currentColor"
10
+ d="M25.595 22.036l-5.26-5.075c.75-1.18 1.206-2.56 1.206-4.05 0-4.32-3.63-7.82-8.103-7.82-4.477 0-8.107 3.503-8.107 7.82 0 4.32 3.63 7.825 8.106 7.825 1.544 0 2.972-.44 4.198-1.162l5.26 5.074c.37.356.98.354 1.35 0l1.352-1.304c.37-.357.37-.947 0-1.304zm-12.16-3.91c-2.985 0-5.405-2.336-5.405-5.216 0-2.88 2.42-5.214 5.405-5.214 2.984 0 5.404 2.335 5.404 5.214 0 2.88-2.42 5.215-5.407 5.215z" />
11
+ </svg>
12
+ }, true);
13
+
@@ -1,14 +1,14 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('sort-asc', (props: any) => {
6
- return <svg
7
- {...props}
8
- viewBox="0 0 16 16">
9
- <path fill="currentColor"
10
- d="M10.5 5.8l-3-3-3 3 .707.708L7 4.688v8.312h1V4.69l1.793 1.817z"
11
- />
12
- </svg>
13
- }, true);
14
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('sort-asc', (props: any) => {
6
+ return <svg
7
+ {...props}
8
+ viewBox="0 0 16 16">
9
+ <path fill="currentColor"
10
+ d="M10.5 5.8l-3-3-3 3 .707.708L7 4.688v8.312h1V4.69l1.793 1.817z"
11
+ />
12
+ </svg>
13
+ }, true);
14
+
@@ -1,18 +1,18 @@
1
- /** @jsxImportSource react */
2
- import {VDOM} from '../../ui/Widget';
3
- import {registerIcon} from './registry';
4
-
5
- export default registerIcon('square', (props: any) => {
6
- return <svg
7
- {...props}
8
- viewBox="0 0 64 64">
9
- <rect
10
- x="12"
11
- y="12"
12
- width="40"
13
- height="40"
14
- fill="currentColor"
15
- />
16
- </svg>
17
- }, true);
18
-
1
+ /** @jsxImportSource react */
2
+ import {VDOM} from '../../ui/Widget';
3
+ import {registerIcon} from './registry';
4
+
5
+ export default registerIcon('square', (props: any) => {
6
+ return <svg
7
+ {...props}
8
+ viewBox="0 0 64 64">
9
+ <rect
10
+ x="12"
11
+ y="12"
12
+ width="40"
13
+ height="40"
14
+ fill="currentColor"
15
+ />
16
+ </svg>
17
+ }, true);
18
+
@@ -1,142 +1,142 @@
1
- import { Widget } from "../../ui/Widget";
2
- import { PureContainerBase, PureContainerConfig } from "../../ui/PureContainer";
3
- import RouteMatcher from "route-parser";
4
- import { ReadOnlyDataView } from "../../data/ReadOnlyDataView";
5
- import { routeAppend } from "../../util/routeAppend";
6
- import { StringProp, BooleanProp, Prop } from "../../ui/Prop";
7
- import { RenderingContext } from "../../ui/RenderingContext";
8
- import { Instance } from "../../ui/Instance";
9
-
10
- export interface RouteConfig extends PureContainerConfig {
11
- /** Url binding. Bind this to the global `url` variable. */
12
- url?: StringProp;
13
-
14
- /** Target route, e.g. `~/user/:userId`. All routes should start with `~/`. */
15
- route?: string;
16
-
17
- /** Target route, e.g. `~/user/:userId`. All routes should start with `~/`. */
18
- path?: string;
19
-
20
- /** Name used to expose local data. Defaults to `$route`. */
21
- recordName?: string;
22
-
23
- /** Match route even if given `route` is only a prefix of the current `url`. */
24
- prefix?: BooleanProp;
25
-
26
- /** Parameters mapping */
27
- params?: Prop<any>;
28
-
29
- /** Parameter name mapping */
30
- map?: Record<string, string>;
31
- }
32
-
33
- // Base class for extending with custom Config types
34
- export class RouteBase<Config extends RouteConfig = RouteConfig> extends PureContainerBase<Config> {
35
- declare url?: string;
36
- declare route: string;
37
- declare path?: string;
38
- declare prefix?: boolean;
39
- declare recordName: string;
40
- declare params?: Prop<any>;
41
- declare map?: Record<string, string>;
42
- declare matcher?: any;
43
- init() {
44
- if (this.path) this.route = this.path;
45
-
46
- super.init();
47
-
48
- if (this.route && this.route[0] !== "+")
49
- this.matcher = new RouteMatcher(this.route + (this.prefix ? "(*remainder)" : ""));
50
- }
51
-
52
- initInstance(context: RenderingContext, instance: Instance) {
53
- instance.store = new ReadOnlyDataView({
54
- store: instance.parentStore,
55
- });
56
- super.initInstance(context, instance);
57
- }
58
-
59
- applyParentStore(instance: Instance) {
60
- instance.store.setStore(instance.parentStore);
61
- }
62
-
63
- declareData(...args: any[]): void {
64
- super.declareData(...args, {
65
- url: undefined,
66
- });
67
- }
68
-
69
- checkVisible(context: RenderingContext, instance: Instance, data: any) {
70
- if (!data.visible) return false;
71
-
72
- if (data.url !== instance.cached.url) {
73
- instance.cached.url = data.url;
74
- let matcher = this.matcher;
75
- let route = this.route;
76
- if (this.route[0] === "+") {
77
- route = routeAppend(context.lastRoute.route, this.route.substring(1));
78
- if (!instance.cached.matcher || instance.cached.route !== route)
79
- instance.cached.matcher = new RouteMatcher(route + (this.prefix ? "(*remainder)" : ""));
80
- matcher = instance.cached.matcher;
81
- }
82
- instance.cached.result = matcher.match(data.url);
83
- instance.cached.matcher = matcher;
84
- instance.cached.route = data.route = route;
85
- }
86
- if (!instance.cached.result) return false;
87
-
88
- return super.checkVisible(context, instance, data);
89
- }
90
-
91
- prepareData(context: RenderingContext, instance: Instance) {
92
- super.prepareData(context, instance);
93
-
94
- const { store, cached } = instance;
95
-
96
- (store as ReadOnlyDataView).setData({
97
- [this.recordName]: cached.result,
98
- });
99
-
100
- //TODO: Replace comparison with deepEquals
101
- if (this.params && this.params.bind) {
102
- var params = store.get(this.params.bind);
103
- if (JSON.stringify(params) != JSON.stringify(cached.result)) {
104
- store.set(this.params.bind, cached.result);
105
- }
106
- }
107
-
108
- if (this.map) {
109
- for (var key in cached.result) {
110
- var binding = this.map[key];
111
- if (binding) store.set(binding, cached.result[key]);
112
- }
113
- }
114
- }
115
-
116
- explore(context: RenderingContext, instance: Instance) {
117
- context.push("lastRoute", {
118
- route: instance.cached.route,
119
- result: instance.cached.result,
120
- reverse: function (data: any) {
121
- return instance.cached.matcher.reverse({
122
- ...instance.cached.result,
123
- remainder: "",
124
- ...data,
125
- });
126
- },
127
- });
128
- super.explore(context, instance);
129
- }
130
-
131
- exploreCleanup(context: RenderingContext, instance: Instance) {
132
- context.pop("lastRoute");
133
- }
134
- }
135
-
136
- RouteBase.prototype.recordName = "$route";
137
- RouteBase.prototype.prefix = false;
138
-
139
- // Closed type for direct usage
140
- export class Route extends RouteBase<RouteConfig> {}
141
-
142
- Widget.alias("route", Route);
1
+ import { Widget } from "../../ui/Widget";
2
+ import { PureContainerBase, PureContainerConfig } from "../../ui/PureContainer";
3
+ import RouteMatcher from "route-parser";
4
+ import { ReadOnlyDataView } from "../../data/ReadOnlyDataView";
5
+ import { routeAppend } from "../../util/routeAppend";
6
+ import { StringProp, BooleanProp, Prop } from "../../ui/Prop";
7
+ import { RenderingContext } from "../../ui/RenderingContext";
8
+ import { Instance } from "../../ui/Instance";
9
+
10
+ export interface RouteConfig extends PureContainerConfig {
11
+ /** Url binding. Bind this to the global `url` variable. */
12
+ url?: StringProp;
13
+
14
+ /** Target route, e.g. `~/user/:userId`. All routes should start with `~/`. */
15
+ route?: string;
16
+
17
+ /** Target route, e.g. `~/user/:userId`. All routes should start with `~/`. */
18
+ path?: string;
19
+
20
+ /** Name used to expose local data. Defaults to `$route`. */
21
+ recordName?: string;
22
+
23
+ /** Match route even if given `route` is only a prefix of the current `url`. */
24
+ prefix?: BooleanProp;
25
+
26
+ /** Parameters mapping */
27
+ params?: Prop<any>;
28
+
29
+ /** Parameter name mapping */
30
+ map?: Record<string, string>;
31
+ }
32
+
33
+ // Base class for extending with custom Config types
34
+ export class RouteBase<Config extends RouteConfig = RouteConfig> extends PureContainerBase<Config> {
35
+ declare url?: string;
36
+ declare route: string;
37
+ declare path?: string;
38
+ declare prefix?: boolean;
39
+ declare recordName: string;
40
+ declare params?: Prop<any>;
41
+ declare map?: Record<string, string>;
42
+ declare matcher?: any;
43
+ init() {
44
+ if (this.path) this.route = this.path;
45
+
46
+ super.init();
47
+
48
+ if (this.route && this.route[0] !== "+")
49
+ this.matcher = new RouteMatcher(this.route + (this.prefix ? "(*remainder)" : ""));
50
+ }
51
+
52
+ initInstance(context: RenderingContext, instance: Instance) {
53
+ instance.store = new ReadOnlyDataView({
54
+ store: instance.parentStore,
55
+ });
56
+ super.initInstance(context, instance);
57
+ }
58
+
59
+ applyParentStore(instance: Instance) {
60
+ instance.store.setStore(instance.parentStore);
61
+ }
62
+
63
+ declareData(...args: any[]): void {
64
+ super.declareData(...args, {
65
+ url: undefined,
66
+ });
67
+ }
68
+
69
+ checkVisible(context: RenderingContext, instance: Instance, data: any) {
70
+ if (!data.visible) return false;
71
+
72
+ if (data.url !== instance.cached.url) {
73
+ instance.cached.url = data.url;
74
+ let matcher = this.matcher;
75
+ let route = this.route;
76
+ if (this.route[0] === "+") {
77
+ route = routeAppend(context.lastRoute.route, this.route.substring(1));
78
+ if (!instance.cached.matcher || instance.cached.route !== route)
79
+ instance.cached.matcher = new RouteMatcher(route + (this.prefix ? "(*remainder)" : ""));
80
+ matcher = instance.cached.matcher;
81
+ }
82
+ instance.cached.result = matcher.match(data.url);
83
+ instance.cached.matcher = matcher;
84
+ instance.cached.route = data.route = route;
85
+ }
86
+ if (!instance.cached.result) return false;
87
+
88
+ return super.checkVisible(context, instance, data);
89
+ }
90
+
91
+ prepareData(context: RenderingContext, instance: Instance) {
92
+ super.prepareData(context, instance);
93
+
94
+ const { store, cached } = instance;
95
+
96
+ (store as ReadOnlyDataView).setData({
97
+ [this.recordName]: cached.result,
98
+ });
99
+
100
+ //TODO: Replace comparison with deepEquals
101
+ if (this.params && this.params.bind) {
102
+ var params = store.get(this.params.bind);
103
+ if (JSON.stringify(params) != JSON.stringify(cached.result)) {
104
+ store.set(this.params.bind, cached.result);
105
+ }
106
+ }
107
+
108
+ if (this.map) {
109
+ for (var key in cached.result) {
110
+ var binding = this.map[key];
111
+ if (binding) store.set(binding, cached.result[key]);
112
+ }
113
+ }
114
+ }
115
+
116
+ explore(context: RenderingContext, instance: Instance) {
117
+ context.push("lastRoute", {
118
+ route: instance.cached.route,
119
+ result: instance.cached.result,
120
+ reverse: function (data: any) {
121
+ return instance.cached.matcher.reverse({
122
+ ...instance.cached.result,
123
+ remainder: "",
124
+ ...data,
125
+ });
126
+ },
127
+ });
128
+ super.explore(context, instance);
129
+ }
130
+
131
+ exploreCleanup(context: RenderingContext, instance: Instance) {
132
+ context.pop("lastRoute");
133
+ }
134
+ }
135
+
136
+ RouteBase.prototype.recordName = "$route";
137
+ RouteBase.prototype.prefix = false;
138
+
139
+ // Closed type for direct usage
140
+ export class Route extends RouteBase<RouteConfig> {}
141
+
142
+ Widget.alias("route", Route);
@@ -1,42 +1,42 @@
1
- import { Dropdown, DropdownConfig } from "./Dropdown";
2
- import { getCursorPos } from "./captureMouse";
3
- import { View } from "../../data/View";
4
- import { Instance } from "../../ui/Instance";
5
-
6
- export interface ContextMenuConfig extends DropdownConfig {}
7
-
8
- export class ContextMenu extends Dropdown {
9
- constructor(config?: ContextMenuConfig) {
10
- super(config);
11
- }
12
- }
13
- ContextMenu.prototype.trackMouse = true;
14
- ContextMenu.prototype.dismissOnFocusOut = true;
15
- ContextMenu.prototype.firstChildDefinesWidth = true;
16
- ContextMenu.prototype.matchWidth = false;
17
- ContextMenu.prototype.placementOrder = "down-right right up-right down-left left up-left";
18
- ContextMenu.prototype.offset = 0;
19
- ContextMenu.prototype.autoFocus = true;
20
- ContextMenu.prototype.autoFocusFirstChild = false;
21
- ContextMenu.prototype.focusable = true;
22
-
23
- export const openContextMenu = (
24
- e: React.MouseEvent,
25
- content: any,
26
- storeOrInstance?: View | Instance,
27
- options?: any,
28
- ) => {
29
- e.preventDefault();
30
- e.stopPropagation();
31
- let position = getCursorPos(e);
32
- let menu = ContextMenu.create({
33
- relatedElement: e.currentTarget,
34
- mousePosition: {
35
- x: position.clientX,
36
- y: position.clientY,
37
- },
38
- trackMouse: true,
39
- items: content,
40
- });
41
- return menu.open(storeOrInstance, options);
42
- };
1
+ import { Dropdown, DropdownConfig } from "./Dropdown";
2
+ import { getCursorPos } from "./captureMouse";
3
+ import { View } from "../../data/View";
4
+ import { Instance } from "../../ui/Instance";
5
+
6
+ export interface ContextMenuConfig extends DropdownConfig {}
7
+
8
+ export class ContextMenu extends Dropdown {
9
+ constructor(config?: ContextMenuConfig) {
10
+ super(config);
11
+ }
12
+ }
13
+ ContextMenu.prototype.trackMouse = true;
14
+ ContextMenu.prototype.dismissOnFocusOut = true;
15
+ ContextMenu.prototype.firstChildDefinesWidth = true;
16
+ ContextMenu.prototype.matchWidth = false;
17
+ ContextMenu.prototype.placementOrder = "down-right right up-right down-left left up-left";
18
+ ContextMenu.prototype.offset = 0;
19
+ ContextMenu.prototype.autoFocus = true;
20
+ ContextMenu.prototype.autoFocusFirstChild = false;
21
+ ContextMenu.prototype.focusable = true;
22
+
23
+ export const openContextMenu = (
24
+ e: React.MouseEvent,
25
+ content: any,
26
+ storeOrInstance?: View | Instance,
27
+ options?: any,
28
+ ) => {
29
+ e.preventDefault();
30
+ e.stopPropagation();
31
+ let position = getCursorPos(e);
32
+ let menu = ContextMenu.create({
33
+ relatedElement: e.currentTarget,
34
+ mousePosition: {
35
+ x: position.clientX,
36
+ y: position.clientY,
37
+ },
38
+ trackMouse: true,
39
+ items: content,
40
+ });
41
+ return menu.open(storeOrInstance, options);
42
+ };