@danxbot/ui 7.4.2 → 7.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/dist/index.js +8822 -8653
- package/dist/index.js.map +1 -1
- package/dist/pure.js +112 -100
- package/dist/pure.js.map +1 -1
- package/dist/types/components/InlineEdit.d.ts +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/lib/reads/index.d.ts +2 -1
- package/dist/types/lib/reads/optimistic.d.ts +68 -0
- package/dist/types/lib/reads/slots.d.ts +30 -0
- package/dist/types/lib/records/store.d.ts +74 -1
- package/dist/types/lib/values/email.d.ts +6 -0
- package/dist/types/lib/values/phone.d.ts +39 -11
- package/package.json +1 -1
|
@@ -25,6 +25,77 @@ export declare function write(payload: RecordPayload, options: WriteOptions): Wr
|
|
|
25
25
|
* in one call coalesces into a single notification.
|
|
26
26
|
*/
|
|
27
27
|
export declare function writeAll(payloads: readonly RecordPayload[], options: WriteOptions): WriteAllResult;
|
|
28
|
+
/**
|
|
29
|
+
* One optimistic write, held ON TOP of a record's base rather than merged into it.
|
|
30
|
+
*
|
|
31
|
+
* ==== WHY A LAYER AND NOT A WRITE ====
|
|
32
|
+
*
|
|
33
|
+
* The first optimistic writes built on this store merged the belief into the base with a
|
|
34
|
+
* client-invented `__timestamp`, and each one then had to work around what that did:
|
|
35
|
+
*
|
|
36
|
+
* - the rollback had to be stamped NEWER than the belief, or the out-of-order guard dropped
|
|
37
|
+
* it — and a same-millisecond apply-then-revert is not newer, so a local monotonic clock
|
|
38
|
+
* was needed to get it through;
|
|
39
|
+
* - once a client timestamp was stored, the SERVER's own later answer could lose to it, since
|
|
40
|
+
* a browser clock and a database column are not the same clock;
|
|
41
|
+
* - the rollback snapshot came from a read, which strips the envelope, so `__type` had to be
|
|
42
|
+
* patched back in before the store would take it.
|
|
43
|
+
*
|
|
44
|
+
* A layer has none of those problems by construction. The base — the only thing the ordering
|
|
45
|
+
* guard adjudicates — is never touched by the belief, so the belief can never outrank a server
|
|
46
|
+
* answer and removing it is a removal, not a write that has to win anything.
|
|
47
|
+
*
|
|
48
|
+
* ==== ORDER ====
|
|
49
|
+
*
|
|
50
|
+
* Layers apply oldest first, so the newest belief about a field is the one a reader sees — a
|
|
51
|
+
* set, clear, set, clear on one field shows the last clear the moment it is made, whatever
|
|
52
|
+
* order the four answers come back in. Removing a layer from the middle leaves every later one
|
|
53
|
+
* standing: undoing write 2 of 4 does not undo 3 and 4.
|
|
54
|
+
*/
|
|
55
|
+
export interface OptimisticLayer {
|
|
56
|
+
/** Global and strictly increasing — also the issue order of the writes that made them. */
|
|
57
|
+
readonly id: number;
|
|
58
|
+
/** Data fields, stored as given — never normalized, so a patch cannot mint records. */
|
|
59
|
+
fields: Record<string, unknown>;
|
|
60
|
+
/** An ISO time when this layer is a delete. */
|
|
61
|
+
readonly tombstone: string | undefined;
|
|
62
|
+
/** True when this layer IS the record — an optimistic create with no server row yet. */
|
|
63
|
+
readonly created: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Put an optimistic layer on top of `Type:id`, creating a base-less record for a create.
|
|
67
|
+
*
|
|
68
|
+
* Notification is QUEUED here, like every other store change; the optimistic-write primitive
|
|
69
|
+
* flushes synchronously afterwards, because a user-initiated write must never wait on an
|
|
70
|
+
* animation frame (a hidden page never gets one).
|
|
71
|
+
*
|
|
72
|
+
* @returns the layer id, for `removeOptimisticLayer` / `trimOptimisticLayers`
|
|
73
|
+
*/
|
|
74
|
+
export declare function pushOptimisticLayer(type: string, id: string | number, layer: {
|
|
75
|
+
fields?: Record<string, unknown>;
|
|
76
|
+
tombstone?: string;
|
|
77
|
+
created?: boolean;
|
|
78
|
+
}): number;
|
|
79
|
+
/**
|
|
80
|
+
* Take one layer off. A record that only ever existed as an optimistic create disappears with
|
|
81
|
+
* its last layer — it reads `unknown` again, exactly as before the create.
|
|
82
|
+
*/
|
|
83
|
+
export declare function removeOptimisticLayer(key: string, layerId: number): void;
|
|
84
|
+
/**
|
|
85
|
+
* A later write's answer has landed: every OLDER layer's belief about the same fields is
|
|
86
|
+
* superseded, whether or not that older request has answered yet. A layer left with nothing to
|
|
87
|
+
* say is dropped. Without this, a set whose answer is still out would keep overlaying a field
|
|
88
|
+
* the server has already confirmed was cleared after it.
|
|
89
|
+
*/
|
|
90
|
+
export declare function trimOptimisticLayers(key: string, beforeLayerId: number, fields: readonly string[]): void;
|
|
91
|
+
/**
|
|
92
|
+
* Whether the BASE is tombstoned — what a list slot prunes on. An optimistic delete hides the
|
|
93
|
+
* row from every read but must not cost the slot its key, or a rollback would bring the record
|
|
94
|
+
* back with no list left holding it.
|
|
95
|
+
*/
|
|
96
|
+
export declare function isBaseTombstoned(key: string): boolean;
|
|
97
|
+
/** Does `key` carry any optimistic layer right now? */
|
|
98
|
+
export declare function hasOptimisticLayers(key: string): boolean;
|
|
28
99
|
/**
|
|
29
100
|
* The `unknown` state, as ONE module-level frozen constant.
|
|
30
101
|
*
|
|
@@ -54,7 +125,9 @@ export declare function peekRecord(type: string, id: string | number, needs: str
|
|
|
54
125
|
*
|
|
55
126
|
* Exported so a caller that must observe the effect of a write synchronously —
|
|
56
127
|
* a test, or a measurement taken immediately after a write — can flush rather
|
|
57
|
-
* than wait for a frame.
|
|
128
|
+
* than wait for a frame. The optimistic write (`reads/optimistic.ts`) flushes
|
|
129
|
+
* after every step: a reader's own action is one change, not a burst, and it
|
|
130
|
+
* must reach the screen in the same tick even on a page that gets no frames.
|
|
58
131
|
*/
|
|
59
132
|
export declare function flushRecordNotifications(): void;
|
|
60
133
|
export declare function subscribeToKey(key: string, listener: () => void): () => void;
|
|
@@ -2,5 +2,11 @@
|
|
|
2
2
|
* Whether `value` reads as a plausible email address. An empty (or
|
|
3
3
|
* whitespace-only) value is treated as VALID — clearing the field is not a
|
|
4
4
|
* typo, and a required-field rule belongs to the caller, not this check.
|
|
5
|
+
*
|
|
6
|
+
* SG-909 review fix: the previous regex (`/^[^\s@]+@[^\s@]+\.[^\s@]+$/`)
|
|
7
|
+
* matched the domain half non-specifically, so `"a@b..com"` (an empty label
|
|
8
|
+
* between two dots) passed, and it never looked at trailing punctuation at
|
|
9
|
+
* all, so `"jane@example.com."` and `"jane@example.com,"` — the shape a typo
|
|
10
|
+
* or a sentence's own full stop produces — both passed too.
|
|
5
11
|
*/
|
|
6
12
|
export declare function isValidEmail(value: string): boolean;
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
* rule `formatDate` documents. A stored value should already be `parsePhone`'s
|
|
7
7
|
* output; if it is not, that is a data problem worth seeing in the row, not
|
|
8
8
|
* a blank field that looks like nobody ever entered a number.
|
|
9
|
+
*
|
|
10
|
+
* Reuses `formatPhonePartial` for the ten-digit case (SG-909 review) rather
|
|
11
|
+
* than repeating the same three-slice punctuation a second time — passing it
|
|
12
|
+
* exactly ten digits always produces the identical `"(XXX) XXX-XXXX"` string,
|
|
13
|
+
* since `formatPhonePartial` only ever appends a raw, unformatted tail past
|
|
14
|
+
* the tenth digit and there is no tail here.
|
|
9
15
|
*/
|
|
10
16
|
export declare function formatPhone(value: string | null | undefined): string;
|
|
11
17
|
/**
|
|
@@ -19,22 +25,44 @@ export declare function formatPhone(value: string | null | undefined): string;
|
|
|
19
25
|
* too many, or an 11-digit number NOT starting with `1` (a foreign number
|
|
20
26
|
* mis-typed into a US field, not a US number with an extra digit) — returns
|
|
21
27
|
* `null` rather than truncating or padding a guess into place.
|
|
28
|
+
*
|
|
29
|
+
* THIS is the one place in the file the 11-digit-leading-`1` rule is written
|
|
30
|
+
* (SG-909 review — it used to also live in `digitsOfPhoneInProgress`, which
|
|
31
|
+
* no longer transforms digits at all; see that function's own doc for why).
|
|
22
32
|
*/
|
|
23
33
|
export declare function parsePhone(input: string): string | null;
|
|
24
34
|
/**
|
|
25
|
-
* Every non-digit stripped
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
35
|
+
* Every non-digit stripped — nothing else. `PhoneField` (SG-909) keeps this
|
|
36
|
+
* as ITS state while a person is still typing.
|
|
37
|
+
*
|
|
38
|
+
* Deliberately NOT capped at ten and NOT country-code-aware, unlike an
|
|
39
|
+
* earlier revision of this function. That revision silently dropped every
|
|
40
|
+
* digit past the tenth and stripped a leading `"1"` off an 11-digit run —
|
|
41
|
+
* which meant pasting `"555-123-4567 x12"` or `"44 20 7946 0958"` (a UK
|
|
42
|
+
* number) landed at commit as `parsePhone` accepting whatever ten-or-eleven
|
|
43
|
+
* digits happened to survive the cap, saving a DIFFERENT phone number than
|
|
44
|
+
* the one actually typed, with no error and no visible sign anything had
|
|
45
|
+
* been thrown away. `PhoneField` now keeps the full digit sequence — see its
|
|
46
|
+
* own module comment for how it is FORMATTED (first ten punctuated, any rest
|
|
47
|
+
* appended raw) and how `parsePhone` alone decides, at commit, whether the
|
|
48
|
+
* full sequence resolves to a real ten-digit number.
|
|
30
49
|
*/
|
|
31
50
|
export declare function digitsOfPhoneInProgress(input: string): string;
|
|
32
51
|
/**
|
|
33
|
-
*
|
|
34
|
-
* progressively punctuated as each
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
52
|
+
* A digit sequence of any length → what the box shows WHILE TYPING —
|
|
53
|
+
* progressively punctuated as each of the first ten digits lands, with any
|
|
54
|
+
* digit past the tenth appended after a space, UNFORMATTED, rather than
|
|
55
|
+
* silently dropped (SG-909 review). `formatPhone` above is the too-late-to-
|
|
56
|
+
* use-here sibling: it takes the STORED ten-digit form and either renders it
|
|
57
|
+
* or hands back a non-ten-digit value unchanged, which would show a partial
|
|
58
|
+
* number completely unpunctuated until the last digit arrived, and would
|
|
59
|
+
* have nowhere to put an eleventh digit at all.
|
|
60
|
+
*
|
|
61
|
+
* The trailing digits past ten are shown, not hidden, specifically so a
|
|
62
|
+
* too-long paste or a stray extra keystroke stays visible for the person to
|
|
63
|
+
* see and correct — `parsePhone` will refuse anything that is not exactly
|
|
64
|
+
* ten digits (or eleven with a leading `1`) at commit, and a refusal against
|
|
65
|
+
* a box that visibly still has extra digits in it is legible; a refusal
|
|
66
|
+
* against a box that silently ate them is not.
|
|
39
67
|
*/
|
|
40
68
|
export declare function formatPhonePartial(digits: string): string;
|