@octans/ui 1.6.2 → 1.7.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.
@@ -2,14 +2,35 @@ import { default as dayjs } from 'dayjs';
2
2
  declare function setLocale(locale: string): void;
3
3
  declare function setTimezone(timezone?: string | null): void;
4
4
  declare function getTimezone(): string | undefined;
5
+ declare function setInputTimezone(timezone?: string | null): void;
6
+ declare function getInputTimezone(): string | undefined;
7
+ /**
8
+ * True for a value that names a DAY rather than a moment.
9
+ *
10
+ * These are deliberately left floating: no input zone applied, no display zone
11
+ * applied. A birthday or a MySQL `DATE` column has no time and no zone, so
12
+ * pinning it to one and rendering it in another moves it — `'2024-03-15'` read
13
+ * as UTC and shown in Los Angeles is the 14th, which is how a date of birth
14
+ * ends up off by a day.
15
+ */
16
+ declare function isFloatingDate(value?: dayjs.ConfigType): boolean;
17
+ /**
18
+ * Turns a value into an instant, using `zone` for strings that do not say.
19
+ *
20
+ * Anything that is already an instant is left alone: a `Date`, an epoch
21
+ * number, another dayjs object, or a string ending in `Z` or an offset. Only
22
+ * the naive strings are ambiguous, and only they are pinned.
23
+ */
24
+ declare function parseInTimezone(value?: dayjs.ConfigType, zone?: string): dayjs.Dayjs;
5
25
  /**
6
26
  * Reads a value in the display time zone, or the viewer's clock when there
7
- * isn't one. `timezone` overrides the global for this one call.
27
+ * isn't one. `timezone` overrides the global for this one call, as does
28
+ * `inputTimezone` for the zone a naive string is read in.
8
29
  *
9
30
  * A zone the runtime rejects falls back rather than throwing: a date that
10
31
  * renders in the wrong zone is a bug, and a component that throws while
11
32
  * rendering is an outage.
12
33
  */
13
- declare function inTimezone(value?: dayjs.ConfigType, timezone?: string): dayjs.Dayjs;
34
+ declare function inTimezone(value?: dayjs.ConfigType, timezone?: string, input?: string): dayjs.Dayjs;
14
35
  declare const mysqlFormat = "YYYY-MM-DD HH:mm:ss";
15
- export { dayjs, setLocale, setTimezone, getTimezone, inTimezone, mysqlFormat };
36
+ export { dayjs, setLocale, setTimezone, getTimezone, setInputTimezone, getInputTimezone, isFloatingDate, parseInTimezone, inTimezone, mysqlFormat };
@@ -9,6 +9,17 @@ export interface FormatContextInterface {
9
9
  * to be, unconditionally.
10
10
  */
11
11
  timezone?: string;
12
+ /**
13
+ * IANA time zone a date string with no zone of its own is READ in.
14
+ *
15
+ * `timezone` picks the clock a date is shown on; this picks the clock it was
16
+ * written on. `'2024-03-15 02:00:00'` out of a MySQL `DATETIME` names no
17
+ * instant by itself, so without this it is read as the viewer's local time
18
+ * and one stored row becomes a different moment for every reader.
19
+ *
20
+ * Defaults to the library-wide input zone set with `setInputTimezone`.
21
+ */
22
+ inputTimezone?: string;
12
23
  }
13
24
  export declare const emptyValuePlaceholder = "\u2014";
14
25
  export declare const formatters: Record<string, any>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@octans/ui",
3
- "version": "1.6.2",
4
- "description": "A Vue 3 component library \u2014 accessible, themeable UI primitives and application shell components.",
3
+ "version": "1.7.0",
4
+ "description": "A Vue 3 component library accessible, themeable UI primitives and application shell components.",
5
5
  "keywords": [
6
6
  "vue",
7
7
  "vue3",
@@ -242,20 +242,37 @@ later:
242
242
  import { addTranslations, setTranslationLocale } from '@octans/ui'
243
243
  ```
244
244
 
245
- Dates have two knobs, both set once at start-up and both global:
245
+ Dates have three knobs, all global, all settable at install
246
+ (`app.use(UI, { locale, timezone, inputTimezone })`) or later:
246
247
 
247
248
  ```ts
248
- import { setLocale, setTimezone } from '@octans/ui'
249
+ import { setLocale, setTimezone, setInputTimezone } from '@octans/ui'
249
250
 
250
251
  setLocale('fr') // formats, month names, and the day the week starts on
252
+ setInputTimezone('UTC') // what a string with NO zone of its own means
251
253
  setTimezone('America/Los_Angeles') // what "now" is, and what zone dates render in
252
254
  ```
253
255
 
254
- `setTimezone` is for an app that must show ONE zone to everybody — an
255
- operations console pinned to head-office time — rather than each viewer's own
256
- clock, which is the default. It affects display only; it never reinterprets a
257
- stored value. `Formatter`, `Calendar` and `DatePicker` each take a `timezone`
258
- prop to override it for one instance.
256
+ The two zones answer different questions and are easy to confuse:
257
+
258
+ - **`setTimezone`** — the clock a date is SHOWN on. For an app that must show
259
+ one zone to everybody, an operations console pinned to head-office time,
260
+ rather than each viewer's own clock, which is the default.
261
+ - **`setInputTimezone`** — the clock a date was WRITTEN on. A MySQL `DATETIME`
262
+ arrives as `2024-03-15 02:00:00`, a wall clock naming no moment, so without
263
+ this it is read as the reader's own local time and the same stored row means
264
+ a different instant in every country. Setting `setTimezone` alone does NOT
265
+ fix that: it converts an instant that was already wrong. Set both, or
266
+ neither.
267
+
268
+ Neither is reactive — they are read during render, so set them before mounting
269
+ or remount the subtree. Two things are deliberately never reinterpreted: a
270
+ value that already names an instant (a `Z` or offset suffix, a `Date`, an epoch
271
+ number), and a bare `2024-03-15`, which is a day rather than a moment and would
272
+ otherwise render as the 14th west of the display zone.
273
+
274
+ `Formatter` takes `timezone` and `input-timezone` props to override either for
275
+ one instance; `Calendar` and `DatePicker` take `timezone`.
259
276
 
260
277
  ## Components
261
278