@cosmicdrift/kumiko-renderer 0.328.0 → 0.328.1
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/app/action-form-shim.d.ts +14 -0
- package/{src/app/action-form-shim.ts → dist/app/action-form-shim.js} +26 -46
- package/dist/app/app-features-context.d.ts +8 -0
- package/dist/app/app-features-context.js +16 -0
- package/dist/app/column-renderers.d.ts +30 -0
- package/dist/app/column-renderers.js +34 -0
- package/dist/app/config-edit-shim.d.ts +11 -0
- package/{src/app/config-edit-shim.ts → dist/app/config-edit-shim.js} +12 -25
- package/dist/app/content-editors.d.ts +38 -0
- package/dist/app/content-editors.js +26 -0
- package/dist/app/content-preview.d.ts +11 -0
- package/dist/app/content-preview.js +30 -0
- package/dist/app/custom-screens.d.ts +11 -0
- package/dist/app/custom-screens.js +20 -0
- package/dist/app/dashboard-body.d.ts +16 -0
- package/dist/app/dashboard-body.js +11 -0
- package/dist/app/extension-form-submit.d.ts +32 -0
- package/dist/app/extension-form-submit.js +73 -0
- package/dist/app/extension-sections.d.ts +72 -0
- package/dist/app/extension-sections.js +34 -0
- package/dist/app/feature-schema.d.ts +4 -0
- package/{src/app/feature-schema.ts → dist/app/feature-schema.js} +12 -22
- package/dist/app/form-schema.d.ts +4 -0
- package/dist/app/form-schema.js +85 -0
- package/dist/app/kumiko-screen.d.ts +43 -0
- package/dist/app/kumiko-screen.js +2206 -0
- package/dist/app/layout-fields.d.ts +3 -0
- package/dist/app/layout-fields.js +20 -0
- package/dist/app/list-facets.d.ts +48 -0
- package/dist/app/list-facets.js +185 -0
- package/dist/app/nav.d.ts +61 -0
- package/dist/app/nav.js +139 -0
- package/dist/app/projection-detail-shim.d.ts +8 -0
- package/dist/app/projection-detail-shim.js +71 -0
- package/dist/app/projection-list-shim.d.ts +13 -0
- package/{src/app/projection-list-shim.ts → dist/app/projection-list-shim.js} +26 -41
- package/dist/app/qn.d.ts +7 -0
- package/{src/app/qn.ts → dist/app/qn.js} +9 -11
- package/dist/app/qualify-screen-id.d.ts +2 -0
- package/{src/app/qualify-screen-id.ts → dist/app/qualify-screen-id.js} +5 -6
- package/dist/app/reference-facet-bridge.d.ts +10 -0
- package/dist/app/reference-facet-bridge.js +22 -0
- package/dist/app/return-to.d.ts +31 -0
- package/dist/app/return-to.js +188 -0
- package/dist/app/row-actions.d.ts +77 -0
- package/dist/app/row-actions.js +416 -0
- package/dist/app/screen-access.d.ts +8 -0
- package/dist/app/screen-access.js +48 -0
- package/dist/app/secret-mint-body.d.ts +10 -0
- package/dist/app/secret-mint-body.js +140 -0
- package/dist/app/secrets-edit-body.d.ts +8 -0
- package/dist/app/secrets-edit-body.js +76 -0
- package/dist/app/use-embedded-screen.d.ts +6 -0
- package/dist/app/use-embedded-screen.js +19 -0
- package/dist/app/variable-chips.d.ts +7 -0
- package/dist/app/variable-chips.js +16 -0
- package/dist/app/write-failed-error.d.ts +6 -0
- package/dist/app/write-failed-error.js +21 -0
- package/dist/components/embedded-list-field.d.ts +10 -0
- package/dist/components/embedded-list-field.js +259 -0
- package/dist/components/grid-cell-for-field.d.ts +25 -0
- package/dist/components/grid-cell-for-field.js +31 -0
- package/dist/components/multi-select-checkboxes.d.ts +14 -0
- package/dist/components/multi-select-checkboxes.js +36 -0
- package/dist/components/reference-create-dialog.d.ts +13 -0
- package/dist/components/reference-create-dialog.js +46 -0
- package/dist/components/related-list-section.d.ts +25 -0
- package/dist/components/related-list-section.js +273 -0
- package/dist/components/render-edit-action-button.d.ts +22 -0
- package/dist/components/render-edit-action-button.js +43 -0
- package/dist/components/render-edit-logic.d.ts +6 -0
- package/dist/components/render-edit-logic.js +63 -0
- package/dist/components/render-edit-types.d.ts +209 -0
- package/dist/components/render-edit-types.js +1 -0
- package/dist/components/render-edit.d.ts +6 -0
- package/dist/components/render-edit.js +1169 -0
- package/dist/components/render-field.d.ts +38 -0
- package/dist/components/render-field.js +544 -0
- package/dist/components/render-list.d.ts +117 -0
- package/dist/components/render-list.js +232 -0
- package/dist/components/write-form-section.d.ts +17 -0
- package/dist/components/write-form-section.js +104 -0
- package/dist/context/dispatcher-context.d.ts +10 -0
- package/{src/context/dispatcher-context.tsx → dist/context/dispatcher-context.js} +16 -29
- package/dist/context/draft-storage-context.d.ts +12 -0
- package/dist/context/draft-storage-context.js +18 -0
- package/dist/context/user-roles-context.d.ts +7 -0
- package/{src/context/user-roles-context.tsx → dist/context/user-roles-context.js} +7 -15
- package/dist/format-when.d.ts +1 -0
- package/{src/format-when.ts → dist/format-when.js} +7 -7
- package/dist/hooks/reference-limits.d.ts +3 -0
- package/{src/hooks/reference-limits.ts → dist/hooks/reference-limits.js} +0 -1
- package/dist/hooks/use-ai-text.d.ts +52 -0
- package/dist/hooks/use-ai-text.js +90 -0
- package/dist/hooks/use-disclosure.d.ts +7 -0
- package/dist/hooks/use-disclosure.js +8 -0
- package/dist/hooks/use-form.d.ts +7 -0
- package/dist/hooks/use-form.js +36 -0
- package/dist/hooks/use-list-url-state.d.ts +43 -0
- package/dist/hooks/use-list-url-state.js +131 -0
- package/dist/hooks/use-mutation.d.ts +9 -0
- package/dist/hooks/use-mutation.js +37 -0
- package/dist/hooks/use-query.d.ts +14 -0
- package/dist/hooks/use-query.js +118 -0
- package/dist/hooks/use-reference-lookup.d.ts +14 -0
- package/dist/hooks/use-reference-lookup.js +63 -0
- package/dist/hooks/use-store.d.ts +3 -0
- package/dist/hooks/use-store.js +38 -0
- package/dist/hooks/use-stream-handler.d.ts +14 -0
- package/dist/hooks/use-stream-handler.js +93 -0
- package/dist/i18n-defaults.d.ts +2 -0
- package/dist/i18n-defaults.js +201 -0
- package/dist/i18n.d.ts +64 -0
- package/dist/i18n.js +166 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +55 -0
- package/dist/inside-drawer.d.ts +2 -0
- package/{src/inside-drawer.ts → dist/inside-drawer.js} +2 -5
- package/dist/page-header-slot.d.ts +2 -0
- package/{src/page-header-slot.ts → dist/page-header-slot.js} +2 -5
- package/dist/primitives.d.ts +1351 -0
- package/dist/primitives.js +73 -0
- package/dist/screen-fills-height.d.ts +3 -0
- package/dist/screen-fills-height.js +3 -0
- package/dist/share-links.d.ts +4 -0
- package/dist/share-links.js +11 -0
- package/dist/sort-by-accessor.d.ts +5 -0
- package/dist/sort-by-accessor.js +16 -0
- package/dist/sse/live-events.d.ts +23 -0
- package/dist/sse/live-events.js +28 -0
- package/dist/tokens.d.ts +83 -0
- package/dist/tokens.js +80 -0
- package/package.json +16 -9
- package/src/__tests__/error-i18n-defaults.test.ts +0 -82
- package/src/__tests__/format-when.test.ts +0 -12
- package/src/__tests__/i18n.test.tsx +0 -283
- package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
- package/src/__tests__/qn.test.ts +0 -83
- package/src/__tests__/share-links.test.ts +0 -26
- package/src/__tests__/sort-by-accessor.test.ts +0 -48
- package/src/__tests__/stringify-nav-params.test.ts +0 -33
- package/src/__tests__/use-list-url-state.test.tsx +0 -250
- package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
- package/src/app/__tests__/action-form-shim.test.ts +0 -137
- package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
- package/src/app/__tests__/config-edit-shim.test.ts +0 -57
- package/src/app/__tests__/content-editors.test.tsx +0 -128
- package/src/app/__tests__/content-preview.test.tsx +0 -184
- package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
- package/src/app/__tests__/entity-edit-fill-height.test.tsx +0 -118
- package/src/app/__tests__/entity-edit-jsonb-embedded-submit.test.tsx +0 -239
- package/src/app/__tests__/entity-list-create-singleton.test.tsx +0 -128
- package/src/app/__tests__/entity-list-row-action-entity-target.test.tsx +0 -424
- package/src/app/__tests__/entity-list-row-action-icon.test.tsx +0 -248
- package/src/app/__tests__/entity-list-row-action-kumiko-actions-view.test.tsx +0 -162
- package/src/app/__tests__/entity-list-row-action-refetch.test.tsx +0 -401
- package/src/app/__tests__/entity-list-screen-padding.test.tsx +0 -128
- package/src/app/__tests__/feature-schema.test.ts +0 -40
- package/src/app/__tests__/form-schema.test.ts +0 -247
- package/src/app/__tests__/list-daterange-facet.test.ts +0 -165
- package/src/app/__tests__/list-filter-facets.test.tsx +0 -521
- package/src/app/__tests__/nav.test.ts +0 -198
- package/src/app/__tests__/projection-detail-actions.test.tsx +0 -719
- package/src/app/__tests__/projection-detail-reference-field.test.tsx +0 -165
- package/src/app/__tests__/projection-detail-shim.test.ts +0 -188
- package/src/app/__tests__/projection-detail-singleton.test.tsx +0 -191
- package/src/app/__tests__/projection-list-bad-shape.test.tsx +0 -152
- package/src/app/__tests__/projection-list-reference-column.test.tsx +0 -219
- package/src/app/__tests__/projection-list-search-sort.test.tsx +0 -212
- package/src/app/__tests__/qualified-names.test.ts +0 -37
- package/src/app/__tests__/return-to.test.ts +0 -396
- package/src/app/__tests__/row-actions-navigate-tab.test.ts +0 -223
- package/src/app/__tests__/row-default-edit-action.test.tsx +0 -324
- package/src/app/__tests__/screen-access-allows.test.ts +0 -34
- package/src/app/__tests__/secret-mint-body.test.tsx +0 -404
- package/src/app/__tests__/variable-chips.test.tsx +0 -70
- package/src/app/app-features-context.tsx +0 -25
- package/src/app/column-renderers.tsx +0 -68
- package/src/app/content-editors.tsx +0 -85
- package/src/app/content-preview.tsx +0 -67
- package/src/app/custom-screens.tsx +0 -29
- package/src/app/dashboard-body.tsx +0 -33
- package/src/app/extension-form-submit.tsx +0 -123
- package/src/app/extension-sections.tsx +0 -111
- package/src/app/form-schema.ts +0 -91
- package/src/app/kumiko-screen.tsx +0 -3801
- package/src/app/layout-fields.ts +0 -31
- package/src/app/list-facets.ts +0 -259
- package/src/app/nav.tsx +0 -258
- package/src/app/projection-detail-shim.ts +0 -86
- package/src/app/reference-facet-bridge.tsx +0 -58
- package/src/app/return-to.tsx +0 -234
- package/src/app/row-actions.ts +0 -640
- package/src/app/screen-access.ts +0 -63
- package/src/app/secret-mint-body.tsx +0 -259
- package/src/app/secrets-edit-body.tsx +0 -194
- package/src/app/use-embedded-screen.ts +0 -27
- package/src/app/variable-chips.tsx +0 -39
- package/src/app/write-failed-error.ts +0 -27
- package/src/components/__tests__/embedded-list-field.test.tsx +0 -531
- package/src/components/__tests__/multi-select-checkboxes.test.tsx +0 -162
- package/src/components/__tests__/related-list-section-empty-state.test.tsx +0 -143
- package/src/components/__tests__/related-list-section.test.tsx +0 -1733
- package/src/components/__tests__/render-edit-action-button.test.tsx +0 -205
- package/src/components/__tests__/render-edit-hidden-section.test.tsx +0 -128
- package/src/components/__tests__/render-edit-logic.test.ts +0 -314
- package/src/components/__tests__/render-edit-screen-description.test.tsx +0 -152
- package/src/components/__tests__/render-edit-submit-actions.test.tsx +0 -460
- package/src/components/__tests__/render-field-app-locale.test.tsx +0 -142
- package/src/components/__tests__/render-field-enum-option.test.tsx +0 -99
- package/src/components/__tests__/render-field-icon-derivation.test.tsx +0 -119
- package/src/components/__tests__/render-field-json-format.test.tsx +0 -164
- package/src/components/__tests__/render-field-money-embedded-list-consistency.test.tsx +0 -212
- package/src/components/__tests__/render-field-money-roundtrip.test.tsx +0 -217
- package/src/components/__tests__/render-field-number-grouping.test.tsx +0 -76
- package/src/components/__tests__/render-field-number-unit.test.tsx +0 -227
- package/src/components/__tests__/render-field-password-format.test.tsx +0 -101
- package/src/components/__tests__/render-field-select-display.test.tsx +0 -134
- package/src/components/__tests__/render-field-unit-format.test.tsx +0 -107
- package/src/components/__tests__/render-field-unsupported-types.test.tsx +0 -195
- package/src/components/__tests__/render-list-toolbar-icon-only.test.tsx +0 -146
- package/src/components/__tests__/write-form-section.test.tsx +0 -375
- package/src/components/embedded-list-field.tsx +0 -354
- package/src/components/grid-cell-for-field.tsx +0 -88
- package/src/components/multi-select-checkboxes.tsx +0 -93
- package/src/components/reference-create-dialog.tsx +0 -91
- package/src/components/related-list-section.tsx +0 -491
- package/src/components/render-edit-action-button.tsx +0 -109
- package/src/components/render-edit-logic.ts +0 -85
- package/src/components/render-edit-types.ts +0 -226
- package/src/components/render-edit.tsx +0 -1871
- package/src/components/render-field.tsx +0 -951
- package/src/components/render-list.tsx +0 -593
- package/src/components/write-form-section.tsx +0 -198
- package/src/context/draft-storage-context.tsx +0 -39
- package/src/hooks/__tests__/use-ai-text.test.tsx +0 -177
- package/src/hooks/__tests__/use-disclosure.test.tsx +0 -25
- package/src/hooks/__tests__/use-form.test.tsx +0 -65
- package/src/hooks/__tests__/use-mutation.test.tsx +0 -77
- package/src/hooks/__tests__/use-query.test.tsx +0 -149
- package/src/hooks/__tests__/use-stream-handler.test.tsx +0 -107
- package/src/hooks/use-ai-text.ts +0 -172
- package/src/hooks/use-disclosure.ts +0 -20
- package/src/hooks/use-form.ts +0 -78
- package/src/hooks/use-list-url-state.ts +0 -207
- package/src/hooks/use-mutation.ts +0 -61
- package/src/hooks/use-query.ts +0 -166
- package/src/hooks/use-reference-lookup.ts +0 -76
- package/src/hooks/use-store.ts +0 -48
- package/src/hooks/use-stream-handler.ts +0 -134
- package/src/i18n-defaults.ts +0 -240
- package/src/i18n.tsx +0 -286
- package/src/index.ts +0 -279
- package/src/primitives.tsx +0 -1567
- package/src/screen-fills-height.ts +0 -3
- package/src/share-links.ts +0 -12
- package/src/sort-by-accessor.ts +0 -20
- package/src/sse/live-events.tsx +0 -56
- package/src/tokens.tsx +0 -170
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, } from "react";
|
|
3
|
+
/** Structural marker a top-level `actions` node can carry so DefaultForm's
|
|
4
|
+
* sticky-footer split (fw#1918) treats it as the pinned primary action even
|
|
5
|
+
* though it isn't a `Button` with `type="submit"` — e.g. RenderEdit's
|
|
6
|
+
* footer-slot mount, whose actual rendered button is opaque app code the
|
|
7
|
+
* split can't inspect (see `ScreenSlots.footerPrimary`). */
|
|
8
|
+
export const STICKY_PRIMARY_ACTION_PROP = "kumikoStickyPrimaryAction";
|
|
9
|
+
/** Teil-C action-icon collapse rule: a group of more than two actions where
|
|
10
|
+
* every member carries an icon renders icon-only instead of wall-to-wall
|
|
11
|
+
* text buttons; any icon-less member keeps the whole group on text so it
|
|
12
|
+
* doesn't fall apart visually mid-group. */
|
|
13
|
+
export function shouldRenderActionsIconOnly(actions) {
|
|
14
|
+
return actions.length > 2 && actions.every((a) => a.icon !== undefined);
|
|
15
|
+
}
|
|
16
|
+
// Status value -> StatusTone heuristic, shared by every surface that shows a
|
|
17
|
+
// raw status value without a tone of its own (projectionDetail header badge,
|
|
18
|
+
// list cells). Covers the common status vocabularies; unknown values stay
|
|
19
|
+
// undefined so the caller keeps its own neutral default.
|
|
20
|
+
const STATUS_TONE_BY_VALUE = {
|
|
21
|
+
ok: "ok",
|
|
22
|
+
active: "ok",
|
|
23
|
+
done: "ok",
|
|
24
|
+
complete: "ok",
|
|
25
|
+
completed: "ok",
|
|
26
|
+
paid: "ok",
|
|
27
|
+
approved: "ok",
|
|
28
|
+
published: "ok",
|
|
29
|
+
success: "ok",
|
|
30
|
+
pending: "warn",
|
|
31
|
+
processing: "warn",
|
|
32
|
+
review: "warn",
|
|
33
|
+
"in-review": "warn",
|
|
34
|
+
waiting: "warn",
|
|
35
|
+
open: "warn",
|
|
36
|
+
draft: "warn",
|
|
37
|
+
failed: "bad",
|
|
38
|
+
error: "bad",
|
|
39
|
+
overdue: "bad",
|
|
40
|
+
rejected: "bad",
|
|
41
|
+
blocked: "bad",
|
|
42
|
+
critical: "bad",
|
|
43
|
+
};
|
|
44
|
+
const STATUS_TONE_BY_OPTION_TONE = {
|
|
45
|
+
ok: "ok",
|
|
46
|
+
warn: "warn",
|
|
47
|
+
bad: "bad",
|
|
48
|
+
neutral: "muted",
|
|
49
|
+
};
|
|
50
|
+
export function statusToneForOptionTone(tone) {
|
|
51
|
+
return STATUS_TONE_BY_OPTION_TONE[tone];
|
|
52
|
+
}
|
|
53
|
+
export function statusToneForValue(value) {
|
|
54
|
+
const slug = value
|
|
55
|
+
.trim()
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/[\s_]+/g, "-");
|
|
58
|
+
// Own-key check: the value comes from row data, and a plain object lookup
|
|
59
|
+
// would hand back `Object.prototype.constructor` & friends as a "tone".
|
|
60
|
+
return Object.hasOwn(STATUS_TONE_BY_VALUE, slug) ? STATUS_TONE_BY_VALUE[slug] : undefined;
|
|
61
|
+
}
|
|
62
|
+
// ---- Context + Provider + Hook ----
|
|
63
|
+
const PrimitivesContext = createContext(undefined);
|
|
64
|
+
export function PrimitivesProvider({ children, value }) {
|
|
65
|
+
return _jsx(PrimitivesContext.Provider, { value: value, children: children });
|
|
66
|
+
}
|
|
67
|
+
export function usePrimitives() {
|
|
68
|
+
const registry = useContext(PrimitivesContext);
|
|
69
|
+
if (registry === undefined) {
|
|
70
|
+
throw new Error("usePrimitives: no <PrimitivesProvider> mounted. Wrap your app in one (createKumikoApp does this for you with defaultPrimitives from @cosmicdrift/kumiko-renderer-web).");
|
|
71
|
+
}
|
|
72
|
+
return registry;
|
|
73
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** wa.me link that opens WhatsApp with `text` prefilled — addressed to
|
|
2
|
+
* `phone` when given (any formatting; international form required, a
|
|
3
|
+
* leading "+" or "00" is accepted), otherwise WhatsApp's contact picker. */
|
|
4
|
+
export declare function buildWhatsAppShareUrl(text: string, phone?: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** wa.me link that opens WhatsApp with `text` prefilled — addressed to
|
|
2
|
+
* `phone` when given (any formatting; international form required, a
|
|
3
|
+
* leading "+" or "00" is accepted), otherwise WhatsApp's contact picker. */
|
|
4
|
+
export function buildWhatsAppShareUrl(text, phone) {
|
|
5
|
+
const recipient = phone === undefined ? "" : whatsAppRecipientDigits(phone);
|
|
6
|
+
return `https://wa.me/${recipient}?text=${encodeURIComponent(text)}`;
|
|
7
|
+
}
|
|
8
|
+
function whatsAppRecipientDigits(phone) {
|
|
9
|
+
const digits = phone.replace(/\D/g, "");
|
|
10
|
+
return digits.startsWith("00") ? digits.slice(2) : digits;
|
|
11
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DataTableSort } from "./primitives.js";
|
|
2
|
+
/** Sorts `rows` by a `DataTableSort` against a field->accessor map. Unknown
|
|
3
|
+
* field or `sort === null` returns `rows` unchanged (no-op, not an error —
|
|
4
|
+
* callers pass whatever the DataTable reports). */
|
|
5
|
+
export declare function sortByAccessor<TRow>(rows: readonly TRow[], sort: DataTableSort | null, accessors: Readonly<Record<string, (row: TRow) => string | number>>): readonly TRow[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Sorts `rows` by a `DataTableSort` against a field->accessor map. Unknown
|
|
2
|
+
* field or `sort === null` returns `rows` unchanged (no-op, not an error —
|
|
3
|
+
* callers pass whatever the DataTable reports). */
|
|
4
|
+
export function sortByAccessor(rows, sort, accessors) {
|
|
5
|
+
if (sort === null)
|
|
6
|
+
return rows;
|
|
7
|
+
const accessor = accessors[sort.field];
|
|
8
|
+
if (accessor === undefined)
|
|
9
|
+
return rows;
|
|
10
|
+
const factor = sort.dir === "asc" ? 1 : -1;
|
|
11
|
+
return [...rows].sort((a, b) => {
|
|
12
|
+
const av = accessor(a);
|
|
13
|
+
const bv = accessor(b);
|
|
14
|
+
return av < bv ? -factor : av > bv ? factor : 0;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type LiveEvent = {
|
|
3
|
+
readonly type: string;
|
|
4
|
+
readonly data: {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly aggregateType: string;
|
|
7
|
+
readonly version: number;
|
|
8
|
+
readonly payload: unknown;
|
|
9
|
+
readonly createdAt: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
/** Abonniert Live-Events für eine Entity (aggregateType). Returnt die
|
|
13
|
+
* Unsubscribe-Funktion. Mehrere Subscriptions parallel auf dieselbe
|
|
14
|
+
* Entity sind erlaubt — jede bekommt ihr eigenes Event. */
|
|
15
|
+
export type LiveEventSubscriber = (entityName: string, listener: (event: LiveEvent) => void) => () => void;
|
|
16
|
+
export type LiveEventsProviderProps = {
|
|
17
|
+
readonly children: ReactNode;
|
|
18
|
+
readonly value: LiveEventSubscriber;
|
|
19
|
+
};
|
|
20
|
+
export declare function LiveEventsProvider({ children, value }: LiveEventsProviderProps): ReactNode;
|
|
21
|
+
/** Hook für useQuery-like Consumer. Liefert die Subscribe-Function
|
|
22
|
+
* aus dem Context. Wenn kein Provider da ist, ist's ein No-op. */
|
|
23
|
+
export declare function useLiveEvents(): LiveEventSubscriber;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Live-Events-Contract, plattform-neutral. Die Plattform (Web mit
|
|
3
|
+
// EventSource, Native mit polyfill) liefert einen `LiveEventSubscriber`
|
|
4
|
+
// via `<LiveEventsProvider value={...}>`; der shared-Layer konsumiert
|
|
5
|
+
// nur das Interface.
|
|
6
|
+
//
|
|
7
|
+
// Warum ein Context statt Module-Singleton wie vor dem Split: ein
|
|
8
|
+
// Module-Singleton koppelt an eine globale Verbindung. Mit Context
|
|
9
|
+
// kann der Caller pro Tree eine andere Subscribe-Quelle durchreichen
|
|
10
|
+
// — nützlich in Tests (Fake-Feed), bei Multi-Tenant-Bridges, und
|
|
11
|
+
// beim Native-Renderer wo die Verbindungs-Lifecycle oft nicht dem
|
|
12
|
+
// App-Lifecycle entspricht.
|
|
13
|
+
import { createContext, useContext } from "react";
|
|
14
|
+
// Wenn kein Provider da ist, liefern wir einen No-op-Subscriber statt
|
|
15
|
+
// zu crashen. Grund: useQuery({ live: true }) kann optimistisch
|
|
16
|
+
// ausgehakt werden ohne den ganzen Baum abzureißen, wenn die Plattform
|
|
17
|
+
// z.B. SSE temporär deaktiviert hat. Fehler-Signale würden stumm
|
|
18
|
+
// geschluckt — das ist explizit dokumentiert.
|
|
19
|
+
const noopSubscriber = () => () => { };
|
|
20
|
+
const LiveEventsContext = createContext(noopSubscriber);
|
|
21
|
+
export function LiveEventsProvider({ children, value }) {
|
|
22
|
+
return _jsx(LiveEventsContext.Provider, { value: value, children: children });
|
|
23
|
+
}
|
|
24
|
+
/** Hook für useQuery-like Consumer. Liefert die Subscribe-Function
|
|
25
|
+
* aus dem Context. Wenn kein Provider da ist, ist's ein No-op. */
|
|
26
|
+
export function useLiveEvents() {
|
|
27
|
+
return useContext(LiveEventsContext);
|
|
28
|
+
}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type ColorTokens = {
|
|
3
|
+
readonly background: string;
|
|
4
|
+
readonly foreground: string;
|
|
5
|
+
readonly card: string;
|
|
6
|
+
readonly cardForeground: string;
|
|
7
|
+
readonly popover: string;
|
|
8
|
+
readonly popoverForeground: string;
|
|
9
|
+
readonly primary: string;
|
|
10
|
+
readonly primaryForeground: string;
|
|
11
|
+
readonly secondary: string;
|
|
12
|
+
readonly secondaryForeground: string;
|
|
13
|
+
readonly muted: string;
|
|
14
|
+
readonly mutedForeground: string;
|
|
15
|
+
readonly accent: string;
|
|
16
|
+
readonly accentForeground: string;
|
|
17
|
+
readonly destructive: string;
|
|
18
|
+
readonly destructiveForeground: string;
|
|
19
|
+
readonly border: string;
|
|
20
|
+
readonly input: string;
|
|
21
|
+
readonly ring: string;
|
|
22
|
+
};
|
|
23
|
+
export type RadiusTokens = {
|
|
24
|
+
readonly sm: string;
|
|
25
|
+
readonly md: string;
|
|
26
|
+
readonly lg: string;
|
|
27
|
+
readonly xl: string;
|
|
28
|
+
};
|
|
29
|
+
export type FontTokens = {
|
|
30
|
+
readonly sans: string;
|
|
31
|
+
readonly heading: string;
|
|
32
|
+
readonly mono: string;
|
|
33
|
+
};
|
|
34
|
+
export type ShadowTokens = {
|
|
35
|
+
readonly card: string;
|
|
36
|
+
};
|
|
37
|
+
export type SpacingTokens = {
|
|
38
|
+
readonly card: string;
|
|
39
|
+
};
|
|
40
|
+
export type CoreTokens = {
|
|
41
|
+
readonly color: ColorTokens;
|
|
42
|
+
readonly radius: RadiusTokens;
|
|
43
|
+
readonly font: FontTokens;
|
|
44
|
+
readonly shadow: ShadowTokens;
|
|
45
|
+
readonly spacing: SpacingTokens;
|
|
46
|
+
};
|
|
47
|
+
/** Erweiterung für App-eigene Token-Kategorien. Devs augmentieren:
|
|
48
|
+
*
|
|
49
|
+
* declare module "@cosmicdrift/kumiko-renderer" {
|
|
50
|
+
* interface AppTokens {
|
|
51
|
+
* chart: { gridline: string; line: string };
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
*
|
|
55
|
+
* Und reichen im App-CSS die passenden `--chart-*` Variablen rein.
|
|
56
|
+
* Kumikos Default-Primitives nutzen nur CoreTokens. */
|
|
57
|
+
export interface AppTokens {
|
|
58
|
+
}
|
|
59
|
+
export type Tokens = CoreTokens & AppTokens;
|
|
60
|
+
export type ThemeMode = "light" | "dark";
|
|
61
|
+
export type TokensApi = {
|
|
62
|
+
readonly tokens: Tokens;
|
|
63
|
+
readonly mode: ThemeMode;
|
|
64
|
+
readonly setMode: (mode: ThemeMode) => void;
|
|
65
|
+
readonly toggleMode: () => void;
|
|
66
|
+
};
|
|
67
|
+
export type TokensProviderProps = {
|
|
68
|
+
readonly children: ReactNode;
|
|
69
|
+
readonly value: TokensApi;
|
|
70
|
+
};
|
|
71
|
+
export declare function TokensProvider({ children, value }: TokensProviderProps): ReactNode;
|
|
72
|
+
/** Read-only Tokens-Hook. Liefert CSS-var-Strings — nutzbar in
|
|
73
|
+
* style-Props oder Tailwind-arbitrary-values wie
|
|
74
|
+
* `bg-[var(--color-primary)]` (selten, die shadcn-Tailwind-Klassen
|
|
75
|
+
* `bg-primary` sind idiomatischer). */
|
|
76
|
+
export declare function useTokens(): Tokens;
|
|
77
|
+
/** Volle API inkl. Theme-Toggle. Für den Dark/Light-Switch-Button. */
|
|
78
|
+
export declare function useTokenController(): TokensApi;
|
|
79
|
+
/** Tokens mit var-string-Werten. Konstant — die "Werte" sind
|
|
80
|
+
* Referenzen, die echten Farben ändern sich per CSS ohne dass das
|
|
81
|
+
* Objekt mutiert werden muss. Plattform-Packages (renderer-web,
|
|
82
|
+
* -native) importieren das in ihre TokensApi-Impl. */
|
|
83
|
+
export declare const cssVarTokens: Tokens;
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Design-Tokens im shadcn-Namensschema. Werte sind CSS-Variable-
|
|
3
|
+
// Referenzen (`var(--color-primary)`) — die echten Zahlen leben in
|
|
4
|
+
// styles.css (Web) bzw. in einer StyleSheet.create-Config (Native,
|
|
5
|
+
// später). Der Hook ist vor allem für Custom-Components die mal
|
|
6
|
+
// einen Token-Wert in eine JS-style-prop schieben müssen; die
|
|
7
|
+
// Default-Primitives nutzen direkt Tailwind-Klassen und brauchen
|
|
8
|
+
// ihn nicht.
|
|
9
|
+
//
|
|
10
|
+
// Theme-Toggle läuft über `.dark`-Class auf `<html>` — kein JS-State
|
|
11
|
+
// nötig, CSS rendert sofort neu. `useTokenController().toggleTheme()`
|
|
12
|
+
// ist nur ein DOM-Wrapper, kein eigener React-State.
|
|
13
|
+
//
|
|
14
|
+
// Erweiterbar: AppTokens-Interface wie bei Primitives. Dev kann
|
|
15
|
+
// eigene Token-Kategorien deklarieren und mit var-Strings befüllen.
|
|
16
|
+
import { createContext, useContext } from "react";
|
|
17
|
+
// ---- Context + Provider + Hooks ----
|
|
18
|
+
const TokensContext = createContext(undefined);
|
|
19
|
+
export function TokensProvider({ children, value }) {
|
|
20
|
+
return _jsx(TokensContext.Provider, { value: value, children: children });
|
|
21
|
+
}
|
|
22
|
+
/** Read-only Tokens-Hook. Liefert CSS-var-Strings — nutzbar in
|
|
23
|
+
* style-Props oder Tailwind-arbitrary-values wie
|
|
24
|
+
* `bg-[var(--color-primary)]` (selten, die shadcn-Tailwind-Klassen
|
|
25
|
+
* `bg-primary` sind idiomatischer). */
|
|
26
|
+
export function useTokens() {
|
|
27
|
+
return useTokenController().tokens;
|
|
28
|
+
}
|
|
29
|
+
/** Volle API inkl. Theme-Toggle. Für den Dark/Light-Switch-Button. */
|
|
30
|
+
export function useTokenController() {
|
|
31
|
+
const api = useContext(TokensContext);
|
|
32
|
+
if (api === undefined) {
|
|
33
|
+
throw new Error("useTokens/useTokenController: no <TokensProvider> mounted. createKumikoApp verdrahtet den Provider automatisch mit @cosmicdrift/kumiko-renderer-web defaults.");
|
|
34
|
+
}
|
|
35
|
+
return api;
|
|
36
|
+
}
|
|
37
|
+
/** Tokens mit var-string-Werten. Konstant — die "Werte" sind
|
|
38
|
+
* Referenzen, die echten Farben ändern sich per CSS ohne dass das
|
|
39
|
+
* Objekt mutiert werden muss. Plattform-Packages (renderer-web,
|
|
40
|
+
* -native) importieren das in ihre TokensApi-Impl. */
|
|
41
|
+
export const cssVarTokens = {
|
|
42
|
+
color: {
|
|
43
|
+
background: "var(--color-background)",
|
|
44
|
+
foreground: "var(--color-foreground)",
|
|
45
|
+
card: "var(--color-card)",
|
|
46
|
+
cardForeground: "var(--color-card-foreground)",
|
|
47
|
+
popover: "var(--color-popover)",
|
|
48
|
+
popoverForeground: "var(--color-popover-foreground)",
|
|
49
|
+
primary: "var(--color-primary)",
|
|
50
|
+
primaryForeground: "var(--color-primary-foreground)",
|
|
51
|
+
secondary: "var(--color-secondary)",
|
|
52
|
+
secondaryForeground: "var(--color-secondary-foreground)",
|
|
53
|
+
muted: "var(--color-muted)",
|
|
54
|
+
mutedForeground: "var(--color-muted-foreground)",
|
|
55
|
+
accent: "var(--color-accent)",
|
|
56
|
+
accentForeground: "var(--color-accent-foreground)",
|
|
57
|
+
destructive: "var(--color-destructive)",
|
|
58
|
+
destructiveForeground: "var(--color-destructive-foreground)",
|
|
59
|
+
border: "var(--color-border)",
|
|
60
|
+
input: "var(--color-input)",
|
|
61
|
+
ring: "var(--color-ring)",
|
|
62
|
+
},
|
|
63
|
+
radius: {
|
|
64
|
+
sm: "var(--radius-sm)",
|
|
65
|
+
md: "var(--radius-md)",
|
|
66
|
+
lg: "var(--radius-lg)",
|
|
67
|
+
xl: "var(--radius-xl)",
|
|
68
|
+
},
|
|
69
|
+
font: {
|
|
70
|
+
sans: "var(--font-sans)",
|
|
71
|
+
heading: "var(--font-heading)",
|
|
72
|
+
mono: "var(--font-mono)",
|
|
73
|
+
},
|
|
74
|
+
shadow: {
|
|
75
|
+
card: "var(--card-shadow)",
|
|
76
|
+
},
|
|
77
|
+
spacing: {
|
|
78
|
+
card: "var(--card-padding)",
|
|
79
|
+
},
|
|
80
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer",
|
|
3
|
-
"version": "0.328.
|
|
3
|
+
"version": "0.328.1",
|
|
4
4
|
"description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
-
"types": "./
|
|
14
|
-
"default": "./
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@cosmicdrift/kumiko-framework": "0.328.
|
|
19
|
-
"@cosmicdrift/kumiko-headless": "0.328.
|
|
20
|
-
"@cosmicdrift/kumiko-types": "0.328.
|
|
18
|
+
"@cosmicdrift/kumiko-framework": "0.328.1",
|
|
19
|
+
"@cosmicdrift/kumiko-headless": "0.328.1",
|
|
20
|
+
"@cosmicdrift/kumiko-types": "0.328.1",
|
|
21
21
|
"react": "^19.2.6",
|
|
22
22
|
"temporal-polyfill": "^0.3.2",
|
|
23
23
|
"zod": "^4.4.3"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@types/react-dom": "^19.2.3",
|
|
29
29
|
"jsdom": "^29.1.1",
|
|
30
30
|
"react-dom": "^19.2.6",
|
|
31
|
-
"@cosmicdrift/kumiko-locale-de": "0.328.
|
|
31
|
+
"@cosmicdrift/kumiko-locale-de": "0.328.1"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
@@ -41,10 +41,17 @@
|
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"registry": "https://registry.npmjs.org",
|
|
44
|
-
"access": "public"
|
|
44
|
+
"access": "public",
|
|
45
|
+
"exports": {
|
|
46
|
+
".": {
|
|
47
|
+
"types": "./dist/index.d.ts",
|
|
48
|
+
"default": "./dist/index.js"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
45
51
|
},
|
|
46
52
|
"files": [
|
|
47
|
-
"
|
|
53
|
+
"dist",
|
|
54
|
+
"src/changes.json",
|
|
48
55
|
"README.md",
|
|
49
56
|
"LICENSE"
|
|
50
57
|
]
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
AccessDeniedError,
|
|
4
|
-
ConflictError,
|
|
5
|
-
FeatureDisabledError,
|
|
6
|
-
InternalError,
|
|
7
|
-
NotFoundError,
|
|
8
|
-
RateLimitError,
|
|
9
|
-
UnconfiguredError,
|
|
10
|
-
UniqueViolationError,
|
|
11
|
-
UnprocessableError,
|
|
12
|
-
ValidationError,
|
|
13
|
-
VersionConflictError,
|
|
14
|
-
} from "@cosmicdrift/kumiko-framework/errors";
|
|
15
|
-
import { localeDeBundle } from "@cosmicdrift/kumiko-locale-de";
|
|
16
|
-
import { REQUIRED_FIELD_I18N_KEY } from "../app/form-schema";
|
|
17
|
-
import { kumikoDefaultTranslations } from "../i18n-defaults";
|
|
18
|
-
|
|
19
|
-
// Keys are read off LIVE error instances, not a hardcoded list — a copied list
|
|
20
|
-
// would mirror the bundle and never catch a renamed i18nKey or a new error
|
|
21
|
-
// class shipped without a default translation. Ship an 11th error class (or
|
|
22
|
-
// rename a key) without adding the default → this fails.
|
|
23
|
-
const errorInstances = [
|
|
24
|
-
new InternalError(),
|
|
25
|
-
new AccessDeniedError(),
|
|
26
|
-
new NotFoundError("Thing"),
|
|
27
|
-
new ConflictError(),
|
|
28
|
-
new VersionConflictError({ entityId: 1, expectedVersion: 1, currentVersion: 2 }),
|
|
29
|
-
new UniqueViolationError({ entityName: "Thing" }),
|
|
30
|
-
new UnprocessableError("reason"),
|
|
31
|
-
new UnconfiguredError({ feature: "f", key: "k" }),
|
|
32
|
-
new FeatureDisabledError("f", "h"),
|
|
33
|
-
new RateLimitError({
|
|
34
|
-
bucket: "b",
|
|
35
|
-
limit: 1,
|
|
36
|
-
windowSeconds: 1,
|
|
37
|
-
remaining: 0,
|
|
38
|
-
retryAfterSeconds: 1,
|
|
39
|
-
resetAt: "1970-01-01T00:00:00Z",
|
|
40
|
-
}),
|
|
41
|
-
new ValidationError({ fields: [] }),
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const de = localeDeBundle;
|
|
45
|
-
const en = kumikoDefaultTranslations["en"];
|
|
46
|
-
|
|
47
|
-
describe("kumikoDefaultTranslations covers every error i18nKey", () => {
|
|
48
|
-
for (const e of errorInstances) {
|
|
49
|
-
test(`${e.code} → ${e.i18nKey} has en default and de locale-package copy`, () => {
|
|
50
|
-
expect(de[e.i18nKey]).toBeTruthy();
|
|
51
|
-
expect(en?.[e.i18nKey]).toBeTruthy();
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Client-emitted (renderer-web download helper) — not thrown by a class, but
|
|
56
|
-
// rendered through the same last-resort bundle. Gap #5 named it explicitly.
|
|
57
|
-
test("errors.download.urlMissing has de+en default", () => {
|
|
58
|
-
expect(de?.["errors.download.urlMissing"]).toBeTruthy();
|
|
59
|
-
expect(en?.["errors.download.urlMissing"]).toBeTruthy();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Client-emitted (dispatcher-live error-mapping) — network/abort never
|
|
63
|
-
// reach the server, so no error class mints these; still rendered through
|
|
64
|
-
// this last-resort bundle whenever a feature reads res.error.i18nKey raw.
|
|
65
|
-
test("dispatcher.errors.network has de+en default", () => {
|
|
66
|
-
expect(de?.["dispatcher.errors.network"]).toBeTruthy();
|
|
67
|
-
expect(en?.["dispatcher.errors.network"]).toBeTruthy();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("dispatcher.errors.aborted has de+en default", () => {
|
|
71
|
-
expect(de?.["dispatcher.errors.aborted"]).toBeTruthy();
|
|
72
|
-
expect(en?.["dispatcher.errors.aborted"]).toBeTruthy();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Client-emitted (form-schema.ts required-field presence check) — not
|
|
76
|
-
// thrown by an error class, applied as a params.i18nKey override on a zod
|
|
77
|
-
// issue instead; still rendered through this last-resort bundle.
|
|
78
|
-
test("form-schema's required-field i18nKey has de+en default", () => {
|
|
79
|
-
expect(de[REQUIRED_FIELD_I18N_KEY]).toBeTruthy();
|
|
80
|
-
expect(en?.[REQUIRED_FIELD_I18N_KEY]).toBeTruthy();
|
|
81
|
-
});
|
|
82
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { formatWhen } from "../format-when";
|
|
3
|
-
|
|
4
|
-
describe("formatWhen", () => {
|
|
5
|
-
test("formats a parseable ISO timestamp", () => {
|
|
6
|
-
expect(formatWhen("2024-01-01T00:00:00.000Z")).not.toBe("2024-01-01T00:00:00.000Z");
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
test("falls back to the raw value on an unparseable input", () => {
|
|
10
|
-
expect(formatWhen("garbage")).toBe("garbage");
|
|
11
|
-
});
|
|
12
|
-
});
|