@colixsystems/widget-sdk 0.152.0 → 0.153.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/README.md CHANGED
@@ -72,7 +72,17 @@ See the design reference for the full architecture: [`docs/architecture/widget-m
72
72
 
73
73
  ## Status
74
74
 
75
- `v0.152.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
75
+ `v0.153.0` — pre-publish. The package surface (types, function names, export paths) is the v1 contract; runtime behaviour for some hooks is stubbed (each hook documents what's wired and what isn't). It is **not yet published to npm**.
76
+
77
+ ### What's new in 0.153.0 (contract 1.118.0 — unchanged)
78
+
79
+ **`./host` publishes the local-clock DATETIME conversion `<DateTimePicker>` uses (sc-8448).** The Studio's Data Manager sliced the stored UTC string and saved the input's value without a zone, so it showed and wrote UTC labelled as local. It now reads the same conversion the picker does, so a stored instant shows the same wall clock in the Studio and in the Player.
80
+
81
+ - **`isoToDateTimeLocalInput(value)`** — a stored instant as `<input type="datetime-local">`'s `YYYY-MM-DDTHH:mm` on the viewer's clock. A bare `YYYY-MM-DD` is local midnight.
82
+ - **`dateTimeLocalInputToIso(raw)`** — the inverse: a local `YYYY-MM-DDTHH:mm` as a full UTC ISO instant.
83
+ - **`formatDateTimeLabel(value, mode)`** — the picker's trigger label (`YYYY-MM-DD HH:mm` local for `"datetime"`).
84
+
85
+ Behaviour: a bare date given to a `mode="datetime"` picker now shows local midnight instead of UTC midnight (which read as the previous evening west of Greenwich), and a year before 1000 is zero-padded so typing a year no longer clears the web input. Otherwise additive.
76
86
 
77
87
  ### What's new in 0.152.0 (contract 1.118.0 — unchanged)
78
88
 
@@ -15,12 +15,33 @@ export function parseToDate(value) {
15
15
  return new Date();
16
16
  }
17
17
 
18
+ const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
19
+
20
+ // A stored DATETIME instant → `<input type="datetime-local">`'s
21
+ // `YYYY-MM-DDTHH:mm` on the viewer's local clock. A bare calendar date is
22
+ // local midnight, not UTC midnight, so it never slips a day west of Greenwich.
23
+ export function isoToDateTimeLocalInput(value) {
24
+ if (value == null || value === "") return "";
25
+ if (typeof value === "string" && DATE_ONLY.test(value)) return `${value}T00:00`;
26
+ const d = new Date(value);
27
+ if (Number.isNaN(d.getTime())) return "";
28
+ return `${formatToIso(d, "date")}T${formatToIso(d, "time")}`;
29
+ }
30
+
31
+ // The inverse: a naive local `YYYY-MM-DDTHH:mm` → a full UTC ISO instant.
32
+ export function dateTimeLocalInputToIso(raw) {
33
+ if (raw == null || raw === "") return "";
34
+ const d = new Date(raw);
35
+ if (Number.isNaN(d.getTime())) return "";
36
+ return d.toISOString();
37
+ }
38
+
18
39
  export function formatToIso(date, mode) {
19
40
  if (!(date instanceof Date) || Number.isNaN(date.getTime())) return null;
20
41
  if (mode === "date") {
21
42
  // Local-date ISO (yyyy-mm-dd) — calendar dates are timezone-free so a
22
43
  // "May 28" picked in Stockholm doesn't read as "May 27" in NYC.
23
- const y = date.getFullYear();
44
+ const y = String(date.getFullYear()).padStart(4, "0");
24
45
  const m = String(date.getMonth() + 1).padStart(2, "0");
25
46
  const d = String(date.getDate()).padStart(2, "0");
26
47
  return `${y}-${m}-${d}`;
@@ -46,10 +67,8 @@ export function formatDisplayLabel(value, mode) {
46
67
  }
47
68
  if (effectiveMode === "date") return String(value).slice(0, 10);
48
69
  if (effectiveMode === "time") return String(value).slice(0, 5);
49
- // datetime — render the stored UTC ISO in the user's local clock.
50
- const d = new Date(value);
51
- if (Number.isNaN(d.getTime())) return String(value);
52
- return `${formatToIso(d, "date")} ${formatToIso(d, "time")}`;
70
+ const local = isoToDateTimeLocalInput(value);
71
+ return local ? local.replace("T", " ") : String(value);
53
72
  }
54
73
 
55
74
  // Perceived-luminance test for a hex colour (`#rgb` or `#rrggbb`). The web
@@ -26,7 +26,11 @@
26
26
 
27
27
  import React from "react";
28
28
  import { useHostTheme } from "./hooks.js";
29
- import { isDarkColor } from "./datetimepicker-format.js";
29
+ import {
30
+ isDarkColor,
31
+ isoToDateTimeLocalInput,
32
+ dateTimeLocalInputToIso,
33
+ } from "./datetimepicker-format.js";
30
34
  import { DEFAULT_THEME_TOKENS } from "./_theme-tokens.js";
31
35
 
32
36
  const MODE_TO_INPUT_TYPE = {
@@ -51,15 +55,7 @@ function _isoToInputValue(value, mode) {
51
55
  if (mode === "time") {
52
56
  return String(value).slice(0, 5);
53
57
  }
54
- // datetime-local
55
- const d = new Date(value);
56
- if (Number.isNaN(d.getTime())) return "";
57
- const y = d.getFullYear();
58
- const m = String(d.getMonth() + 1).padStart(2, "0");
59
- const day = String(d.getDate()).padStart(2, "0");
60
- const hh = String(d.getHours()).padStart(2, "0");
61
- const mm = String(d.getMinutes()).padStart(2, "0");
62
- return `${y}-${m}-${day}T${hh}:${mm}`;
58
+ return isoToDateTimeLocalInput(value);
63
59
  }
64
60
 
65
61
  // Translate the input's typed string back to the ISO format the wire wants.
@@ -69,9 +65,7 @@ function _isoToInputValue(value, mode) {
69
65
  function _inputValueToIso(raw, mode) {
70
66
  if (raw == null || raw === "") return "";
71
67
  if (mode === "date" || mode === "time") return raw;
72
- const d = new Date(raw);
73
- if (Number.isNaN(d.getTime())) return "";
74
- return d.toISOString();
68
+ return dateTimeLocalInputToIso(raw);
75
69
  }
76
70
 
77
71
  export function DateTimePicker({
package/dist/host.d.ts CHANGED
@@ -452,3 +452,22 @@ export function resolveGradientTokenStops(
452
452
  gradient: unknown,
453
453
  theme: unknown,
454
454
  ): unknown;
455
+
456
+ /**
457
+ * sc-8448 — a stored DATETIME instant as `<input type="datetime-local">`'s
458
+ * `YYYY-MM-DDTHH:mm` on the viewer's local clock. A bare `YYYY-MM-DD` is local
459
+ * midnight. Empty or unparseable input returns `""`.
460
+ */
461
+ export function isoToDateTimeLocalInput(value: unknown): string;
462
+
463
+ /** sc-8448 — a local `YYYY-MM-DDTHH:mm` as a full UTC ISO instant, or `""`. */
464
+ export function dateTimeLocalInputToIso(raw: unknown): string;
465
+
466
+ /**
467
+ * sc-8448 — the `<DateTimePicker>` trigger label: for `"datetime"` the stored
468
+ * instant as `YYYY-MM-DD HH:mm` local time, falling back to the raw string.
469
+ */
470
+ export function formatDateTimeLabel(
471
+ value: unknown,
472
+ mode: "date" | "time" | "datetime",
473
+ ): string;
package/dist/host.js CHANGED
@@ -124,3 +124,10 @@ export {
124
124
  normaliseThemeGradient,
125
125
  normaliseLoginDesign,
126
126
  } from "./theme-background.js";
127
+
128
+ // sc-8448: one DATETIME local-clock conversion for the picker and the Studio.
129
+ export {
130
+ isoToDateTimeLocalInput,
131
+ dateTimeLocalInputToIso,
132
+ formatDisplayLabel as formatDateTimeLabel,
133
+ } from "./datetimepicker-format.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colixsystems/widget-sdk",
3
- "version": "0.152.0",
3
+ "version": "0.153.0",
4
4
  "description": "Common widget interface for AppStudio. Implements WidgetManifest, WidgetContext, property schema, and helper hooks.",
5
5
  "homepage": "https://github.com/Colix-AB/AppStudio",
6
6
  "type": "module",