@singularsystems/neo-core 1.6.4 → 1.6.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
@@ -1,5 +1,11 @@
1
1
  # Neo core changelog
2
2
 
3
+ ## Version 1.6.5 (28 September 2026)
4
+
5
+ - Fixed position helper not correctly positioning fixed elements that are within a fixed container.
6
+ - Added support for local timezone format for dates. Timezone type can be defaulted using `DateUtils.defaultTimeZoneFormat`.
7
+ - Can be used if datetime values in your database are not stored as UTC.
8
+
3
9
  ## Version 1.6.4 (15 September 2026)
4
10
 
5
11
  - Added support for `AbortSignal` in ConfigService and AuthenticationService. Equivalent to CancellationToken.
@@ -131,14 +131,18 @@ var FixedPositionHelper = /** @class */ (function () {
131
131
  }
132
132
  };
133
133
  FixedPositionHelper.prototype.positionFixedPopup = function () {
134
+ var _a, _b, _c;
134
135
  var rect = this.anchorElement.getBoundingClientRect();
135
- this.popupElement.style.top = (Math.floor(rect.top) + this.topOffset) + "px";
136
+ var containingRect = (_a = this.popupElement.offsetParent) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
137
+ var offsetLeft = (_b = containingRect === null || containingRect === void 0 ? void 0 : containingRect.left) !== null && _b !== void 0 ? _b : 0;
138
+ var offsetTop = (_c = containingRect === null || containingRect === void 0 ? void 0 : containingRect.top) !== null && _c !== void 0 ? _c : 0;
139
+ this.popupElement.style.top = (Math.floor(rect.top - offsetTop) + this.topOffset) + "px";
136
140
  this.popupElement.style.right = "auto";
137
141
  if (this.positionInfo.left !== undefined) {
138
- this.popupElement.style.left = (rect.left + this.positionInfo.left) + "px";
142
+ this.popupElement.style.left = (rect.left - offsetLeft + this.positionInfo.left) + "px";
139
143
  }
140
144
  else {
141
- this.popupElement.style.left = (rect.right - this.popupElement.offsetWidth) + "px";
145
+ this.popupElement.style.left = (rect.right - offsetLeft - this.popupElement.offsetWidth) + "px";
142
146
  }
143
147
  };
