@singularsystems/neo-react 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
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.3.5
6
+
7
+ - Fixed drop down to not add a blank item if the bound value is zero, and the items contains an item with id of zero.
8
+ - Minor changes to `IRoute` to allow `basePath` property.
9
+
10
+ ## Version 1.3.4
11
+
12
+ - Added `PopupHost` component
13
+ - Can be used to create popup controls like drop downs / search components.
14
+
5
15
  ## Version 1.3.3
6
16
 
7
17
  - Minor type fixes.
@@ -105,9 +105,10 @@ var DropDown = /** @class */ (function (_super) {
105
105
  var items = this.items;
106
106
  var selectedItem = this.getSelectedOption(this.props.bind.value); // This sets the sort value to allow sorting of drop downs in grids.
107
107
  var value = this.props.bind.value;
108
- var notFound = items.length > 0 && value && selectedItem[this.valueMember] !== value;
109
- var addBlankItem = ((_c = (_b = splitProps.select) === null || _b === void 0 ? void 0 : _b.allowNulls) !== null && _c !== void 0 ? _c : this.props.bind.propertyInfo.allowNulls) || !value || notFound;
110
- if (addBlankItem && items.find(function (item) { return item[_this.valueMember] === null || item[_this.valueMember] === ""; })) {
108
+ var valueIsEmpty = !value;
109
+ var notFound = items.length > 0 && !valueIsEmpty && selectedItem[this.valueMember] !== value;
110
+ var addBlankItem = ((_c = (_b = splitProps.select) === null || _b === void 0 ? void 0 : _b.allowNulls) !== null && _c !== void 0 ? _c : this.props.bind.propertyInfo.allowNulls) || valueIsEmpty || notFound;
111
+ if (addBlankItem && items.find(function (item) { return item[_this.valueMember] === null || item[_this.valueMember] === "" || (valueIsEmpty && item[_this.valueMember] === value); })) {
111
112
  // If there is an item with a null value, don't add a blank drop down item.
112
113
  addBlankItem = false;
113
114
  }
@@ -126,13 +127,13 @@ var DropDown = /** @class */ (function (_super) {
126
127
  if (domProps.readOnly) {
127
128
  domProps.disabled = true;
128
129
  }
129
- var valueIsBlank = value === undefined || value === null;
130
- var nullText = (valueIsBlank || ((_e = splitProps.select) === null || _e === void 0 ? void 0 : _e.deSelectText) === undefined) ? (_f = splitProps.select) === null || _f === void 0 ? void 0 : _f.nullText : (_g = splitProps.select) === null || _g === void 0 ? void 0 : _g.deSelectText;
131
- if (valueIsBlank) {
130
+ var valueIsNull = value === undefined || value === null;
131
+ var nullText = (valueIsNull || ((_e = splitProps.select) === null || _e === void 0 ? void 0 : _e.deSelectText) === undefined) ? (_f = splitProps.select) === null || _f === void 0 ? void 0 : _f.nullText : (_g = splitProps.select) === null || _g === void 0 ? void 0 : _g.deSelectText;
132
+ if (valueIsNull) {
132
133
  domProps.className = Utils.joinWithSpaces(domProps.className, "select-no-value");
133
134
  }
134
135
  control =
135
- React.createElement("select", __assign({ value: valueIsBlank ? "" : value, onChange: this.onItemSelected, ref: splitProps.editor.inputElement }, domProps),
136
+ React.createElement("select", __assign({ value: valueIsNull ? "" : value, onChange: this.onItemSelected, ref: splitProps.editor.inputElement }, domProps),
136
137
  addBlankItem && React.createElement("option", { className: "option-default" }, notFound ? "(Not found): ".concat(value) : nullText),
137
138
  items.map(function (item) { return (React.createElement("option", { value: item[_this.valueMember], key: item[_this.valueMember] }, item[_this.displayMember])); }));
138
139
  }
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ interface IPopupHostProps {
3
+ anchor: React.RefObject<HTMLElement | null>;
4
+ /** If the popup height is less than this value, the top of the popup will be moved up so that the height is at least this value. */
5
+ jumpThreshold?: number;
6
+ /** Called when the close animation completes. */
7
+ onClose?: () => void;
8
+ children: React.ReactElement;
9
+ }
10
+ /**
11
+ * A component that displays a popup over an anchor element.
12
+ * The popup is dismissed when clicking outside of it, or pressing the Escape key.
13
+ *
14
+ * This component is a low level component that should be used by other re-usable components, not directly in views.
15
+ */
16
+ export default class PopupHost extends React.Component<IPopupHostProps> {
17
+ constructor(props: IPopupHostProps);
18
+ private isVisible;
19
+ private popupRef;
20
+ private hideTimer;
21
+ render(): false | React.JSX.Element;
22
+ componentDidUpdate(): void;
23
+ componentWillUnmount(): void;
24
+ /** Shows, and positions the popup. */
25
+ show(): void;
26
+ /**
27
+ * Recalculates the position of the popup relative to the anchor.
28
+ * Call this if the height of the child popup may have changed.
29
+ */
30
+ performLayout(): void;
31
+ private onKeyDown;
32
+ private documentClick;
33
+ /**
34
+ * Starts the animation to hide the popup.
35
+ * The onClose callback will be called once the animation completes.
36
+ */
37
+ beginHide(): void;
38
+ private hide;
39
+ private removeDocumentClickListener;
40
+ }
41
+ export {};
@@ -0,0 +1,128 @@
1
+ import { __decorate, __extends, __metadata } from "tslib";
2
+ import React from "react";
3
+ import { observer } from "mobx-react";
4
+ import { Misc } from "@singularsystems/neo-core";
5
+ /**
6
+ * A component that displays a popup over an anchor element.
7
+ * The popup is dismissed when clicking outside of it, or pressing the Escape key.
8
+ *
9
+ * This component is a low level component that should be used by other re-usable components, not directly in views.
10
+ */
11
+ var PopupHost = /** @class */ (function (_super) {
12
+ __extends(PopupHost, _super);
13
+ function PopupHost(props) {
14
+ var _this = _super.call(this, props) || this;
15
+ _this.isVisible = false;
16
+ _this.popupRef = React.createRef();
17
+ _this.onKeyDown = function (event) {
18
+ if (event.key === "Escape") {
19
+ _this.beginHide();
20
+ }
21
+ };
22
+ _this.onKeyDown = _this.onKeyDown.bind(_this);
23
+ _this.documentClick = _this.documentClick.bind(_this);
24
+ return _this;
25
+ }
26
+ PopupHost.prototype.render = function () {
27
+ return this.isVisible && (React.createElement("div", { className: "neo-popup", ref: this.popupRef, onKeyDown: this.onKeyDown }, this.props.children));
28
+ };
29
+ PopupHost.prototype.componentDidUpdate = function () {
30
+ this.performLayout();
31
+ };
32
+ PopupHost.prototype.componentWillUnmount = function () {
33
+ this.removeDocumentClickListener();
34
+ };
35
+ /** Shows, and positions the popup. */
36
+ PopupHost.prototype.show = function () {
37
+ if (this.hideTimer) {
38
+ clearTimeout(this.hideTimer);
39
+ this.hideTimer = undefined;
40
+ }
41
+ if (this.popupRef.current) {
42
+ this.popupRef.current.style.opacity = "1";
43
+ }
44
+ this.isVisible = true;
45
+ this.forceUpdate();
46
+ window.document.body.addEventListener("mousedown", this.documentClick);
47
+ };
48
+ /**
49
+ * Recalculates the position of the popup relative to the anchor.
50
+ * Call this if the height of the child popup may have changed.
51
+ */
52
+ PopupHost.prototype.performLayout = function () {
53
+ var _a;
54
+ var popup = this.popupRef.current;
55
+ var fixedHeader = (_a = Misc.Settings.fixedAppHeaderElement) === null || _a === void 0 ? void 0 : _a.call(undefined);
56
+ var screenPadding = 8;
57
+ var screenTop = (fixedHeader && getComputedStyle(fixedHeader).position === "fixed" ? fixedHeader.getBoundingClientRect().bottom : 0) + screenPadding;
58
+ var screenBottom = window.innerHeight - screenPadding;
59
+ if (popup && this.props.anchor.current) {
60
+ popup.style.height = "";
61
+ var anchorRect = this.props.anchor.current.getBoundingClientRect();
62
+ var innerElement = popup.firstElementChild;
63
+ var popupStyles = window.getComputedStyle(innerElement !== null && innerElement !== void 0 ? innerElement : popup);
64
+ var paddingTop = parseFloat(popupStyles.paddingTop);
65
+ var paddingLeft = parseFloat(popupStyles.paddingLeft);
66
+ popup.style.top = "".concat(anchorRect.top - paddingTop, "px");
67
+ popup.style.left = "".concat(Math.max(0, anchorRect.left - paddingLeft), "px");
68
+ var popupRect = popup.getBoundingClientRect();
69
+ var heightToFit = screenBottom - popupRect.top;
70
+ var jumpThreshold = this.props.jumpThreshold ? Math.min(this.props.jumpThreshold, popupRect.height) : 0;
71
+ if (popupRect.right > window.innerWidth) {
72
+ popup.style.left = "".concat(window.innerWidth - popupRect.width, "px");
73
+ }
74
+ if (popupRect.bottom > screenBottom) {
75
+ if (heightToFit < jumpThreshold) {
76
+ // give the popup as much height as possible by moving the top of the popup higher.
77
+ var top_1 = screenBottom - jumpThreshold;
78
+ if (top_1 < screenTop) {
79
+ popup.style.height = "".concat(screenBottom - screenTop, "px");
80
+ popup.style.top = "".concat(screenTop, "px");
81
+ }
82
+ else {
83
+ popup.style.height = "".concat(jumpThreshold, "px");
84
+ popup.style.top = "".concat(top_1, "px");
85
+ }
86
+ }
87
+ else {
88
+ popup.style.height = "".concat(heightToFit, "px");
89
+ }
90
+ }
91
+ }
92
+ };
93
+ PopupHost.prototype.documentClick = function (event) {
94
+ // hide if the click is outside the popup
95
+ if (this.popupRef.current && !this.popupRef.current.contains(event.target)) {
96
+ this.beginHide();
97
+ }
98
+ };
99
+ /**
100
+ * Starts the animation to hide the popup.
101
+ * The onClose callback will be called once the animation completes.
102
+ */
103
+ PopupHost.prototype.beginHide = function () {
104
+ var _this = this;
105
+ this.removeDocumentClickListener();
106
+ var transitionDuration = 0;
107
+ if (this.popupRef.current) {
108
+ this.popupRef.current.style.opacity = "0";
109
+ transitionDuration = parseFloat(window.getComputedStyle(this.popupRef.current).transitionDuration) * 1000;
110
+ }
111
+ this.hideTimer = setTimeout(function () { return _this.hide(); }, transitionDuration);
112
+ };
113
+ PopupHost.prototype.hide = function () {
114
+ var _a;
115
+ this.isVisible = false;
116
+ this.forceUpdate();
117
+ (_a = this.props.onClose) === null || _a === void 0 ? void 0 : _a.call(undefined);
118
+ };
119
+ PopupHost.prototype.removeDocumentClickListener = function () {
120
+ window.document.body.removeEventListener("mousedown", this.documentClick);
121
+ };
122
+ PopupHost = __decorate([
123
+ observer,
124
+ __metadata("design:paramtypes", [Object])
125
+ ], PopupHost);
126
+ return PopupHost;
127
+ }(React.Component));
128
+ export default PopupHost;
@@ -30,6 +30,7 @@ import NumberInput from './NumberInput';
30
30
  import Pager from './Paging/Pager';
31
31
  import PagerControlsBasic from './Paging/BasicPagerControls';
32
32
  import PageSizeControl from './Paging/PageSizeControl';
33
+ import PopupHost from "./PopupHost";
33
34
  import ProgressBar from './ProgressBar';
34
35
  import RadioList from './RadioList';
35
36
  import Slider from './Slider';
@@ -42,4 +43,4 @@ import ToastContainer from './Notifications/ToastContainer';
42
43
  import Tooltip from './Tooltip';
43
44
  import TooltipProvider from './TooltipProvider';
44
45
  import ValidationSummary from './ValidationSummary';
45
- export { Alert, AutoCompleteDropDown, Badge, Button, Card, Checkbox, Collapsable, ColorPicker, ContextMenuContainer, DatePicker, DropDown, FileBasicInput, FileContext, FileDropArea, FileInput, FileUploadButton, FileUploadProgress, Form, FormContext, FormGroup, FormGroupFloating, FormGroupInline, GridLayout, Icon, Input, Link, Loader, Modal, ModalContainer, NumberInput, Pager, PagerControlsBasic, PageSizeControl, Passwordbox, ProgressBar, RadioList, Slider, TabContainer, Tab, Textbox, TransitionContainer, TransitionPanel, Toast, ToastContainer, Tooltip, TooltipProvider, ValidationSummary };
46
+ export { Alert, AutoCompleteDropDown, Badge, Button, Card, Checkbox, Collapsable, ColorPicker, ContextMenuContainer, DatePicker, DropDown, FileBasicInput, FileContext, FileDropArea, FileInput, FileUploadButton, FileUploadProgress, Form, FormContext, FormGroup, FormGroupFloating, FormGroupInline, GridLayout, Icon, Input, Link, Loader, Modal, ModalContainer, NumberInput, Pager, PagerControlsBasic, PageSizeControl, Passwordbox, PopupHost, ProgressBar, RadioList, Slider, TabContainer, Tab, Textbox, TransitionContainer, TransitionPanel, Toast, ToastContainer, Tooltip, TooltipProvider, ValidationSummary };
@@ -30,6 +30,7 @@ import NumberInput from './NumberInput';
30
30
  import Pager from './Paging/Pager';
31
31
  import PagerControlsBasic from './Paging/BasicPagerControls';
32
32
  import PageSizeControl from './Paging/PageSizeControl';
33
+ import PopupHost from "./PopupHost";
33
34
  import ProgressBar from './ProgressBar';
34
35
  import RadioList from './RadioList';
35
36
  import Slider from './Slider';
@@ -42,4 +43,4 @@ import ToastContainer from './Notifications/ToastContainer';
42
43
  import Tooltip from './Tooltip';
43
44
  import TooltipProvider from './TooltipProvider';
44
45
  import ValidationSummary from './ValidationSummary';
45
- export { Alert, AutoCompleteDropDown, Badge, Button, Card, Checkbox, Collapsable, ColorPicker, ContextMenuContainer, DatePicker, DropDown, FileBasicInput, FileContext, FileDropArea, FileInput, FileUploadButton, FileUploadProgress, Form, FormContext, FormGroup, FormGroupFloating, FormGroupInline, GridLayout, Icon, Input, Link, Loader, Modal, ModalContainer, NumberInput, Pager, PagerControlsBasic, PageSizeControl, Passwordbox, ProgressBar, RadioList, Slider, TabContainer, Tab, Textbox, TransitionContainer, TransitionPanel, Toast, ToastContainer, Tooltip, TooltipProvider, ValidationSummary };
46
+ export { Alert, AutoCompleteDropDown, Badge, Button, Card, Checkbox, Collapsable, ColorPicker, ContextMenuContainer, DatePicker, DropDown, FileBasicInput, FileContext, FileDropArea, FileInput, FileUploadButton, FileUploadProgress, Form, FormContext, FormGroup, FormGroupFloating, FormGroupInline, GridLayout, Icon, Input, Link, Loader, Modal, ModalContainer, NumberInput, Pager, PagerControlsBasic, PageSizeControl, Passwordbox, PopupHost, ProgressBar, RadioList, Slider, TabContainer, Tab, Textbox, TransitionContainer, TransitionPanel, Toast, ToastContainer, Tooltip, TooltipProvider, ValidationSummary };
@@ -0,0 +1,8 @@
1
+ export interface ISearchItem {
2
+ name: string;
3
+ icon?: string;
4
+ onClick: () => void;
5
+ }
6
+ export interface ISearchItemProvider {
7
+ getItems(): ISearchItem[] | Promise<ISearchItem[]>;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import { ISearchItem, ISearchItemProvider } from "./ISearchItemProvider";
2
+ import { IMenuRoute } from "./MenuRoute";
3
+ /**
4
+ * Provides items displayed on the main menu.
5
+ * The items passed to this constructor should be the same as what is passed to the sidebar.
6
+ */
7
+ export declare class MainMenuItemProvider implements ISearchItemProvider {
8
+ private navigationHelper;
9
+ private allItems;
10
+ constructor(routes: IMenuRoute[], navigationHelper?: import("./NavigationHelper").INavigationHelper);
11
+ getItems(): ISearchItem[];
12
+ private flattenRoutes;
13
+ }
@@ -0,0 +1,38 @@
1
+ import { Misc } from "@singularsystems/neo-core";
2
+ import { NeoReactTypes } from "../Modules/Types";
3
+ /**
4
+ * Provides items displayed on the main menu.
5
+ * The items passed to this constructor should be the same as what is passed to the sidebar.
6
+ */
7
+ var MainMenuItemProvider = /** @class */ (function () {
8
+ function MainMenuItemProvider(routes, navigationHelper) {
9
+ if (navigationHelper === void 0) { navigationHelper = Misc.Globals.appService.get(NeoReactTypes.Routing.NavigationHelper); }
10
+ this.navigationHelper = navigationHelper;
11
+ this.allItems = [];
12
+ this.flattenRoutes(routes);
13
+ }
14
+ MainMenuItemProvider.prototype.getItems = function () {
15
+ var _this = this;
16
+ return this.allItems.map(function (route) { return ({
17
+ name: route.name,
18
+ icon: route.icon,
19
+ onClick: function () {
20
+ if (route.path) {
21
+ _this.navigationHelper.navigateInternal(route.path);
22
+ }
23
+ },
24
+ }); }).sortBy(function (c) { return c.name; });
25
+ };
26
+ MainMenuItemProvider.prototype.flattenRoutes = function (routes) {
27
+ var _a;
28
+ (_a = this.allItems).push.apply(_a, routes.filter(function (r) { return r.path; }));
29
+ for (var _i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
30
+ var route = routes_1[_i];
31
+ if (route.children) {
32
+ this.flattenRoutes(route.children);
33
+ }
34
+ }
35
+ };
36
+ return MainMenuItemProvider;
37
+ }());
38
+ export { MainMenuItemProvider };
@@ -0,0 +1,13 @@
1
+ import { ISearchItem, ISearchItemProvider } from "./ISearchItemProvider";
2
+ import { IMenuRoute } from "./MenuRoute";
3
+ /**
4
+ * Provides items displayed on the main menu.
5
+ * The items passed to this constructor should be the same as what is passed to the sidebar.
6
+ */
7
+ export declare class MainMenuSearchItemProvider implements ISearchItemProvider {
8
+ private navigationHelper;
9
+ private allItems;
10
+ constructor(routes: IMenuRoute[], navigationHelper?: import("./NavigationHelper").INavigationHelper);
11
+ getItems(): ISearchItem[];
12
+ private flattenRoutes;
13
+ }
@@ -0,0 +1,38 @@
1
+ import { Misc } from "@singularsystems/neo-core";
2
+ import { NeoReactTypes } from "../Modules/Types";
3
+ /**
4
+ * Provides items displayed on the main menu.
5
+ * The items passed to this constructor should be the same as what is passed to the sidebar.
6
+ */
7
+ var MainMenuSearchItemProvider = /** @class */ (function () {
8
+ function MainMenuSearchItemProvider(routes, navigationHelper) {
9
+ if (navigationHelper === void 0) { navigationHelper = Misc.Globals.appService.get(NeoReactTypes.Routing.NavigationHelper); }
10
+ this.navigationHelper = navigationHelper;
11
+ this.allItems = [];
12
+ this.flattenRoutes(routes);
13
+ }
14
+ MainMenuSearchItemProvider.prototype.getItems = function () {
15
+ var _this = this;
16
+ return this.allItems.map(function (route) { return ({
17
+ name: route.name,
18
+ icon: route.icon,
19
+ onClick: function () {
20
+ if (route.path) {
21
+ _this.navigationHelper.navigateInternal(route.path);
22
+ }
23
+ },
24
+ }); }).sortBy(function (c) { return c.name; });
25
+ };
26
+ MainMenuSearchItemProvider.prototype.flattenRoutes = function (routes) {
27
+ var _a;
28
+ (_a = this.allItems).push.apply(_a, routes.filter(function (r) { return r.path; }));
29
+ for (var _i = 0, routes_1 = routes; _i < routes_1.length; _i++) {
30
+ var route = routes_1[_i];
31
+ if (route.children) {
32
+ this.flattenRoutes(route.children);
33
+ }
34
+ }
35
+ };
36
+ return MainMenuSearchItemProvider;
37
+ }());
38
+ export { MainMenuSearchItemProvider };
@@ -1,5 +1,4 @@
1
1
  import { __assign, __spreadArray } from "tslib";
2
- import { MenuRoute } from './MenuRoute';
3
2
  var RouteProvider = /** @class */ (function () {
4
3
  /**
5
4
  * Creates a route provider which provides a list of flattened routes.
@@ -106,10 +105,9 @@ var RouteProvider = /** @class */ (function () {
106
105
  * Adds a unique key, and adds route parameters extracted from the component static params object.
107
106
  */
108
107
  RouteProvider.prototype.processRoute = function (into, route) {
108
+ var _a;
109
109
  var processed = __assign(__assign({}, route), { path: route.path, params: [], key: this.key++, order: 0 });
110
- if (route instanceof MenuRoute) {
111
- processed.path = route.basePath;
112
- }
110
+ processed.path = (_a = route.basePath) !== null && _a !== void 0 ? _a : route.path;
113
111
  processed.path = processed.path.toLowerCase();
114
112
  if (processed.path.length > 1 && processed.path.endsWith("/")) {
115
113
  processed.path = processed.path.substring(0, processed.path.length - 1);
@@ -2,8 +2,8 @@ export { default as RouteProvider } from './RouteProvider';
2
2
  export { default as RouteView } from './RouteView';
3
3
  export * from './BreadCrumbItem';
4
4
  export { PageLeaveHandler } from './PageLeaveHandler';
5
- export { IMenuRoute, MenuRoute } from './MenuRoute';
6
- export { INavigationHelper } from './NavigationHelper';
7
- export { IViewParameter } from './ViewParameter';
8
- export { BreadCrumbSelectMode, IRouteParameter, RouteParameters } from './IRouteParameter';
9
- export { IRouteChangedProps } from './IRouteChangedProps';
5
+ export { type IMenuRoute, MenuRoute } from './MenuRoute';
6
+ export type { INavigationHelper } from './NavigationHelper';
7
+ export type { IViewParameter } from './ViewParameter';
8
+ export { BreadCrumbSelectMode, type IRouteParameter, type RouteParameters } from './IRouteParameter';
9
+ export type { IRouteChangedProps } from './IRouteChangedProps';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularsystems/neo-react",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
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",