@chelone/core 0.5.0 → 0.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.
- package/dist/assistant/assistant-session.d.ts +28 -0
- package/dist/assistant/assistant-session.js +208 -0
- package/dist/assistant/echo-transport.d.ts +7 -0
- package/dist/assistant/echo-transport.js +28 -0
- package/dist/assistant/http-transport.d.ts +10 -0
- package/dist/assistant/http-transport.js +98 -0
- package/dist/assistant/types.d.ts +54 -0
- package/dist/auth/access-control.d.ts +13 -5
- package/dist/auth/access-control.js +25 -21
- package/dist/auth/auth-options.d.ts +21 -17
- package/dist/auth/auth-options.js +80 -48
- package/dist/auth/permission-matrix.d.ts +12 -0
- package/dist/auth/permission-matrix.js +67 -0
- package/dist/auth/types.d.ts +14 -4
- package/dist/block-editor/block-document.d.ts +60 -0
- package/dist/block-editor/block-document.js +143 -0
- package/dist/block-editor/data-blocks.d.ts +63 -0
- package/dist/block-editor/data-blocks.js +117 -0
- package/dist/chart/chart-data.d.ts +25 -0
- package/dist/chart/chart-data.js +61 -0
- package/dist/command-menu/hotkey.js +58 -47
- package/dist/command-menu/recents.js +8 -11
- package/dist/command-menu/registry.d.ts +9 -5
- package/dist/command-menu/registry.js +36 -46
- package/dist/controller/calendar-dates.js +82 -113
- package/dist/controller/calendar-events.js +93 -88
- package/dist/controller/client-list-controller.d.ts +2 -2
- package/dist/controller/client-list-controller.js +251 -254
- package/dist/controller/data-table-columns.d.ts +2 -0
- package/dist/controller/data-table-columns.js +50 -56
- package/dist/controller/deep-equal.d.ts +1 -0
- package/dist/controller/deep-equal.js +14 -0
- package/dist/controller/filter-toggle.js +36 -44
- package/dist/controller/in-place-editor.d.ts +42 -0
- package/dist/controller/in-place-editor.js +42 -0
- package/dist/controller/infinite-list-controller.js +220 -190
- package/dist/controller/inspector.d.ts +49 -0
- package/dist/controller/inspector.js +64 -0
- package/dist/controller/job-monitor.d.ts +41 -0
- package/dist/controller/job-monitor.js +49 -0
- package/dist/controller/kanban-board.d.ts +2 -3
- package/dist/controller/kanban-board.js +43 -24
- package/dist/controller/list-controller.d.ts +5 -5
- package/dist/controller/list-controller.js +444 -400
- package/dist/controller/list-params.js +96 -87
- package/dist/controller/pivot-grid.d.ts +36 -0
- package/dist/controller/pivot-grid.js +99 -0
- package/dist/controller/prev-next.d.ts +2 -2
- package/dist/controller/prev-next.js +74 -54
- package/dist/controller/record-controllers.d.ts +14 -6
- package/dist/controller/record-controllers.js +288 -257
- package/dist/controller/record-diff.d.ts +21 -0
- package/dist/controller/record-diff.js +50 -0
- package/dist/controller/record-timeline.d.ts +35 -0
- package/dist/controller/record-timeline.js +48 -0
- package/dist/controller/record-tree.js +57 -47
- package/dist/controller/record-workflow.d.ts +38 -16
- package/dist/controller/record-workflow.js +85 -64
- package/dist/controller/reference-many-controller.js +198 -192
- package/dist/controller/reference-one-controller.d.ts +1 -1
- package/dist/controller/reference-one-controller.js +63 -56
- package/dist/controller/saved-queries.js +104 -91
- package/dist/controller/translate-fallback.js +10 -6
- package/dist/csv/export.d.ts +2 -1
- package/dist/csv/export.js +43 -40
- package/dist/csv/import-controller.js +185 -169
- package/dist/csv/match-headers.js +29 -22
- package/dist/csv/parse-with.js +60 -54
- package/dist/csv/run-import.js +69 -72
- package/dist/csv/validate-rows.d.ts +1 -1
- package/dist/csv/validate-rows.js +65 -52
- package/dist/data/cache-ops.d.ts +5 -4
- package/dist/data/cache-ops.js +208 -190
- package/dist/data/combine-data-providers.js +25 -23
- package/dist/data/data-provider-log.d.ts +45 -0
- package/dist/data/data-provider-log.js +93 -0
- package/dist/data/errors.js +14 -10
- package/dist/data/fake-provider.d.ts +6 -3
- package/dist/data/fake-provider.js +129 -114
- package/dist/data/fetch-utils.js +61 -44
- package/dist/data/filter-branch.d.ts +5 -0
- package/dist/data/filter-branch.js +10 -0
- package/dist/data/get-many-aggregate.js +84 -76
- package/dist/data/http-error.js +17 -12
- package/dist/data/keys.js +50 -36
- package/dist/data/mutation-options.d.ts +14 -9
- package/dist/data/mutation-options.js +93 -109
- package/dist/data/query-options.js +73 -68
- package/dist/data/remove-empty.d.ts +3 -0
- package/dist/data/remove-empty.js +11 -0
- package/dist/data/undoable.d.ts +2 -2
- package/dist/data/undoable.js +190 -174
- package/dist/data/with-lifecycle-callbacks.d.ts +45 -17
- package/dist/data/with-lifecycle-callbacks.js +66 -52
- package/dist/environment/application-update-store.js +58 -55
- package/dist/environment/offline-store.js +21 -21
- package/dist/form/array-binding.d.ts +30 -11
- package/dist/form/array-binding.js +184 -166
- package/dist/form/choice-ids.d.ts +7 -0
- package/dist/form/choice-ids.js +11 -0
- package/dist/form/choices-controller.d.ts +3 -2
- package/dist/form/choices-controller.js +302 -275
- package/dist/form/date-format.d.ts +38 -0
- package/dist/form/date-format.js +89 -0
- package/dist/form/dirty-values.d.ts +2 -2
- package/dist/form/dirty-values.js +22 -11
- package/dist/form/duration.d.ts +22 -0
- package/dist/form/duration.js +49 -0
- package/dist/form/edit-create-form.d.ts +12 -5
- package/dist/form/edit-create-form.js +243 -188
- package/dist/form/event-value.d.ts +6 -0
- package/dist/form/event-value.js +17 -0
- package/dist/form/field-error.d.ts +14 -0
- package/dist/form/field-error.js +28 -0
- package/dist/form/field-name.d.ts +20 -0
- package/dist/form/field-name.js +6 -0
- package/dist/form/filter-form-values.js +63 -49
- package/dist/form/form-controller.d.ts +9 -1
- package/dist/form/form-controller.js +165 -160
- package/dist/form/form-groups.d.ts +4 -3
- package/dist/form/form-groups.js +79 -79
- package/dist/form/form-handle.d.ts +175 -0
- package/dist/form/form-handle.js +68 -0
- package/dist/form/input-binding.d.ts +56 -31
- package/dist/form/input-binding.js +169 -118
- package/dist/form/input-values.d.ts +130 -0
- package/dist/form/input-values.js +177 -0
- package/dist/form/json-text.js +51 -37
- package/dist/form/save-pipeline.d.ts +6 -8
- package/dist/form/save-pipeline.js +91 -82
- package/dist/form/set-form-values.d.ts +6 -0
- package/dist/form/set-form-values.js +10 -0
- package/dist/form/source.js +97 -65
- package/dist/form/text-of.d.ts +2 -0
- package/dist/form/text-of.js +7 -0
- package/dist/form/validators.d.ts +58 -19
- package/dist/form/validators.js +97 -71
- package/dist/geo/bbox.d.ts +5 -4
- package/dist/geo/bbox.js +69 -48
- package/dist/geo/bounds.d.ts +14 -3
- package/dist/geo/bounds.js +98 -68
- package/dist/geo/constraints.js +88 -93
- package/dist/geo/coordinates.js +31 -23
- package/dist/geo/editor.d.ts +13 -13
- package/dist/geo/editor.js +176 -153
- package/dist/geo/geocoding.d.ts +4 -4
- package/dist/geo/geocoding.js +38 -41
- package/dist/geo/geojson.d.ts +12 -74
- package/dist/geo/geojson.js +52 -40
- package/dist/geo/geometry-math.d.ts +4 -4
- package/dist/geo/geometry-math.js +100 -93
- package/dist/geo/index.d.ts +7 -6
- package/dist/geo/map-layers.d.ts +42 -7
- package/dist/geo/map-layers.js +88 -62
- package/dist/geo/map-style.js +31 -32
- package/dist/geo/messages.js +48 -45
- package/dist/geo/nominatim.js +88 -80
- package/dist/geo/osm-presets.d.ts +4 -3
- package/dist/geo/osm-presets.js +108 -86
- package/dist/geo/osm-tags.js +14 -12
- package/dist/geo/overpass.d.ts +14 -2
- package/dist/geo/overpass.js +83 -90
- package/dist/geo/shape-value.d.ts +9 -5
- package/dist/geo/shape-value.js +169 -146
- package/dist/geo/snap-to-roads.d.ts +3 -3
- package/dist/geo/snap-to-roads.js +55 -50
- package/dist/geo/throttle.js +36 -39
- package/dist/guards.d.ts +37 -0
- package/dist/guards.js +62 -0
- package/dist/i18n/default-messages.js +34 -29
- package/dist/i18n/english-messages.js +187 -189
- package/dist/i18n/i18n.d.ts +8 -2
- package/dist/i18n/i18n.js +47 -48
- package/dist/i18n/inflection.d.ts +34 -0
- package/dist/i18n/inflection.js +82 -0
- package/dist/i18n/messages.d.ts +10 -2
- package/dist/i18n/messages.js +17 -4
- package/dist/i18n/missing-keys.d.ts +19 -0
- package/dist/i18n/missing-keys.js +68 -0
- package/dist/i18n/translatable.d.ts +16 -1
- package/dist/i18n/translatable.js +40 -47
- package/dist/index.d.ts +96 -22
- package/dist/index.js +52 -257
- package/dist/json/deep-equal.d.ts +8 -0
- package/dist/json/deep-equal.js +24 -0
- package/dist/json/strip-json-comments.js +38 -42
- package/dist/noop.d.ts +2 -0
- package/dist/noop.js +4 -0
- package/dist/notification/error-message.d.ts +2 -0
- package/dist/notification/error-message.js +10 -0
- package/dist/notification/notification-store.d.ts +3 -2
- package/dist/notification/notification-store.js +41 -45
- package/dist/onboarding-tour/placement.d.ts +34 -0
- package/dist/onboarding-tour/placement.js +67 -0
- package/dist/onboarding-tour/tour-controller.d.ts +25 -0
- package/dist/onboarding-tour/tour-controller.js +50 -0
- package/dist/realtime/add-events-for-mutations.js +75 -81
- package/dist/realtime/announce-lock.d.ts +7 -0
- package/dist/realtime/announce-lock.js +18 -0
- package/dist/realtime/broadcast-channel-transport.d.ts +14 -0
- package/dist/realtime/broadcast-channel-transport.js +69 -0
- package/dist/realtime/copy-members.js +22 -14
- package/dist/realtime/in-memory-lock-provider.js +41 -60
- package/dist/realtime/live.js +95 -101
- package/dist/realtime/lock-options.js +16 -16
- package/dist/realtime/lock-session.js +91 -78
- package/dist/realtime/memory-transport.js +26 -67
- package/dist/realtime/presence.js +120 -122
- package/dist/realtime/realtime-data-provider.d.ts +10 -0
- package/dist/realtime/realtime-data-provider.js +45 -42
- package/dist/realtime/reconnect-backoff.d.ts +15 -0
- package/dist/realtime/reconnect-backoff.js +17 -0
- package/dist/realtime/sse-transport.d.ts +31 -0
- package/dist/realtime/sse-transport.js +235 -0
- package/dist/realtime/status-store.js +23 -28
- package/dist/realtime/topic-hub.d.ts +24 -0
- package/dist/realtime/topic-hub.js +66 -0
- package/dist/realtime/topics.js +10 -12
- package/dist/realtime/types.js +10 -12
- package/dist/realtime/unread-count.js +21 -21
- package/dist/realtime/websocket-transport.d.ts +32 -0
- package/dist/realtime/websocket-transport.js +306 -0
- package/dist/resource/describe-resource.d.ts +2 -0
- package/dist/resource/describe-resource.js +232 -219
- package/dist/resource/get-at-path.js +29 -14
- package/dist/resource/identifier.d.ts +18 -0
- package/dist/resource/identifier.js +27 -0
- package/dist/resource/record.d.ts +4 -0
- package/dist/resource/record.js +10 -0
- package/dist/resource/register.d.ts +7 -0
- package/dist/resource/registry-store.d.ts +45 -15
- package/dist/resource/registry-store.js +67 -60
- package/dist/resource/registry.d.ts +10 -0
- package/dist/resource/registry.js +8 -4
- package/dist/resource/source-path.d.ts +16 -1
- package/dist/rich-text/rich-text-extras.d.ts +132 -0
- package/dist/rich-text/rich-text-extras.js +179 -0
- package/dist/rich-text/rich-text-image.d.ts +124 -0
- package/dist/rich-text/rich-text-image.js +163 -0
- package/dist/rich-text/rich-text.d.ts +62 -0
- package/dist/rich-text/rich-text.js +142 -0
- package/dist/router/location.d.ts +22 -4
- package/dist/router/location.js +41 -18
- package/dist/router/match.js +47 -39
- package/dist/router/paths.js +40 -34
- package/dist/router/record-from-location.d.ts +1 -1
- package/dist/router/record-from-location.js +25 -17
- package/dist/store/adapters.js +51 -55
- package/dist/store/micro-store.js +57 -59
- package/dist/store/shallow-equal.d.ts +12 -0
- package/dist/store/shallow-equal.js +20 -0
- package/dist/store/store.js +54 -57
- package/package.json +13 -11
package/dist/router/match.js
CHANGED
|
@@ -1,45 +1,53 @@
|
|
|
1
|
+
// src/router/match.ts
|
|
2
|
+
/** Compile a pattern into a case-insensitive regex + ordered param names. */
|
|
1
3
|
function compilePattern(pattern) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
const paramNames = [];
|
|
5
|
+
let regexpSource = `^${pattern.replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(/\\\*/g, "*").replace(/^\/*/, "/").replace(/\/+$/, "").replace(/\/:(\w+)/g, (_m, name) => {
|
|
6
|
+
paramNames.push(name);
|
|
7
|
+
return "/([^\\/]+)";
|
|
8
|
+
})}`;
|
|
9
|
+
if (pattern.endsWith("*")) {
|
|
10
|
+
paramNames.push("*");
|
|
11
|
+
regexpSource += pattern === "*" || pattern === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
|
|
12
|
+
} else regexpSource += "\\/*$";
|
|
13
|
+
return {
|
|
14
|
+
matcher: new RegExp(regexpSource, "i"),
|
|
15
|
+
paramNames
|
|
16
|
+
};
|
|
14
17
|
}
|
|
18
|
+
/** Safe URI-decode: fall back to the raw value on a malformed sequence. */
|
|
15
19
|
function safeDecode(value) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
|
+
return decodeURIComponent(value);
|
|
22
|
+
} catch {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
21
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Match `pathname` against `pattern`. Returns the captured params, the matched
|
|
28
|
+
* `pathname`, and `pathnameBase` (the match minus any splat remainder), or
|
|
29
|
+
* `null` when the pattern does not match.
|
|
30
|
+
*/
|
|
22
31
|
function matchPath(pattern, pathname) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
const { matcher, paramNames } = compilePattern(pattern);
|
|
33
|
+
const match = pathname.match(matcher);
|
|
34
|
+
if (!match) return null;
|
|
35
|
+
const matchedPathname = match[0];
|
|
36
|
+
const hasSplat = paramNames[paramNames.length - 1] === "*";
|
|
37
|
+
let pathnameBase = matchedPathname;
|
|
38
|
+
const params = {};
|
|
39
|
+
paramNames.forEach((name, index) => {
|
|
40
|
+
if (name === "*") {
|
|
41
|
+
const splat = match[index + 1] ?? "";
|
|
42
|
+
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splat.length).replace(/(.)\/+$/, "$1");
|
|
43
|
+
params["*"] = splat;
|
|
44
|
+
} else params[name] = safeDecode(match[index + 1] ?? "");
|
|
45
|
+
});
|
|
46
|
+
if (hasSplat && pathnameBase === "") pathnameBase = "/";
|
|
47
|
+
return {
|
|
48
|
+
params,
|
|
49
|
+
pathname: (matchedPathname.length > 1 ? matchedPathname.replace(/\/+$/, "") : matchedPathname) || "/",
|
|
50
|
+
pathnameBase
|
|
51
|
+
};
|
|
42
52
|
}
|
|
43
|
-
export {
|
|
44
|
-
matchPath
|
|
45
|
-
};
|
|
53
|
+
export { matchPath };
|
package/dist/router/paths.js
CHANGED
|
@@ -1,40 +1,46 @@
|
|
|
1
|
+
// src/router/paths.ts
|
|
2
|
+
/**
|
|
3
|
+
* Collapse runs of `/` into a single `/`, WITHOUT touching a `scheme://`
|
|
4
|
+
* authority separator. Matches ra-core's `removeDoubleSlashes` for internal
|
|
5
|
+
* paths while staying safe on the rare absolute URL.
|
|
6
|
+
*/
|
|
1
7
|
function removeDoubleSlashes(path) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
const schemeMatch = path.match(/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//);
|
|
9
|
+
if (schemeMatch) {
|
|
10
|
+
const prefix = schemeMatch[0];
|
|
11
|
+
return prefix + path.slice(prefix.length).replace(/\/\/+/g, "/");
|
|
12
|
+
}
|
|
13
|
+
return path.replace(/\/\/+/g, "/");
|
|
8
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Prefix `path` with `basename`, collapsing the seam and any trailing basename
|
|
17
|
+
* slash. An empty basename is a no-op. The result is always slash-normalized.
|
|
18
|
+
*/
|
|
9
19
|
function joinBasename(path, basename = "") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return collapsed.length > 1 ? collapsed.replace(/\/$/, "") : collapsed;
|
|
20
|
+
const collapsed = removeDoubleSlashes(basename ? `${basename}/${path}` : path);
|
|
21
|
+
return collapsed.length > 1 ? collapsed.replace(/\/$/, "") : collapsed;
|
|
13
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Build a route path for a link intent (parity §0a-11):
|
|
25
|
+
* `list`→`/res`, `create`→`/res/create`, `edit`→`/res/:id`, `show`→`/res/:id/show`.
|
|
26
|
+
* `id==null` on `edit`/`show` falls back to the list path. The id is
|
|
27
|
+
* `encodeURIComponent`d, and double slashes are removed from these four known
|
|
28
|
+
* intents. A custom string `type` is returned COMPLETELY verbatim — NO basename
|
|
29
|
+
* prefix, NO slash collapse — matching ra-core's `useCreatePath` `default`
|
|
30
|
+
* branch (the author owns the full, final path).
|
|
31
|
+
*/
|
|
14
32
|
function createPath(params, basename = "") {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return joinBasename(
|
|
28
|
-
`/${resource}/${encodeURIComponent(id)}/show`,
|
|
29
|
-
basename
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
default:
|
|
33
|
-
return type;
|
|
34
|
-
}
|
|
33
|
+
const { type, resource, id } = params;
|
|
34
|
+
switch (type) {
|
|
35
|
+
case "list": return joinBasename(`/${resource}`, basename);
|
|
36
|
+
case "create": return joinBasename(`/${resource}/create`, basename);
|
|
37
|
+
case "edit":
|
|
38
|
+
if (id == null) return joinBasename(`/${resource}`, basename);
|
|
39
|
+
return joinBasename(`/${resource}/${encodeURIComponent(id)}`, basename);
|
|
40
|
+
case "show":
|
|
41
|
+
if (id == null) return joinBasename(`/${resource}`, basename);
|
|
42
|
+
return joinBasename(`/${resource}/${encodeURIComponent(id)}/show`, basename);
|
|
43
|
+
default: return type;
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
|
-
export {
|
|
37
|
-
createPath,
|
|
38
|
-
joinBasename,
|
|
39
|
-
removeDoubleSlashes
|
|
40
|
-
};
|
|
46
|
+
export { createPath, joinBasename, removeDoubleSlashes };
|
|
@@ -13,6 +13,6 @@ export interface RecordFromLocationOptions {
|
|
|
13
13
|
/**
|
|
14
14
|
* The record at `state[stateSource]` if it is an object, else the JSON in the
|
|
15
15
|
* `searchSource` param. Returns `null` for no param, invalid JSON, a repeated
|
|
16
|
-
* param or a value that is not
|
|
16
|
+
* param or a value that is not an object. Never throws.
|
|
17
17
|
*/
|
|
18
18
|
export declare function getRecordFromLocation(location: Pick<CheloneLocation, "state" | "searchParams">, options?: RecordFromLocationOptions): Record<string, unknown> | null;
|
|
@@ -1,19 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { isRecord } from "../guards.js";
|
|
2
|
+
// src/router/record-from-location.ts
|
|
3
|
+
/**
|
|
4
|
+
* Read a seed record out of a location: the framework-free twin of ra-core's
|
|
5
|
+
* `useRecordFromLocation`. A router adapter passes its `CheloneLocation`;
|
|
6
|
+
* the clone link writes `?source=<json>`.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The record at `state[stateSource]` if it is an object, else the JSON in the
|
|
10
|
+
* `searchSource` param. Returns `null` for no param, invalid JSON, a repeated
|
|
11
|
+
* param or a value that is not an object. Never throws.
|
|
12
|
+
*/
|
|
4
13
|
function getRecordFromLocation(location, options = {}) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const { searchSource = "source", stateSource = "record" } = options;
|
|
15
|
+
const fromState = isRecord(location.state) ? location.state[stateSource] : void 0;
|
|
16
|
+
if (isRecord(fromState)) return fromState;
|
|
17
|
+
const values = location.searchParams.getAll(searchSource);
|
|
18
|
+
const [value] = values;
|
|
19
|
+
if (values.length !== 1 || value === void 0) return null;
|
|
20
|
+
try {
|
|
21
|
+
const parsed = JSON.parse(value);
|
|
22
|
+
return isRecord(parsed) ? parsed : null;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
16
26
|
}
|
|
17
|
-
export {
|
|
18
|
-
getRecordFromLocation
|
|
19
|
-
};
|
|
27
|
+
export { getRecordFromLocation };
|
package/dist/store/adapters.js
CHANGED
|
@@ -1,61 +1,57 @@
|
|
|
1
|
+
// src/store/adapters.ts
|
|
1
2
|
function memoryStoreAdapter(initial = {}) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
const map = new Map(Object.entries(initial));
|
|
4
|
+
return {
|
|
5
|
+
getItem: (key) => map.get(key),
|
|
6
|
+
setItem: (key, value) => void map.set(key, value),
|
|
7
|
+
removeItem: (key) => void map.delete(key)
|
|
8
|
+
};
|
|
8
9
|
}
|
|
10
|
+
/** window/localStorage touched ONLY inside method bodies — module import is SSR-safe. */
|
|
9
11
|
function storage() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
if (typeof window === "undefined") return void 0;
|
|
13
|
+
try {
|
|
14
|
+
return window.localStorage;
|
|
15
|
+
} catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
function localStorageAdapter(options = {}) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return () => window.removeEventListener("storage", listener);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
20
|
+
const prefix = options.prefix ?? "chelone.";
|
|
21
|
+
return {
|
|
22
|
+
getItem(key) {
|
|
23
|
+
const raw = storage()?.getItem(prefix + key);
|
|
24
|
+
if (raw == null) return void 0;
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(raw);
|
|
27
|
+
} catch {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
setItem(key, value) {
|
|
32
|
+
try {
|
|
33
|
+
storage()?.setItem(prefix + key, JSON.stringify(value));
|
|
34
|
+
} catch {}
|
|
35
|
+
},
|
|
36
|
+
removeItem(key) {
|
|
37
|
+
storage()?.removeItem(prefix + key);
|
|
38
|
+
},
|
|
39
|
+
subscribeExternal(onChange) {
|
|
40
|
+
if (typeof window === "undefined") return () => {};
|
|
41
|
+
const listener = (event) => {
|
|
42
|
+
if (!event.key?.startsWith(prefix)) return;
|
|
43
|
+
const key = event.key.slice(prefix.length);
|
|
44
|
+
if (event.newValue == null) {
|
|
45
|
+
onChange(key, void 0);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
onChange(key, JSON.parse(event.newValue));
|
|
50
|
+
} catch {}
|
|
51
|
+
};
|
|
52
|
+
window.addEventListener("storage", listener);
|
|
53
|
+
return () => window.removeEventListener("storage", listener);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
57
56
|
}
|
|
58
|
-
export {
|
|
59
|
-
localStorageAdapter,
|
|
60
|
-
memoryStoreAdapter
|
|
61
|
-
};
|
|
57
|
+
export { localStorageAdapter, memoryStoreAdapter };
|
|
@@ -1,61 +1,59 @@
|
|
|
1
|
+
// src/store/micro-store.ts
|
|
1
2
|
function createMicroStore(initial, options) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
};
|
|
3
|
+
let state = initial;
|
|
4
|
+
let destroyed = false;
|
|
5
|
+
let attachTeardown;
|
|
6
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
7
|
+
const cleanups = /* @__PURE__ */ new Set();
|
|
8
|
+
/** Runs the attach teardown at most once per attach cycle. */
|
|
9
|
+
const detach = () => {
|
|
10
|
+
const teardown = attachTeardown;
|
|
11
|
+
attachTeardown = void 0;
|
|
12
|
+
teardown?.();
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
getSnapshot: () => state,
|
|
16
|
+
setState(update) {
|
|
17
|
+
if (destroyed) return;
|
|
18
|
+
const patch = typeof update === "function" ? update(state) : update;
|
|
19
|
+
let changed = false;
|
|
20
|
+
for (const key in patch) if (!Object.is(state[key], patch[key])) {
|
|
21
|
+
changed = true;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
if (!changed) return;
|
|
25
|
+
state = {
|
|
26
|
+
...state,
|
|
27
|
+
...patch
|
|
28
|
+
};
|
|
29
|
+
for (const subscription of subscriptions) subscription.callback();
|
|
30
|
+
},
|
|
31
|
+
subscribe(callback) {
|
|
32
|
+
if (destroyed) return () => {};
|
|
33
|
+
const subscription = { callback };
|
|
34
|
+
const isFirst = subscriptions.size === 0;
|
|
35
|
+
subscriptions.add(subscription);
|
|
36
|
+
if (isFirst && options?.onSubscribed) attachTeardown = options.onSubscribed() ?? void 0;
|
|
37
|
+
return () => {
|
|
38
|
+
if (!subscriptions.delete(subscription)) return;
|
|
39
|
+
if (subscriptions.size === 0 && !destroyed) detach();
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
destroy() {
|
|
43
|
+
if (destroyed) return;
|
|
44
|
+
destroyed = true;
|
|
45
|
+
detach();
|
|
46
|
+
for (const cleanup of cleanups) cleanup();
|
|
47
|
+
cleanups.clear();
|
|
48
|
+
subscriptions.clear();
|
|
49
|
+
},
|
|
50
|
+
onDestroy(cleanup) {
|
|
51
|
+
if (destroyed) {
|
|
52
|
+
cleanup();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
cleanups.add(cleanup);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
58
|
}
|
|
59
|
-
export {
|
|
60
|
-
createMicroStore
|
|
61
|
-
};
|
|
59
|
+
export { createMicroStore };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `shallowEqual(a, b)`: shallow equality with `Object.is` semantics at the top
|
|
3
|
+
* level. Parity with ra-core's `shallowEqual`.
|
|
4
|
+
*
|
|
5
|
+
* - `Object.is`-equal inputs are equal, so `NaN` equals `NaN` and `0` differs
|
|
6
|
+
* from `-0`;
|
|
7
|
+
* - two objects or arrays are equal iff they have the same own enumerable keys
|
|
8
|
+
* and each value pair is `Object.is`-equal; nested values compare by
|
|
9
|
+
* reference;
|
|
10
|
+
* - a non-object, or `null`, that is not `Object.is`-equal is unequal.
|
|
11
|
+
*/
|
|
12
|
+
export declare function shallowEqual(a: unknown, b: unknown): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/store/shallow-equal.ts
|
|
2
|
+
/**
|
|
3
|
+
* `shallowEqual(a, b)`: shallow equality with `Object.is` semantics at the top
|
|
4
|
+
* level. Parity with ra-core's `shallowEqual`.
|
|
5
|
+
*
|
|
6
|
+
* - `Object.is`-equal inputs are equal, so `NaN` equals `NaN` and `0` differs
|
|
7
|
+
* from `-0`;
|
|
8
|
+
* - two objects or arrays are equal iff they have the same own enumerable keys
|
|
9
|
+
* and each value pair is `Object.is`-equal; nested values compare by
|
|
10
|
+
* reference;
|
|
11
|
+
* - a non-object, or `null`, that is not `Object.is`-equal is unequal.
|
|
12
|
+
*/
|
|
13
|
+
function shallowEqual(a, b) {
|
|
14
|
+
if (Object.is(a, b)) return true;
|
|
15
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
|
|
16
|
+
const keysA = Object.keys(a);
|
|
17
|
+
if (keysA.length !== Object.keys(b).length) return false;
|
|
18
|
+
return keysA.every((key) => Object.hasOwn(b, key) && Object.is(Reflect.get(a, key), Reflect.get(b, key)));
|
|
19
|
+
}
|
|
20
|
+
export { shallowEqual };
|
package/dist/store/store.js
CHANGED
|
@@ -1,59 +1,56 @@
|
|
|
1
|
+
// src/store/store.ts
|
|
1
2
|
function createStore(adapter) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
};
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
const hydrated = /* @__PURE__ */ new Set();
|
|
5
|
+
const subscribers = /* @__PURE__ */ new Map();
|
|
6
|
+
const notify = (key) => {
|
|
7
|
+
const set = subscribers.get(key);
|
|
8
|
+
if (set) for (const cb of set) cb();
|
|
9
|
+
};
|
|
10
|
+
const apply = (key, value) => {
|
|
11
|
+
hydrated.add(key);
|
|
12
|
+
if (value === void 0) cache.delete(key);
|
|
13
|
+
else cache.set(key, value);
|
|
14
|
+
notify(key);
|
|
15
|
+
};
|
|
16
|
+
adapter?.subscribeExternal?.((key, value) => apply(key, value));
|
|
17
|
+
return {
|
|
18
|
+
getItem(key) {
|
|
19
|
+
if (!hydrated.has(key) && adapter) {
|
|
20
|
+
hydrated.add(key);
|
|
21
|
+
const persisted = adapter.getItem(key);
|
|
22
|
+
if (persisted !== void 0) cache.set(key, persisted);
|
|
23
|
+
}
|
|
24
|
+
return cache.get(key);
|
|
25
|
+
},
|
|
26
|
+
setItem(key, value) {
|
|
27
|
+
hydrated.add(key);
|
|
28
|
+
if (Object.is(cache.get(key), value)) return;
|
|
29
|
+
cache.set(key, value);
|
|
30
|
+
adapter?.setItem(key, value);
|
|
31
|
+
notify(key);
|
|
32
|
+
},
|
|
33
|
+
removeItem(key) {
|
|
34
|
+
hydrated.add(key);
|
|
35
|
+
cache.delete(key);
|
|
36
|
+
adapter?.removeItem(key);
|
|
37
|
+
notify(key);
|
|
38
|
+
},
|
|
39
|
+
subscribe(key, callback) {
|
|
40
|
+
let set = subscribers.get(key);
|
|
41
|
+
if (!set) {
|
|
42
|
+
set = /* @__PURE__ */ new Set();
|
|
43
|
+
subscribers.set(key, set);
|
|
44
|
+
}
|
|
45
|
+
set.add(callback);
|
|
46
|
+
return () => {
|
|
47
|
+
set.delete(callback);
|
|
48
|
+
if (set.size === 0 && subscribers.get(key) === set) subscribers.delete(key);
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
keys() {
|
|
52
|
+
return [...cache.keys()];
|
|
53
|
+
}
|
|
54
|
+
};
|
|
56
55
|
}
|
|
57
|
-
export {
|
|
58
|
-
createStore
|
|
59
|
-
};
|
|
56
|
+
export { createStore };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chelone/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,21 +30,23 @@
|
|
|
30
30
|
"zod": "^3.25.0 || ^4.0.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@arethetypeswrong/cli": "^0.18.
|
|
34
|
-
"@
|
|
35
|
-
"@tanstack/
|
|
36
|
-
"@
|
|
33
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
34
|
+
"@chelone/test-utils": "0.0.0",
|
|
35
|
+
"@tanstack/form-core": "^1.33.5",
|
|
36
|
+
"@tanstack/query-core": "^5.106.1",
|
|
37
|
+
"@types/node": "^26.6.6",
|
|
37
38
|
"@types/papaparse": "^5.5.2",
|
|
38
|
-
"jsdom": "^
|
|
39
|
+
"jsdom": "^31.0.0",
|
|
39
40
|
"papaparse": "^5.7.0",
|
|
40
|
-
"publint": "^0.3.
|
|
41
|
+
"publint": "^0.3.25",
|
|
41
42
|
"terra-draw": "^1.39.0",
|
|
42
|
-
"vite": "^
|
|
43
|
-
"vitest": "^
|
|
44
|
-
"zod": "^
|
|
43
|
+
"vite": "^8.3.6",
|
|
44
|
+
"vitest": "^5.1.0",
|
|
45
|
+
"zod": "^4.6.7"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"
|
|
48
|
+
"@types/geojson": "^7946.0.16",
|
|
49
|
+
"dot.paths": "^0.2.2"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
52
|
"build": "vite build && tsc -p tsconfig.build.json && node ../../scripts/dts-extensions.mjs dist",
|