144
148
  FixedPositionHelper.prototype.dispose = function () {
@@ -70,6 +70,7 @@ var Serialiser = /** @class */ (function () {
70
70
  this.objectRefs = {};
71
71
  };
72
72
  Serialiser.prototype.serialiseObject = function (from, to, isDictionary) {
73
+ var _a;
73
74
  if (isDictionary === void 0) { isDictionary = false; }
74
75
  //check that this object hasnt already been serialised.
75
76
  var referenceId = from[referenceIdKey];
@@ -152,8 +153,14 @@ var Serialiser = /** @class */ (function () {
152
153
  if (fromValue !== null && propertyInfo.propertyType === DataType.Decimal) {
153
154
  to[key] = NumberUtils.decimalService.toNumber(fromValue);
154
155
  }
155
- else if (propertyInfo.timeZoneSerialisation === TimeZoneFormat.None && fromValue instanceof Date) {
156
- to[key] = DateUtils.formatApi(fromValue, propertyInfo.timeZoneSerialisation);
156
+ else if (fromValue instanceof Date) {
157
+ var timezoneFormat = (_a = propertyInfo.timeZoneSerialisation) !== null && _a !== void 0 ? _a : DateUtils.defaultTimeZoneFormat;
158
+ if (timezoneFormat === TimeZoneFormat.UTC) {
159
+ to[key] = fromValue;
160
+ }
161
+ else {
162
+ to[key] = DateUtils.formatApi(fromValue, timezoneFormat);
163
+ }
157
164
  }
158
165
  else {
159
166
  to[key] = fromValue;
@@ -4,6 +4,11 @@ import { ITimeValues, TimeSpan } from "./TimeSpan";
4
4
  export default class DateUtils {
5
5
  static defaultFormatString: string;
6
6
  static defaultFormatStringWithTime: string;
7
+ /**
8
+ * The default time zone format to use when serialising dates.
9
+ * Can be overridden using `@Attributes.Date`.
10
+ */
11
+ static defaultTimeZoneFormat: TimeZoneFormat;
7
12
  private static token;
8
13
  private static timezone;
9
14
  private static timezoneClip;
@@ -17,6 +22,10 @@ export default class DateUtils {
17
22
  * Formats a date using api standards.
18
23
  */
19
24
  static formatApi(date: Date, timezoneFormat: TimeZoneFormat): string;
25
+ /**
26
+ * Converts the date instance to a string, without adding a timezone offset or UTC indicator.
27
+ */
28
+ static formatLocal(date: Date): string;
20
29
  private static pad;
21
30
  /**
22
31
  * Tries to parse a date from a string using the supplied format string
@@ -64,10 +64,25 @@ var DateUtils = /** @class */ (function () {
64
64
  if (timezoneFormat === TimeZoneFormat.UTC) {
65
65
  return date.toISOString();
66
66
  }
67
+ else if (timezoneFormat === TimeZoneFormat.Local) {
68
+ return this.formatLocal(date);
69
+ }
67
70
  else {
68
71
  return DateUtils.format(date, "yyyy-MM-dd");
69
72
  }
70
73
  };
74
+ /**
75
+ * Converts the date instance to a string, without adding a timezone offset or UTC indicator.
76
+ */
77
+ DateUtils.formatLocal = function (date) {
78
+ var dateString = DateUtils.format(date, "yyyy-MM-dd");
79
+ if (date.getMilliseconds() != 0) {
80
+ return dateString + "T" + DateUtils.format(date, "HH:mm:ss.l");
81
+ }
82
+ else {
83
+ return dateString + "T" + DateUtils.format(date, "HH:mm:ss");
84
+ }
85
+ };
71
86
  DateUtils.pad = function (val, len) {
72
87
  if (len === void 0) { len = 2; }
73
88
  val = String(val);
@@ -227,6 +242,11 @@ var DateUtils = /** @class */ (function () {
227
242
  };
228
243
  DateUtils.defaultFormatString = "dd MMM yyyy";
229
244
  DateUtils.defaultFormatStringWithTime = "dd MMM yyyy HH:mm";
245
+ /**
246
+ * The default time zone format to use when serialising dates.
247
+ * Can be overridden using `@Attributes.Date`.
248
+ */
249
+ DateUtils.defaultTimeZoneFormat = TimeZoneFormat.UTC;
230
250
  DateUtils.token = /d{1,4}|M{1,4}|yy(?:yy)?|([HhmsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g;
231
251
  DateUtils.timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g;
232
252
  DateUtils.timezoneClip = /[^-+\dA-Z]/g;
@@ -1,5 +1,5 @@
1
1
  import { ensureTypeInfo } from './NeoTypeInfo';
2
- import { SerialiseType, RelationType, OnChangedOptions, DataType, TimeZoneFormat } from './Misc';
2
+ import { SerialiseType, RelationType, OnChangedOptions, DataType } from './Misc';
3
3
  import { Utils } from "../Utils";
4
4
  function getOrAddPropertyInfo(type, propertyName) {
5
5
  return ensureTypeInfo(type.constructor).neo.getOrAddProperty(propertyName);
@@ -12,7 +12,6 @@ export function Display(name) {
12
12
  }
13
13
  /** Indicates that this is a date property. Json strings will be converted to date objects on deserialisation. */
14
14
  export function Date(timeZoneSerialisation) {
15
- if (timeZoneSerialisation === void 0) { timeZoneSerialisation = TimeZoneFormat.UTC; }
16
15
  return function (type, propertyKey, descriptor) {
17
16
  var pi = getOrAddPropertyInfo(type, propertyKey);
18
17
  pi.propertyType = DataType.Date;
@@ -15,10 +15,12 @@ export declare enum SerialiseType {
15
15
  Never = 4
16
16
  }
17
17
  export declare enum TimeZoneFormat {
18
+ /** Date will be serialised without time zone info. */
19
+ None = 0,
18
20
  /** Date will be serialised as UTC with Z */
19
21
  UTC = 1,
20
- /** Date will be serialised without time zone info. */
21
- None = 2
22
+ /** Date will be serialised as local time (no conversion from value supplied by user). */
23
+ Local = 2
22
24
  }
23
25
  export declare enum RelationType {
24
26
  None = 0,
@@ -16,10 +16,12 @@ export var SerialiseType;
16
16
  })(SerialiseType || (SerialiseType = {}));
17
17
  export var TimeZoneFormat;
18
18
  (function (TimeZoneFormat) {
19
+ /** Date will be serialised without time zone info. */
20
+ TimeZoneFormat[TimeZoneFormat["None"] = 0] = "None";
19
21
  /** Date will be serialised as UTC with Z */
20
22
  TimeZoneFormat[TimeZoneFormat["UTC"] = 1] = "UTC";
21
- /** Date will be serialised without time zone info. */
22
- TimeZoneFormat[TimeZoneFormat["None"] = 2] = "None";
23
+ /** Date will be serialised as local time (no conversion from value supplied by user). */
24
+ TimeZoneFormat[TimeZoneFormat["Local"] = 2] = "Local";
23
25
  })(TimeZoneFormat || (TimeZoneFormat = {}));
24
26
  export var RelationType;
25
27
  (function (RelationType) {
@@ -0,0 +1,18 @@
1
+ /** A stack that keeps track of the current item and allows selection by key. */
2
+ export declare class ObservableStack<T> {
3
+ constructor();
4
+ private items;
5
+ private _current?;
6
+ /**
7
+ * Adds an item to the stack.
8
+ * The `current` property will be updated to the newly added item.
9
+ * The item can be removed by calling the dispose method on the returned object. */
10
+ register(item: T, key?: string): {
11
+ /** Removes the item from the stack and updates the `current` property if this item is the current one. */
12
+ dispose: () => void;
13
+ };
14
+ /** Selects an item by its key. Will set `current` to undefined if not found. */
15
+ select(key?: string): void;
16
+ /** The current item. */
17
+ get current(): T | undefined;
18
+ }
@@ -0,0 +1,49 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { Attributes } from "..";
3
+ import { NeoTypeInfo } from "./NeoTypeInfo";
4
+ /** A stack that keeps track of the current item and allows selection by key. */
5
+ var ObservableStack = /** @class */ (function () {
6
+ function ObservableStack() {
7
+ this.items = [];
8
+ this._current = undefined;
9
+ NeoTypeInfo.makeObservable(this);
10
+ }
11
+ /**
12
+ * Adds an item to the stack.
13
+ * The `current` property will be updated to the newly added item.
14
+ * The item can be removed by calling the dispose method on the returned object. */
15
+ ObservableStack.prototype.register = function (item, key) {
16
+ var _this = this;
17
+ var keyedItem = { key: key, item: item };
18
+ this.items.push(keyedItem);
19
+ this._current = keyedItem;
20
+ return {
21
+ /** Removes the item from the stack and updates the `current` property if this item is the current one. */
22
+ dispose: function () {
23
+ _this.items.remove(keyedItem);
24
+ if (_this._current === keyedItem) {
25
+ _this._current = _this.items[_this.items.length - 1];
26
+ }
27
+ }
28
+ };
29
+ };
30
+ /** Selects an item by its key. Will set `current` to undefined if not found. */
31
+ ObservableStack.prototype.select = function (key) {
32
+ this._current = this.items.find(function (c) { return c.key === key; });
33
+ };
34
+ Object.defineProperty(ObservableStack.prototype, "current", {
35
+ /** The current item. */
36
+ get: function () {
37
+ var _a;
38
+ return (_a = this._current) === null || _a === void 0 ? void 0 : _a.item;
39
+ },
40
+ enumerable: false,
41
+ configurable: true
42
+ });
43
+ __decorate([
44
+ Attributes.Observable(),
45
+ __metadata("design:type", Object)
46
+ ], ObservableStack.prototype, "_current", void 0);
47
+ return ObservableStack;
48
+ }());
49
+ export { ObservableStack };
@@ -25,7 +25,7 @@ export default class PropertyInfo {
25
25
  observableType: Nullable<ObservableType>;
26
26
  /** See SerialiseType */
27
27
  serialise: SerialiseType;
28
- timeZoneSerialisation: TimeZoneFormat;
28
+ timeZoneSerialisation?: TimeZoneFormat;
29
29
  /** Type of parent / child if this property is related to another model. 'type' property must be set if this is not 'none'. */
30
30
  relationType: RelationType;
31
31
  /** Data type of the property. */
@@ -7,6 +7,7 @@ export { ObservableProperty } from './ObservableProperty';
7
7
  export { ISelectedItem } from './Misc';
8
8
  export { IEnumItem } from './EnumHelper';
9
9
  export { ModelFieldInfo, IModelFieldInfoContainer } from './ModelFieldInfo';
10
+ export { ObservableStack } from './ObservableStack';
10
11
  import * as GraphTraverser from './ModelGraphTraverser';
11
12
  export { GraphTraverser, PropertyInfo };
12
13
  export { AuditValues, AuditValuesBase } from './BaseModels/AuditValues';
@@ -3,6 +3,7 @@ import PropertyInfo from './PropertyInfo';
3
3
  export { ObservableValue, ValueWrapper } from './ObservableValue';
4
4
  export { ObservableProperty } from './ObservableProperty';
5
5
  export { ModelFieldInfo } from './ModelFieldInfo';
6
+ export { ObservableStack } from './ObservableStack';
6
7
  import * as GraphTraverser from './ModelGraphTraverser';
7
8
  export { GraphTraverser, PropertyInfo };
8
9
  // Base Models
@@ -45,7 +45,7 @@ var OidcAuthService = /** @class */ (function () {
45
45
  });
46
46
  OidcAuthService.prototype.loadUserFromSession = function (options) {
47
47
  return __awaiter(this, void 0, void 0, function () {
48
- var userData, userDataJson;
48
+ var userData, trySilentSignIn, useCachedData, userDataJson;
49
49
  var _a, _b;
50
50
  return __generator(this, function (_c) {
51
51
  switch (_c.label) {
@@ -60,11 +60,13 @@ var OidcAuthService = /** @class */ (function () {
60
60
  _c.sent();
61
61
  return [2 /*return*/, this.user];
62
62
  case 3:
63
+ trySilentSignIn = (_a = options === null || options === void 0 ? void 0 : options.silentSignIn) !== null && _a !== void 0 ? _a : !!window.opener, useCachedData = NetworkUtils.useCachedData(this.config);
64
+ if (!(useCachedData || trySilentSignIn)) return [3 /*break*/, 9];
63
65
  userDataJson = localStorage.getItem(storageKey);
64
66
  if (userDataJson) {
65
67
  userData = JSON.parse(userDataJson);
66
68
  }
67
- if (!NetworkUtils.useCachedData(this.config)) return [3 /*break*/, 6];
69
+ if (!useCachedData) return [3 /*break*/, 6];
68
70
  if (!userData) return [3 /*break*/, 5];
69
71
  return [4 /*yield*/, this.setUserDataAsync(userData)];
70
72
  case 4:
@@ -72,7 +74,7 @@ var OidcAuthService = /** @class */ (function () {
72
74
  _c.label = 5;
73
75
  case 5: return [2 /*return*/, this.user];
74
76
  case 6:
75
- if (!((_a = options === null || options === void 0 ? void 0 : options.silentSignIn) !== null && _a !== void 0 ? _a : !!window.opener)) return [3 /*break*/, 9];
77
+ if (!trySilentSignIn) return [3 /*break*/, 9];
76
78
  return [4 /*yield*/, AbortHelper.race(this.signinSilent(), options === null || options === void 0 ? void 0 : options.abortSignal)];
77
79
  case 7:
78
80
  _c.sent();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularsystems/neo-core",
3
- "version": "1.6.4",
3
+ "version": "1.6.5",
4
4
  "description": "Core functionality for the Neo client library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",