@singularsystems/neo-react 1.4.2 → 1.5.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file details all new features and changes to functionality. If you only need to see changes that require updates to your project, see the [breaking changes](./Breaking.md) readme.
4
4
 
5
+ ## Version 1.5.0 (28 May 2026)
6
+
7
+ - Fixed routes with the same prefix, but different parameter counts not being registered.
8
+ - E.g. a products list view with path `/products`, and product item view with path `/products/{itemId}` were previously seen as a duplicate route.
9
+ - A url of `/products/123` would have matched against the first route.
10
+ - ViewBase - allow `viewParamsUpdated` to be called on initialise even if all the parameters have default values.
11
+
12
+ ## Version 1.4.3 (22 April 2026)
13
+
14
+ - Fix variable usage in neo-react styles.
15
+ - Now uses bootstrap variable names instead of legacy custom variable names defined in end project.
16
+ - This change is to allow simplification of the variables file in the end project.
17
+ - Existing projects do not need to make changes to their variables files.
18
+
5
19
  ## Version 1.4.2 (20 April 2026)
6
20
 
7
21
  - Navigation helper
@@ -42,7 +42,7 @@ declare const NeoReactTypes: {
42
42
  };
43
43
  Core: {
44
44
  AutoRunnerFactory: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Model/IAutoRunner").IAutoRunnerFactory>;
45
- ConnectionManager: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/ConnectionManager").IConnectionManager>;
45
+ ConnectionManager: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Network").IConnectionManager>;
46
46
  DecimalService: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Numeric").IDecimalService<import("@singularsystems/neo-core/dist/Numeric").IDecimal>>;
47
47
  ModelCreator: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Model/IModelCreatorBase").default>;
48
48
  };
@@ -50,9 +50,13 @@ declare const NeoReactTypes: {
50
50
  LocalisationService: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Localisation").ILocalisationService>;
51
51
  };
52
52
  Messaging: {
53
- ConnectionManager: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/ConnectionManager").IConnectionManager>;
53
+ ConnectionManager: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Network").IConnectionManager>;
54
54
  ServerMessageSubscriber: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/SignalR").IServerMessageSubscriber>;
55
55
  };
56
+ Network: {
57
+ AppConnectionMonitor: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Network/IAppConnectionMonitor").IAppConnectionMonitor>;
58
+ ConnectionManager: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Network").IConnectionManager>;
59
+ };
56
60
  Security: {
57
61
  AuthenticationService: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Security").IAuthenticationService>;
58
62
  AuthorisationService: AppServices.ServiceIdentifier<import("@singularsystems/neo-core/dist/Security").IAuthorisationService>;
@@ -58,7 +58,7 @@ var ColorPicker = /** @class */ (function (_super) {
58
58
  ColorPicker_1.render(this.state.selectedColor, this.handleChange),
59
59
  React.createElement("div", { className: "action-container" },
60
60
  React.createElement("div", { className: "btn btn-primary btn-sm", onClick: function () { return _this.accept(); } }, "Accept"),
61
- React.createElement("div", { className: "btn btn-secondary btn-sm ml-1", onClick: function () { return _this.cancel(); } }, "Cancel"))))))));
61
+ React.createElement("div", { className: "btn btn-secondary btn-sm ml-1 ms-1", onClick: function () { return _this.cancel(); } }, "Cancel"))))))));
62
62
  };
63
63
  /** Renders the inner color picker components without the modal */
64
64
  ColorPicker.render = function (color, onChange) {
@@ -74,7 +74,7 @@ var ContextMenu = /** @class */ (function (_super) {
74
74
  item.icon && _this.iconFactory.getIconComponent(item.icon, { fixedWidth: true }),
75
75
  item.text && React.createElement("span", { className: "neo-context-menu-text" }, item.text),
76
76
  item.header && React.createElement("span", { className: "neo-context-menu-text" }, item.header),
77
- item.items && React.createElement("i", { className: "fa-fw fa fa-angle-right child-indicator" }),
77
+ item.items && React.createElement("i", { className: "fa-fw fa fa-angle-right child-indicator neo-icon" }),
78
78
  item.items && _this.hoverItem === item && React.createElement(ContextMenu_1, { menuItems: item.items, show: _this.hoverItem === item, onClick: _this.props.onClick })))); })));
79
79
  };
80
80
  var ContextMenu_1;
@@ -5,7 +5,6 @@ interface INamedRouteParameter extends IRouteParameter {
5
5
  name: string;
6
6
  }
