@cosmicdrift/kumiko-renderer 0.386.0 → 0.388.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/LICENSE +21 -57
- package/dist/app/action-form-body.d.ts +2 -2
- package/dist/app/action-form-body.js +12 -4
- package/dist/app/action-form-shim.d.ts +8 -8
- package/dist/app/action-form-shim.js +20 -22
- package/dist/app/action-form-support.d.ts +1 -0
- package/dist/app/action-form-support.js +1 -1
- package/dist/app/app-features-context.js +4 -4
- package/dist/app/column-renderers.d.ts +7 -9
- package/dist/app/column-renderers.js +15 -18
- package/dist/app/config-edit-body.js +7 -3
- package/dist/app/config-edit-shim.d.ts +7 -8
- package/dist/app/config-edit-shim.js +18 -20
- package/dist/app/custom-screens.d.ts +3 -3
- package/dist/app/custom-screens.js +8 -8
- package/dist/app/dashboard-body.d.ts +2 -2
- package/dist/app/dashboard-body.js +2 -2
- package/dist/app/entity-edit-prefill.d.ts +11 -0
- package/dist/app/entity-edit-prefill.js +18 -13
- package/dist/app/entity-edit-screen.js +4 -4
- package/dist/app/entity-list-screen.js +3 -3
- package/dist/app/extension-form-submit.d.ts +1 -1
- package/dist/app/extension-form-submit.js +14 -15
- package/dist/app/extension-sections.d.ts +29 -28
- package/dist/app/extension-sections.js +10 -10
- package/dist/app/feature-schema.js +11 -11
- package/dist/app/form-schema.js +2 -2
- package/dist/app/header-actions-bar.js +2 -2
- package/dist/app/kumiko-screen.js +8 -10
- package/dist/app/layout-fields.js +1 -1
- package/dist/app/list-facets.js +3 -3
- package/dist/app/nav.d.ts +10 -10
- package/dist/app/nav.js +13 -13
- package/dist/app/projection-detail-body.js +4 -4
- package/dist/app/projection-detail-shim.d.ts +6 -5
- package/dist/app/projection-detail-shim.js +23 -22
- package/dist/app/projection-list-body.js +10 -10
- package/dist/app/projection-list-shim.d.ts +5 -5
- package/dist/app/projection-list-shim.js +17 -18
- package/dist/app/qn.js +10 -12
- package/dist/app/qualify-screen-id.js +1 -1
- package/dist/app/screen-access.js +2 -2
- package/dist/app/screen-shared.js +1 -1
- package/dist/app/secret-mint-body.js +4 -4
- package/dist/app/write-failed-error.js +8 -7
- package/dist/components/edit-mounts.d.ts +2 -2
- package/dist/components/embedded-list-field.js +5 -5
- package/dist/components/grid-cell-for-field.d.ts +1 -1
- package/dist/components/reference-create-dialog.js +3 -3
- package/dist/components/related-list-section.d.ts +1 -1
- package/dist/components/related-list-section.js +15 -2
- package/dist/components/render-edit-action-button.d.ts +1 -3
- package/dist/components/render-edit-action-button.js +2 -2
- package/dist/components/render-edit-logic.js +1 -1
- package/dist/components/render-edit-types.d.ts +6 -6
- package/dist/components/render-edit.js +74 -73
- package/dist/components/render-field.d.ts +7 -7
- package/dist/components/render-field.js +62 -61
- package/dist/components/render-list.d.ts +42 -43
- package/dist/components/render-list.js +93 -84
- package/dist/components/use-wizard-form-draft.js +10 -10
- package/dist/context/dispatcher-context.js +5 -5
- package/dist/context/user-roles-context.js +2 -2
- package/dist/flow-diagram/render.js +9 -1
- package/dist/headless/apex/index.d.ts +1 -2
- package/dist/headless/apex/index.js +5 -6
- package/dist/headless/form/form-controller.js +14 -6
- package/dist/headless/form/types.d.ts +1 -0
- package/dist/headless/form/zod-bridge.js +2 -2
- package/dist/headless/format/index.js +89 -64
- package/dist/headless/format/money.js +1 -1
- package/dist/headless/index.js +2 -2
- package/dist/headless/view-model/edit.js +4 -2
- package/dist/headless/view-model/list.js +184 -150
- package/dist/headless/view-model/types.d.ts +6 -3
- package/dist/hooks/live-refetch-scheduler.js +4 -0
- package/dist/hooks/reference-limits.js +11 -12
- package/dist/hooks/use-list-url-state.d.ts +13 -13
- package/dist/hooks/use-list-url-state.js +21 -22
- package/dist/hooks/use-query.js +3 -3
- package/dist/hooks/use-reference-lookup.d.ts +9 -1
- package/dist/hooks/use-reference-lookup.js +32 -19
- package/dist/hooks/use-store.js +18 -22
- package/dist/hooks/use-stream-handler.js +4 -2
- package/dist/i18n-defaults.js +6 -8
- package/dist/i18n.d.ts +10 -10
- package/dist/i18n.js +25 -25
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -4
- package/dist/live/dispatcher-live.js +2 -2
- package/dist/primitives.d.ts +244 -221
- package/dist/primitives.js +1 -1
- package/dist/sse/live-events.d.ts +5 -5
- package/dist/sse/live-events.js +17 -17
- package/dist/tokens.d.ts +8 -8
- package/dist/tokens.js +16 -17
- package/dist/web/app/browser-locale.d.ts +9 -9
- package/dist/web/app/browser-locale.js +19 -19
- package/dist/web/app/client-plugin.d.ts +44 -52
- package/dist/web/app/client-plugin.js +4 -5
- package/dist/web/app/create-app.d.ts +28 -31
- package/dist/web/app/create-app.js +29 -25
- package/dist/web/app/dashboard-body.js +17 -1
- package/dist/web/app/dashboard-panels.js +12 -2
- package/dist/web/app/document-lang-sync.js +1 -1
- package/dist/web/app/draft-storage.js +1 -1
- package/dist/web/app/nav-providers-context.d.ts +3 -3
- package/dist/web/app/nav-providers-context.js +3 -3
- package/dist/web/app/nav.d.ts +18 -17
- package/dist/web/app/nav.js +66 -64
- package/dist/web/app/rich-content-editor.js +1 -1
- package/dist/web/components/config-cascade.js +17 -18
- package/dist/web/components/config-source-badge.js +4 -4
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +1 -1
- package/dist/web/layout/app-layout.d.ts +9 -9
- package/dist/web/layout/app-layout.js +2 -2
- package/dist/web/layout/avatar.d.ts +4 -3
- package/dist/web/layout/avatar.js +15 -17
- package/dist/web/layout/default-app-shell.d.ts +22 -23
- package/dist/web/layout/editor-panel.js +3 -3
- package/dist/web/layout/nav-tree.js +86 -84
- package/dist/web/layout/profile-menu.d.ts +1 -1
- package/dist/web/layout/shell-header.js +2 -1
- package/dist/web/layout/sidebar-brand.d.ts +7 -7
- package/dist/web/layout/sidebar-user.d.ts +1 -1
- package/dist/web/layout/sidebar-user.js +4 -4
- package/dist/web/layout/sidebar.d.ts +8 -8
- package/dist/web/layout/sidebar.js +7 -7
- package/dist/web/layout/target-resolver-stub.d.ts +5 -5
- package/dist/web/layout/target-resolver-stub.js +20 -20
- package/dist/web/layout/target-url.d.ts +7 -7
- package/dist/web/layout/target-url.js +22 -22
- package/dist/web/layout/theme-toggle.js +4 -5
- package/dist/web/layout/uniform-bar-controls.d.ts +1 -0
- package/dist/web/layout/uniform-bar-controls.js +4 -0
- package/dist/web/layout/workspace-shell.d.ts +21 -21
- package/dist/web/layout/workspace-shell.js +29 -30
- package/dist/web/lib/cn.d.ts +4 -4
- package/dist/web/lib/cn.js +4 -4
- package/dist/web/lib/file-ref-download.js +4 -1
- package/dist/web/primitives/action-menu.d.ts +8 -8
- package/dist/web/primitives/action-menu.js +14 -13
- package/dist/web/primitives/calendar-popover.d.ts +1 -1
- package/dist/web/primitives/calendar-popover.js +10 -10
- package/dist/web/primitives/card-styles.js +1 -1
- package/dist/web/primitives/card.js +2 -2
- package/dist/web/primitives/code-input.d.ts +6 -0
- package/dist/web/primitives/code-input.js +31 -0
- package/dist/web/primitives/combobox.d.ts +12 -12
- package/dist/web/primitives/combobox.js +34 -35
- package/dist/web/primitives/data-table-cell.js +2 -2
- package/dist/web/primitives/data-table.js +6 -6
- package/dist/web/primitives/date-field.js +2 -2
- package/dist/web/primitives/date-input.js +4 -4
- package/dist/web/primitives/default-form.js +2 -2
- package/dist/web/primitives/dropdown-menu.js +14 -15
- package/dist/web/primitives/embedded-list-input.js +3 -3
- package/dist/web/primitives/facet-filter.js +2 -2
- package/dist/web/primitives/field.js +9 -8
- package/dist/web/primitives/file-thumbnail.d.ts +3 -0
- package/dist/web/primitives/file-thumbnail.js +5 -0
- package/dist/web/primitives/form.d.ts +1 -1
- package/dist/web/primitives/form.js +6 -6
- package/dist/web/primitives/input.js +8 -3
- package/dist/web/primitives/layout-elements.js +7 -5
- package/dist/web/primitives/layout.js +2 -2
- package/dist/web/primitives/located-timestamp-input.js +4 -4
- package/dist/web/primitives/money-input.js +13 -17
- package/dist/web/primitives/page-header.js +3 -1
- package/dist/web/primitives/pager.js +1 -1
- package/dist/web/primitives/row-actions.js +6 -7
- package/dist/web/primitives/secret-reveal.js +1 -1
- package/dist/web/primitives/timestamp-input.d.ts +9 -9
- package/dist/web/primitives/timestamp-input.js +21 -21
- package/dist/web/primitives/toast.js +12 -13
- package/dist/web/primitives/use-focus-on-mount.d.ts +2 -0
- package/dist/web/primitives/use-focus-on-mount.js +9 -0
- package/dist/web/sse/live-events.d.ts +6 -6
- package/dist/web/sse/live-events.js +3 -3
- package/dist/web/tokens.d.ts +11 -12
- package/dist/web/tokens.js +35 -37
- package/dist/web/version/update-checker.js +14 -13
- package/dist/web/widgets/ai-text-field.js +1 -1
- package/dist/web/widgets/bounded-load-cache.d.ts +1 -1
- package/dist/web/widgets/bounded-load-cache.js +10 -4
- package/dist/web/widgets/charts.d.ts +10 -10
- package/dist/web/widgets/charts.js +8 -8
- package/dist/web/widgets/choice-cards.d.ts +17 -0
- package/dist/web/widgets/choice-cards.js +12 -0
- package/dist/web/widgets/collapsible-section.d.ts +3 -3
- package/dist/web/widgets/collapsible-section.js +7 -7
- package/dist/web/widgets/detail-list.d.ts +5 -3
- package/dist/web/widgets/detail-list.js +5 -3
- package/dist/web/widgets/feed-list.d.ts +2 -2
- package/dist/web/widgets/feed-list.js +2 -2
- package/dist/web/widgets/form-fields.d.ts +14 -14
- package/dist/web/widgets/form-fields.js +14 -13
- package/dist/web/widgets/index.d.ts +1 -0
- package/dist/web/widgets/index.js +5 -4
- package/dist/web/widgets/infinity-list.js +3 -3
- package/dist/web/widgets/mode-switch.d.ts +2 -2
- package/dist/web/widgets/mode-switch.js +2 -2
- package/dist/web/widgets/pdf-preview.js +1 -1
- package/dist/web/widgets/plan-card.d.ts +2 -0
- package/dist/web/widgets/plan-card.js +1 -1
- package/dist/web/widgets/progress-list.d.ts +1 -2
- package/dist/web/widgets/progress-list.js +1 -2
- package/dist/web/widgets/query-table.d.ts +6 -6
- package/dist/web/widgets/result-panel.d.ts +16 -16
- package/dist/web/widgets/result-panel.js +10 -10
- package/dist/web/widgets/section-card.d.ts +3 -3
- package/dist/web/widgets/section-card.js +3 -3
- package/dist/web/widgets/stat.d.ts +4 -4
- package/dist/web/widgets/stat.js +6 -6
- package/dist/web/widgets/states.d.ts +4 -4
- package/dist/web/widgets/states.js +4 -4
- package/dist/web/widgets/upload-zone.js +13 -5
- package/dist/web/widgets/use-draft.d.ts +7 -7
- package/dist/web/widgets/use-draft.js +7 -7
- package/package.json +6 -6
- package/src/changes.json +49 -0
|
@@ -12,9 +12,9 @@ const SOURCE_I18N_KEY = {
|
|
|
12
12
|
default: "kumiko.config.source.default",
|
|
13
13
|
missing: "kumiko.config.source.missing",
|
|
14
14
|
};
|
|
15
|
-
// Fallback
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// Fallback order of the cascade, with the most specific source first.
|
|
16
|
+
// Comparing indices with the screen-scope source determines which
|
|
17
|
+
// levels a non-operator may see.
|
|
18
18
|
const SOURCE_ORDER = [
|
|
19
19
|
"user-row",
|
|
20
20
|
"tenant-row",
|
|
@@ -51,16 +51,16 @@ function scopeToSource(scope) {
|
|
|
51
51
|
return "system-row";
|
|
52
52
|
}
|
|
53
53
|
function toDisplayLevels(levels, screenScopeSource) {
|
|
54
|
-
// System
|
|
55
|
-
// app-override/computed/default
|
|
54
|
+
// System screens have operator visibility, so the full cascade, including
|
|
55
|
+
// app-override/computed/default, remains visible.
|
|
56
56
|
if (screenScopeSource === "system-row") {
|
|
57
57
|
return levels.map((level) => ({ level, badgeSource: level.source }));
|
|
58
58
|
}
|
|
59
59
|
const scopeIdx = SOURCE_ORDER.indexOf(screenScopeSource);
|
|
60
60
|
const own = levels.filter((l) => SOURCE_ORDER.indexOf(l.source) <= scopeIdx);
|
|
61
61
|
const higher = levels.filter((l) => SOURCE_ORDER.indexOf(l.source) > scopeIdx);
|
|
62
|
-
//
|
|
63
|
-
//
|
|
62
|
+
// Exactly one fallback row: the active higher level (whose value the user
|
|
63
|
+
// effectively receives), or the declared default/missing level.
|
|
64
64
|
const fallback = higher.find((l) => l.isActive) ??
|
|
65
65
|
higher.find((l) => l.source === "default" || l.source === "missing");
|
|
66
66
|
const ownRows = own.map((level) => ({ level, badgeSource: level.source }));
|
|
@@ -71,12 +71,11 @@ function toDisplayLevels(levels, screenScopeSource) {
|
|
|
71
71
|
{
|
|
72
72
|
level: fallback,
|
|
73
73
|
badgeSource: "default",
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
// erscheinen sie hier neutral als "Standard".
|
|
74
|
+
// Use one consistent term, "Standard" (DE) / "Default" (EN)—the same
|
|
75
|
+
// key as the field-label badge (kumiko.config.source.default), so the
|
|
76
|
+
// badge and cascade disclosure do not show two different words. The
|
|
77
|
+
// screen scope cannot set or reset the operator levels (System/Override/
|
|
78
|
+
// Computed), so they appear here neutrally as "Standard".
|
|
80
79
|
badgeLabelKey: "kumiko.config.source.default",
|
|
81
80
|
},
|
|
82
81
|
];
|
|
@@ -106,11 +105,11 @@ export function ConfigCascadeView({ cascade, screenScope, onReset, qualifiedKey,
|
|
|
106
105
|
const displayLevels = toDisplayLevels(cascade.levels, screenScopeSource);
|
|
107
106
|
const activeDisplay = displayLevels.find((d) => d.level.isActive);
|
|
108
107
|
const hasOverride = activeDisplay?.level.source === screenScopeSource;
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
// (
|
|
112
|
-
//
|
|
113
|
-
//
|
|
108
|
+
// Expandable only when the panel provides meaningful additional information:
|
|
109
|
+
// an own override (→ Reset) or more than one level with a value. Empty levels
|
|
110
|
+
// (e.g. the unset tenant-row of a field using only its default) do not count;
|
|
111
|
+
// otherwise a field showing only its default would incorrectly be expandable,
|
|
112
|
+
// making the panel merely repeat the trigger.
|
|
114
113
|
const valuedLevels = displayLevels.filter((d) => d.level.hasValue);
|
|
115
114
|
const expandable = hasOverride || valuedLevels.length > 1;
|
|
116
115
|
const isUnset = activeDisplay === undefined || !activeDisplay.level.hasValue;
|
|
@@ -40,10 +40,10 @@ function scopeToSource(scope) {
|
|
|
40
40
|
}
|
|
41
41
|
export function ConfigSourceBadge({ source, screenScope, }) {
|
|
42
42
|
const t = useTranslation();
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
43
|
+
// Uses the same collapsing rule as toDisplayLevels (config-cascade.tsx):
|
|
44
|
+
// for non-operator screens, operator sources above the screen scope appear
|
|
45
|
+
// as a neutral "Vorgabe" badge so the badge does not reveal the system source
|
|
46
|
+
// intentionally hidden by the cascade view.
|
|
47
47
|
let effective = source;
|
|
48
48
|
if (screenScope !== undefined && screenScope !== "system") {
|
|
49
49
|
const scopeIdx = SOURCE_ORDER.indexOf(scopeToSource(screenScope));
|
package/dist/web/index.d.ts
CHANGED
|
@@ -75,4 +75,4 @@ export { SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from
|
|
|
75
75
|
export type { KumikoBuild } from "./version/update-checker.tsx";
|
|
76
76
|
export { readLoadedBuild } from "./version/update-checker.tsx";
|
|
77
77
|
export type { AiTextAreaProps, AiTextFieldProps, BooleanFieldProps, ComparisonMetric, DateFieldProps, DrawerProps, FeedRow, FileFieldProps, FloatingPanelGeometry, FloatingPanelProps, InfinityListProps, InfinityListSelection, ModeSwitchVariant, NumberFieldProps, PdfPreviewSource, PhotoSlotSpec, PhotoSlotsProps, PlanCardActionSlot, PlanCardLinkSlot, PlanCardPrice, PlanCardProps, PlanGridProps, ProgressListRow, PublicShellProps, PublicShellVariant, QueryTableColumn, QueryTableProps, RangeFieldProps, ResultColumn, SelectFieldProps, SideBySideTableCell, SideBySideTableColumn, SideBySideTableRow, StatDelta, StatTone, StatusBadgeTone, StatusBarEntry, StatusTone, TextareaFieldProps, TextFieldProps, TimeseriesHeight, TimeseriesPoint, TimeseriesReferenceLine, TimeseriesXAxis, TimeseriesYAxis, UploadZoneProps, } from "./widgets/index.ts";
|
|
78
|
-
export { AiTextArea, AiTextField, BooleanField, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PdfPreview, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.ts";
|
|
78
|
+
export { AiTextArea, AiTextField, BooleanField, ChoiceCards, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PdfPreview, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.ts";
|
package/dist/web/index.js
CHANGED
|
@@ -50,4 +50,4 @@ export { applyTokensToCssVars, defaultTokens, lightTokens, useBrowserTokensApi,
|
|
|
50
50
|
export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "./ui/resizable.js";
|
|
51
51
|
export { SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "./ui/sidebar.js";
|
|
52
52
|
export { readLoadedBuild } from "./version/update-checker.js";
|
|
53
|
-
export { AiTextArea, AiTextField, BooleanField, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PdfPreview, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.js";
|
|
53
|
+
export { AiTextArea, AiTextField, BooleanField, ChoiceCards, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PdfPreview, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.js";
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
export type AppLayoutProps = {
|
|
3
|
-
/** Optional.
|
|
3
|
+
/** Optional. Exists only above the main area, not above the sidebar. */
|
|
4
4
|
readonly topbar?: ReactNode;
|
|
5
5
|
readonly sidebar?: ReactNode;
|
|
6
6
|
readonly children: ReactNode;
|
|
7
7
|
readonly testId?: string;
|
|
8
|
-
/** Viewport-fit
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `min-h-screen
|
|
12
|
-
*
|
|
13
|
-
*
|
|
8
|
+
/** Viewport-fit shell. Default `true` → root = `h-screen` (fixed
|
|
9
|
+
* viewport height); sidebar/topbar remain fixed while the main area
|
|
10
|
+
* scrolls INSIDE (`min-h-0` + `overflow-auto`). `false` → classic
|
|
11
|
+
* `min-h-screen` flow where the whole page scrolls—an escape hatch for
|
|
12
|
+
* a public, long content page that needs real body scrolling. Never
|
|
13
|
+
* clips—content scrolls in `main` instead of the body. */
|
|
14
14
|
readonly fill?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
15
|
+
/** Optional classes appended to the root (for a custom background, etc.).
|
|
16
|
+
* Extends the defaults rather than replacing them (`cn` merge). */
|
|
17
17
|
readonly className?: string;
|
|
18
18
|
/** Optionaler Klassen-Append an `<main>`. */
|
|
19
19
|
readonly mainClassName?: string;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
export function AppLayout({ topbar, sidebar, children, testId, fill = true, className, mainClassName, }) {
|
|
4
4
|
return (_jsxs("div", { "data-testid": testId, "data-kumiko-layout": "app", ...(fill === true && { "data-kumiko-fill": "true" }), className: cn(
|
|
5
|
-
// new-york inset
|
|
6
|
-
//
|
|
5
|
+
// new-york inset frame: muted rail background; the sidebar sits
|
|
6
|
+
// transparently on it, while the main area floats as its own panel.
|
|
7
7
|
"flex flex-row bg-muted/40 text-foreground", fill === true ? "h-screen" : "min-h-screen", className), children: [sidebar, _jsxs("div", { className: cn("flex flex-1 min-w-0 flex-col overflow-hidden rounded-xl border bg-background shadow-sm m-2 md:ml-0", fill === true && "min-h-0"), children: [topbar, _jsx("main", { className: cn("flex-1 overflow-auto", fill === true && "min-h-0", mainClassName), children: children })] })] }));
|
|
8
8
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
export type AvatarSize = "sm" | "md" | "lg";
|
|
3
3
|
export type AvatarProps = {
|
|
4
|
-
/** Stable
|
|
5
|
-
* user.id
|
|
4
|
+
/** Stable identifier—the source for the background-color hash. Usually
|
|
5
|
+
* `user.id`; for avatars based only on a label, the label string can also
|
|
6
|
+
* be used. */
|
|
6
7
|
readonly id: string;
|
|
7
|
-
/**
|
|
8
|
+
/** Full name or email—the initials are extracted from this value. */
|
|
8
9
|
readonly label: string;
|
|
9
10
|
readonly size?: AvatarSize;
|
|
10
11
|
readonly testId?: string;
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// Avatar
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// bunte Sidebar.
|
|
2
|
+
// Avatar pill with initials. The color is based on a string hash so the same
|
|
3
|
+
// user always gets the same color (linear pattern). Eight hue targets provide
|
|
4
|
+
// good distinction without making the sidebar overly colorful.
|
|
6
5
|
//
|
|
7
|
-
//
|
|
8
|
-
// `id`
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// Usage: `<Avatar id="user-123" label="Daniel Hennig" size="md" />`.
|
|
7
|
+
// `id` is the color's hash source; `label` is used for initials and the
|
|
8
|
+
// aria-label. There is no image slot yet; one follows once apps provide real
|
|
9
|
+
// avatar URLs.
|
|
11
10
|
import { useMemo } from "react";
|
|
12
11
|
import { cn } from "../lib/cn.js";
|
|
13
|
-
// Tailwind
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// (Avatar-Farbe sollte deterministic sein, nicht theme-abhängig).
|
|
12
|
+
// Tailwind classes for each hue. Background lightness is moderate (550–600)
|
|
13
|
+
// for saturation, while foreground lightness is high (50–100) for contrast.
|
|
14
|
+
// Fixed colors keep avatar colors deterministic and independent of the theme,
|
|
15
|
+
// even though the tokens work in both modes through CSS variables.
|
|
18
16
|
const COLOR_CLASSES = [
|
|
19
17
|
"bg-rose-600 text-rose-50",
|
|
20
18
|
"bg-orange-600 text-orange-50",
|
|
@@ -31,8 +29,8 @@ const SIZE_CLASSES = {
|
|
|
31
29
|
lg: "size-8 text-xs",
|
|
32
30
|
};
|
|
33
31
|
function hashCode(str) {
|
|
34
|
-
// djb2
|
|
35
|
-
//
|
|
32
|
+
// A djb2 variant: fast and sufficiently well distributed for 8 buckets.
|
|
33
|
+
// A cryptographic hash would be overkill for color bucketing.
|
|
36
34
|
let hash = 5381;
|
|
37
35
|
for (let i = 0; i < str.length; i++) {
|
|
38
36
|
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;
|
|
@@ -44,8 +42,8 @@ function pickColor(id) {
|
|
|
44
42
|
return COLOR_CLASSES[idx] ?? COLOR_CLASSES[0] ?? "bg-muted";
|
|
45
43
|
}
|
|
46
44
|
function extractInitials(label) {
|
|
47
|
-
// "Daniel Hennig" → "DH". "alice@example.com" → "AL".
|
|
48
|
-
//
|
|
45
|
+
// "Daniel Hennig" → "DH". "alice@example.com" → "AL". For a single word,
|
|
46
|
+
// it falls back to the first 2 letters ("Daniel" → "DA"). Everything is
|
|
49
47
|
// upper-case.
|
|
50
48
|
const trimmed = label.trim();
|
|
51
49
|
if (trimmed.length === 0)
|
|
@@ -5,37 +5,36 @@ export type DefaultAppShellUser = {
|
|
|
5
5
|
readonly roles: readonly string[];
|
|
6
6
|
};
|
|
7
7
|
export type DefaultAppShellProps = {
|
|
8
|
-
/** Header
|
|
9
|
-
*
|
|
8
|
+
/** Header slot at the top of the sidebar — workspace identity (logo, name,
|
|
9
|
+
* plan tag). The caller provides the content. */
|
|
10
10
|
readonly brand: ReactNode;
|
|
11
|
-
/** Schema (AppSchema
|
|
12
|
-
*
|
|
13
|
-
* schema.navs (per-
|
|
11
|
+
/** Schema (AppSchema or legacy FeatureSchema) passed through to NavTree;
|
|
12
|
+
* sidebar entries are generated automatically from
|
|
13
|
+
* schema.navs (per-feature). */
|
|
14
14
|
readonly schema: AppSchema | FeatureSchema;
|
|
15
|
-
/** Current user — drives
|
|
16
|
-
* role-gated
|
|
17
|
-
*
|
|
18
|
-
* anonymous). */
|
|
15
|
+
/** Current user — drives navigation role gating. Without a user prop,
|
|
16
|
+
* role-gated navigation entries (`access: { roles: [...] }`) are hidden
|
|
17
|
+
* completely (resolveNavigation treats an undefined user as anonymous). */
|
|
19
18
|
readonly user?: DefaultAppShellUser;
|
|
20
|
-
/** Icon
|
|
21
|
-
* ThemeToggle, TenantSwitcher. */
|
|
19
|
+
/** Icon row between the brand and NavTree — typically a Search trigger,
|
|
20
|
+
* ThemeToggle, or TenantSwitcher. */
|
|
22
21
|
readonly sidebarActions?: ReactNode;
|
|
23
|
-
/** Runtime
|
|
24
|
-
*
|
|
25
|
-
* (
|
|
22
|
+
/** Runtime badges per navigation item (bare nav-id → ReactNode), passed
|
|
23
|
+
* through to NavTree. For tier/status badges supplied by the app per user
|
|
24
|
+
* (value + color), rather than embedded in the static schema. */
|
|
26
25
|
readonly navBadges?: ReadonlyMap<string, ReactNode>;
|
|
27
|
-
/**
|
|
28
|
-
* ThemeToggle,
|
|
29
|
-
*
|
|
26
|
+
/** Right-aligned slot in the topbar (next to the breadcrumb) — for
|
|
27
|
+
* ThemeToggle, global actions, and similar controls. Avoids a separate
|
|
28
|
+
* sidebarActions row in the sidebar. */
|
|
30
29
|
readonly headerActions?: ReactNode;
|
|
31
|
-
/** Footer
|
|
32
|
-
*
|
|
30
|
+
/** Footer slot at the bottom of the sidebar — profile row, help link,
|
|
31
|
+
* or plan banner. */
|
|
33
32
|
readonly sidebarFooter?: ReactNode;
|
|
34
|
-
/** Viewport-fit
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
/** Viewport-fit shell. true → fixed viewport height (`h-svh`); content
|
|
34
|
+
* scrolls inside instead of the whole page. Defaults to true — `fill={false}`
|
|
35
|
+
* switches back to page scrolling. */
|
|
37
36
|
readonly fill?: boolean;
|
|
38
|
-
/** Screen
|
|
37
|
+
/** Screen content rendered inside SidebarInset. */
|
|
39
38
|
readonly children: ReactNode;
|
|
40
39
|
};
|
|
41
40
|
export declare function DefaultAppShell({ brand, schema, user, sidebarActions, headerActions, navBadges, sidebarFooter, fill, children, }: DefaultAppShellProps): ReactNode;
|
|
@@ -15,9 +15,9 @@ function EditorPanelInner({ target, resolvers, onClose, }) {
|
|
|
15
15
|
}
|
|
16
16
|
export function EditorPanel({ resolvers }) {
|
|
17
17
|
const nav = useNav();
|
|
18
|
-
// target derived from URL
|
|
19
|
-
// useMemo
|
|
20
|
-
//
|
|
18
|
+
// target is derived from the URL, so F5 and Back restore the state.
|
|
19
|
+
// useMemo keeps the reference stable while searchParams are shallow-equal
|
|
20
|
+
// (the nav implementation provides a plain record for this check).
|
|
21
21
|
const target = useMemo(() => parseTargetFromSearchParams(nav.searchParams), [nav.searchParams]);
|
|
22
22
|
const handleClose = useCallback(() => {
|
|
23
23
|
requestLeave(() => nav.setSearchParams(clearTargetSearchParams(nav.searchParams)));
|