7
7
  export interface IProcessedRoute extends Routing.IRoute {
8
- key: number;
9
8
  /** Lower case base path without trailing / */
10
9
  path: string;
11
10
  /** Route params in order, excluding query parameters. */
@@ -29,8 +28,6 @@ export default class RouteProvider {
29
28
  menuRoutes: Routing.IMenuRoute[];
30
29
  pureRoutes?: Routing.IRoute[] | undefined;
31
30
  notFoundComponent?: React.ComponentType | undefined;
32
- private key;
33
- private routeIndex;
34
31
  private staticRoutes;
35
32
  private parameterisedRoutes;
36
33
  readonly allRoutes: IProcessedRoute[];
@@ -46,7 +43,7 @@ export default class RouteProvider {
46
43
  private flatten;
47
44
  /**
48
45
  * Create a copy of the route info, and process it.
49
- * Adds a unique key, and adds route parameters extracted from the component static params object.
46
+ * Adds route parameters extracted from the component static params object.
50
47
  */
51
48
  private processRoute;
52
49
  }
@@ -10,14 +10,12 @@ var RouteProvider = /** @class */ (function () {
10
10
  this.menuRoutes = menuRoutes;
11
11
  this.pureRoutes = pureRoutes;
12
12
  this.notFoundComponent = notFoundComponent;
13
- this.key = 1;
14
- this.routeIndex = {};
15
13
  this.staticRoutes = [];
16
14
  this.parameterisedRoutes = [];
17
15
  this.allRoutes = [];
18
- this.flatten(this.allRoutes, menuRoutes);
16
+ this.flatten(menuRoutes);
19
17
  if (pureRoutes)
20
- this.flatten(this.allRoutes, pureRoutes);
18
+ this.flatten(pureRoutes);
21
19
  this.staticRoutes = this.allRoutes.filter(function (c) { return c.params.length === 0; });
22
20
  this.parameterisedRoutes = this.allRoutes
23
21
  .filter(function (c) { return c.params.length > 0; })
@@ -84,7 +82,7 @@ var RouteProvider = /** @class */ (function () {
84
82
  }
85
83
  return null;
86
84
  };
87
- RouteProvider.prototype.flatten = function (into, routes, parent) {
85
+ RouteProvider.prototype.flatten = function (routes, parent) {
88
86
  var _a, _b;
89
87
  for (var _i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
90
88
  var route = routes_1[_i];
@@ -93,20 +91,20 @@ var RouteProvider = /** @class */ (function () {
93
91
  if (parent && !route.breadCrumbParent) {
94
92
  route.breadCrumbParent = parent;
95
93
  }
96
- this.processRoute(into, route);
94
+ this.processRoute(route);
97
95
  }
98
96
  var menuRoute = route;
99
97
  var children = __spreadArray(__spreadArray([], ((_a = route.routeChildren) !== null && _a !== void 0 ? _a : []), true), ((_b = menuRoute.children) !== null && _b !== void 0 ? _b : []), true);
100
- this.flatten(into, children, (hasComponent && menuRoute.showInBreadCrumb !== false) ? menuRoute : undefined);
98
+ this.flatten(children, (hasComponent && menuRoute.showInBreadCrumb !== false) ? menuRoute : undefined);
101
99
  }
102
100
  };
103
101
  /**
104
102
  * Create a copy of the route info, and process it.
105
- * Adds a unique key, and adds route parameters extracted from the component static params object.
103
+ * Adds route parameters extracted from the component static params object.
106
104
  */
107
- RouteProvider.prototype.processRoute = function (into, route) {
105
+ RouteProvider.prototype.processRoute = function (route) {
108
106
  var _a;
109
- var processed = __assign(__assign({}, route), { path: route.path, params: [], key: this.key++, order: 0 });
107
+ var processed = __assign(__assign({}, route), { path: route.path, params: [], order: 0 });
110
108
  processed.path = (_a = route.basePath) !== null && _a !== void 0 ? _a : route.path;
111
109
  processed.path = processed.path.toLowerCase();
112
110
  if (processed.path.length > 1 && processed.path.endsWith("/")) {
@@ -124,10 +122,7 @@ var RouteProvider = /** @class */ (function () {
124
122
  }
125
123
  }
126
124
  }
127
- if (!this.routeIndex[processed.path]) {
128
- this.routeIndex[processed.path] = true;
129
- into.push(processed);
130
- }
125
+ this.allRoutes.push(processed);
131
126
  };
132
127
  return RouteProvider;
133
128
  }());
@@ -32,6 +32,8 @@ export default abstract class ViewBase<TViewModel extends IViewModel = EmptyView
32
32
  navigation: import("../Routing").INavigationHelper;
33
33
  private breadCrumbStartItems?;
34
34
  protected viewState: ViewState<TViewModel, TParams>;
35
+ /** If true, viewParamsUpdated() will be called on initialisation even if all parameters have default values. */
36
+ protected callViewParamsUpdatedOnInitialise: boolean;
35
37
  /**
36
38
  * Creates a view
37
39
  * @param props React props.
@@ -24,6 +24,8 @@ var ViewBase = /** @class */ (function (_super) {
24
24
  _this.hasInitialised = false;
25
25
  _this.routingState = Misc.Globals.appService.get(NeoReactTypes.Routing.GlobalRoutingState);
26
26
  _this.navigation = Misc.Globals.appService.get(NeoReactTypes.Routing.NavigationHelper);
27
+ /** If true, viewParamsUpdated() will be called on initialisation even if all parameters have default values. */
28
+ _this.callViewParamsUpdatedOnInitialise = false;
27
29
  if (typeof viewName !== "string") {
28
30
  throw "Error: When inheriting ViewBase, you must pass the view name into the base constructor.";
29
31
  }
@@ -85,7 +87,7 @@ var ViewBase = /** @class */ (function (_super) {
85
87
  _a.sent();
86
88
  _a.label = 2;
87
89
  case 2:
88
- if (!paramsUpdated) return [3 /*break*/, 4];
90
+ if (!(paramsUpdated || this.callViewParamsUpdatedOnInitialise)) return [3 /*break*/, 4];
89
91
  return [4 /*yield*/, this.viewParamsUpdated()];
90
92
  case 3:
91
93
  _a.sent();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularsystems/neo-react",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "React application logic and components for the Neo client library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,7 +26,7 @@ div.dropdown-menu {
26
26
 
27
27
  .dropdown-subtext {
28
28
  font-size: 13px;
29
- color: #888;
29
+ color: $body-secondary-color;
30
30
  max-width: 250px;
31
31
  white-space: wrap;
32
32
  }
@@ -4,7 +4,7 @@ div.color-picker {
4
4
  div.block-button {
5
5
  width: 20px;
6
6
  height: 20px;
7
- border: 1px solid $bs-secondary;
7
+ border: 1px solid $secondary;
8
8
  cursor: pointer;
9
9
  }
10
10
 
@@ -17,9 +17,8 @@ div.color-picker {
17
17
 
18
18
  div.picker-block {
19
19
  padding: 5px;
20
- background-color: $offGrey;
20
+ background-color: white;
21
21
  border-radius: 5px;
22
- border: 1px solid $concrete;
23
22
 
24
23
  div.action-container {
25
24
  text-align: right;
@@ -38,7 +37,7 @@ div.color-picker {
38
37
  top: 0;
39
38
  left: 0;
40
39
  z-index: 5000;
41
- background-color: $lightBlack;
40
+ background-color: $modal-backdrop-bg;
42
41
  opacity: 0.2;
43
42
  cursor: pointer;
44
43
  }
@@ -1,9 +1,9 @@
1
1
  .neo-context-menu {
2
2
  position: absolute;
3
3
  z-index: 1100;
4
- border: 1px solid #ccc;
4
+ border: 1px solid $dropdown-border-color;
5
5
  background: #fff;
6
- color: #212529;
6
+ color: initial;
7
7
  padding: 5px;
8
8
  border-radius: 2px;
9
9
  left: 100%;
@@ -32,8 +32,8 @@
32
32
  padding-right: 15px;
33
33
  }
34
34
 
35
- > i {
36
- color: #666;
35
+ > .neo-icon {
36
+ color: $body-secondary-color;
37
37
  font-size: 12px;
38
38
  }
39
39
 
@@ -51,17 +51,17 @@
51
51
  cursor: pointer;
52
52
 
53
53
  &:hover {
54
- background: transparentize($bs-primary, 0.75);
54
+ background: transparentize($primary, 0.75);
55
55
  }
56
56
  }
57
57
 
58
58
  &.header {
59
59
  background: rgba(0,0,0,0.65);
60
- color: #fff;
60
+ color: white;
61
61
  padding: 5px 4px;
62
62
 
63
- > i {
64
- color: #eee;
63
+ > .neo-icon {
64
+ color: white;
65
65
  }
66
66
  }
67
67
 
@@ -72,8 +72,9 @@
72
72
  }
73
73
 
74
74
  hr {
75
- border-top: 1px dashed #ddd;
75
+ border-top: 1px dashed $dropdown-border-color;
76
76
  margin: 1px 4px 1px 28px;
77
+ opacity: 1;
77
78
  }
78
79
  }
79
80
  }
@@ -125,15 +125,16 @@ $neo-include-datepicker: true !default;
125
125
 
126
126
  &.selectable:hover {
127
127
  cursor: pointer;
128
- background-color: adjust-color($form-focused-border, $lightness: 15%);
128
+ background-color: adjust-color($primary, $lightness: 15%);
129
+ color: #fff;
129
130
  }
130
131
 
131
132
  &.today {
132
- border: 1px solid $form-focused-border;
133
+ border: 1px solid $primary;
133
134
  }
134
135
 
135
136
  &.selected, &.selected:hover {
136
- background-color: $form-focused-border;
137
+ background-color: $primary;
137
138
  color: #fff;
138
139
  }
139
140
  }
package/styles/Forms.scss CHANGED
@@ -39,7 +39,7 @@ div.neo-form-group-floating {
39
39
  color: #495057;
40
40
  border: none;
41
41
  outline: none;
42
- border-bottom: 1px solid $form-border;
42
+ border-bottom: 1px solid $input-border-color;
43
43
  transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
44
44
  width: 100%;
45
45
  padding: 5px 0 3px 0;
@@ -56,7 +56,7 @@ div.neo-form-group-floating {
56
56
  position: absolute;
57
57
  transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
58
58
  width: 100%;
59
- border-bottom: 3px solid $form-focused-shadow-color;
59
+ border-bottom: 3px solid rgba($input-focus-border-color, 0.15);
60
60
  transform: scale(0);
61
61
  }
62
62
 
@@ -65,10 +65,10 @@ div.neo-form-group-floating {
65
65
  transform: scale(1);
66
66
  }
67
67
  label.neo-floating-label {
68
- color: color.adjust($form-focused-border, $lightness: -15%);
68
+ color: color.adjust($input-focus-border-color, $lightness: -15%);
69
69
  }
70
70
  .neo-forms-editor {
71
- border-bottom: 1px solid $form-focused-border;
71
+ border-bottom: 1px solid $input-focus-border-color;
72
72
  }
73
73
  }
74
74
 
@@ -109,7 +109,7 @@ div.neo-form-group-floating {
109
109
 
110
110
  .input-group.file-editor {
111
111
  .file-placeholder {
112
- color: $lightGrey;
112
+ color: $input-placeholder-color;
113
113
  user-select: none;
114
114
  padding: 0;
115
115
 
@@ -34,7 +34,7 @@ div.loader-container {
34
34
  z-index: 1;
35
35
 
36
36
  div.loader-inner {
37
- background: $bs-light;
37
+ background: $light;
38
38
  width: 100%;
39
39
  text-align: center;
40
40
  padding: 20px 15px;
package/styles/Misc.scss CHANGED
@@ -44,7 +44,7 @@ div.collapsable {
44
44
  position: absolute;
45
45
  top: -1000px;
46
46
  left: -1000px;
47
- background-color: $bs-dark;
47
+ background-color: $dark;
48
48
  color: #fff;
49
49
  z-index: 1060;
50
50
  font-size: 0.8rem;
@@ -118,11 +118,11 @@ div.tabs-header {
118
118
 
119
119
  /* File drop */
120
120
  .neo-file-drop {
121
- border: 2px dashed $concrete;
121
+ border: 2px dashed $input-border-color;
122
122
  padding: 15px;
123
123
 
124
124
  &.dragging {
125
- border-color: $bs-primary;
125
+ border-color: $primary;
126
126
  }
127
127
 
128
128
  button {
package/styles/Neo.scss CHANGED
@@ -1,3 +1,4 @@
1
+ @import './Variables.scss';
1
2
  @import './Badge.scss';
2
3
  @import './Button.scss';
3
4
  @import './Card.scss';
@@ -158,7 +158,7 @@ select.form-control.is-invalid {
158
158
  padding-right: 10px;
159
159
  }
160
160
  i {
161
- color: $bs-danger;
161
+ color: $danger;
162
162
  }
163
163
  ul {
164
164
  padding-left: 0;
@@ -0,0 +1,8 @@
1
+ // Legacy mappings:
2
+ $body-secondary-color: #6c757d !default;
3
+
4
+ $modal-backdrop-bg: black !default;
5
+ $dropdown-border-color: #ccc !default;
6
+ $input-border-color: $form-border !default;
7
+ $input-focus-border-color: $form-focused-border !default;
8
+ $input-placeholder-color: #dddddd !default;