@rebasepro/admin 0.13.0 → 0.13.1-canary.g394d868
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/{CollectionEditorDialog-CjXkWZ64.js → CollectionEditorDialog-D78xsXgL.js} +3 -3
- package/dist/{CollectionEditorDialog-CjXkWZ64.js.map → CollectionEditorDialog-D78xsXgL.js.map} +1 -1
- package/dist/{PropertyEditView-W8I3YV89.js → PropertyEditView-B88EC-1f.js} +2 -2
- package/dist/{PropertyEditView-W8I3YV89.js.map → PropertyEditView-B88EC-1f.js.map} +1 -1
- package/dist/{RouterCollectionsStudioView-BsLTNoqX.js → RouterCollectionsStudioView-B1Ws7h9l.js} +4 -4
- package/dist/{RouterCollectionsStudioView-BsLTNoqX.js.map → RouterCollectionsStudioView-B1Ws7h9l.js.map} +1 -1
- package/dist/collection_editor/serializable_types.d.ts +1 -0
- package/dist/collection_editor_ui.js +4 -4
- package/dist/components/AdditionalFieldValue.d.ts +25 -0
- package/dist/components/CollectionViewBinding/CollectionViewBinding.d.ts +16 -0
- package/dist/components/CollectionViewBinding/SlotValue.d.ts +63 -0
- package/dist/components/CollectionViewBinding/SplitListCloseButton.d.ts +17 -4
- package/dist/components/CollectionViewBinding/SplitListShowButton.d.ts +12 -0
- package/dist/components/CollectionViewBinding/usePreviewSlots.d.ts +55 -5
- package/dist/components/DetailViewBinding.d.ts +15 -0
- package/dist/components/DrawerNavigationGroup.d.ts +9 -6
- package/dist/components/DrawerNavigationItem.d.ts +16 -6
- package/dist/components/EditViewBinding.d.ts +30 -1
- package/dist/components/EntityDisplayHeader.d.ts +53 -0
- package/dist/components/EntityIdentityBar.d.ts +43 -1
- package/dist/components/EntityViewBinding.d.ts +60 -6
- package/dist/components/RebaseLayout.d.ts +1 -1
- package/dist/components/RebaseShell.d.ts +1 -1
- package/dist/components/RelationSelector.d.ts +8 -1
- package/dist/components/UserSelector.d.ts +8 -1
- package/dist/components/app/Scaffold.d.ts +9 -3
- package/dist/components/index.d.ts +2 -0
- package/dist/{export-J79rMoNj.js → export-BZhdWhkB.js} +2 -2
- package/dist/{export-J79rMoNj.js.map → export-BZhdWhkB.js.map} +1 -1
- package/dist/form/components/FieldBlock.d.ts +58 -4
- package/dist/form/components/FormRail.d.ts +13 -0
- package/dist/form/components/FormSections.d.ts +15 -1
- package/dist/form/components/useRailVisible.d.ts +5 -4
- package/dist/form/form_utils.d.ts +38 -1
- package/dist/{history-D7L_JlLO.js → history-BPpt68CL.js} +4 -4
- package/dist/{history-D7L_JlLO.js.map → history-BPpt68CL.js.map} +1 -1
- package/dist/hooks/useEntityDisplay.d.ts +102 -0
- package/dist/hooks/useEntityDisplayTitle.d.ts +18 -9
- package/dist/{import-BvYl--U4.js → import-gRfemegK.js} +3 -3
- package/dist/{import-BvYl--U4.js.map → import-gRfemegK.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +152 -57
- package/dist/index.js.map +1 -1
- package/dist/preview/compact_text.d.ts +23 -0
- package/dist/preview/components/BooleanPreview.d.ts +3 -1
- package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayOneOfPreview.d.ts +1 -1
- package/dist/preview/property_previews/ArrayPropertyPreview.d.ts +1 -1
- package/dist/preview/property_previews/MapPropertyPreview.d.ts +1 -1
- package/dist/preview/property_previews/StringPropertyPreview.d.ts +1 -1
- package/dist/routes/RebaseRoute.d.ts +1 -1
- package/dist/types/components/PropertyPreviewProps.d.ts +19 -0
- package/dist/util/number_format.d.ts +14 -0
- package/dist/util/previews.d.ts +9 -2
- package/dist/{util-GiwPgxnL.js → util-BHq3VOjH.js} +9080 -7861
- package/dist/util-BHq3VOjH.js.map +1 -0
- package/package.json +9 -9
- package/src/collection_editor/serializable_types.ts +1 -0
- package/src/components/AdditionalFieldValue.tsx +68 -0
- package/src/components/CollectionTableBinding/CollectionTableBinding.tsx +7 -8
- package/src/components/CollectionTableBinding/PropertyTableCell.tsx +2 -2
- package/src/components/CollectionTableBinding/column_utils.tsx +15 -6
- package/src/components/CollectionTableBinding/internal/popup_field/PopupFormField.tsx +2 -2
- package/src/components/CollectionViewBinding/BoardCardBinding.tsx +26 -27
- package/src/components/CollectionViewBinding/CollectionListViewBinding.tsx +172 -112
- package/src/components/CollectionViewBinding/CollectionViewActions.tsx +1 -1
- package/src/components/CollectionViewBinding/CollectionViewBinding.tsx +38 -8
- package/src/components/CollectionViewBinding/EntityCardBinding.tsx +23 -36
- package/src/components/CollectionViewBinding/SlotValue.tsx +156 -0
- package/src/components/CollectionViewBinding/SplitListCloseButton.tsx +23 -7
- package/src/components/CollectionViewBinding/SplitListShowButton.tsx +28 -0
- package/src/components/CollectionViewBinding/SplitListView.tsx +33 -2
- package/src/components/CollectionViewBinding/useBoardDataController.tsx +12 -3
- package/src/components/CollectionViewBinding/usePreviewSlots.ts +177 -54
- package/src/components/DefaultDrawer.tsx +19 -23
- package/src/components/DetailViewBinding.tsx +87 -55
- package/src/components/DrawerNavigationGroup.tsx +16 -39
- package/src/components/DrawerNavigationItem.tsx +44 -16
- package/src/components/EditViewBinding.tsx +211 -41
- package/src/components/EntityDisplayHeader.tsx +170 -0
- package/src/components/EntityIdentityBar.tsx +149 -23
- package/src/components/EntityPreviewBinding.tsx +58 -18
- package/src/components/EntityViewBinding.tsx +342 -41
- package/src/components/InlineEntityPreview.tsx +10 -10
- package/src/components/RebaseLayout.tsx +2 -2
- package/src/components/RebaseShell.tsx +2 -2
- package/src/components/ReferenceTable/SelectionTableBinding.tsx +4 -2
- package/src/components/RelationSelector.tsx +15 -4
- package/src/components/SideDialogs.tsx +15 -3
- package/src/components/SidePanelBinding.tsx +122 -66
- package/src/components/UserSelector.tsx +15 -4
- package/src/components/app/Scaffold.tsx +112 -10
- package/src/components/index.ts +3 -0
- package/src/form/EntityForm.tsx +64 -52
- package/src/form/EntityFormBinding.tsx +24 -11
- package/src/form/PropertyFieldBinding.tsx +2 -2
- package/src/form/components/FieldBlock.tsx +80 -10
- package/src/form/components/FormRail.tsx +19 -2
- package/src/form/components/FormSections.tsx +32 -5
- package/src/form/components/StorageUploadProgress.tsx +9 -3
- package/src/form/components/useRailVisible.tsx +5 -4
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +2 -2
- package/src/form/field_bindings/BinaryFieldBinding.tsx +10 -5
- package/src/form/field_bindings/BlockFieldBinding.tsx +3 -3
- package/src/form/field_bindings/GeopointFieldBinding.tsx +23 -16
- package/src/form/field_bindings/MapFieldBinding.tsx +2 -2
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +13 -7
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +7 -1
- package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +7 -1
- package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
- package/src/form/field_bindings/RelationFieldBinding.tsx +5 -2
- package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -3
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +2 -2
- package/src/form/field_bindings/UserSelectFieldBinding.tsx +4 -1
- package/src/form/field_bindings/VectorFieldBinding.tsx +6 -4
- package/src/form/form_utils.ts +78 -0
- package/src/hooks/navigation/useBuildCollectionRegistryController.tsx +29 -5
- package/src/hooks/useEntityDisplay.tsx +262 -0
- package/src/hooks/useEntityDisplayTitle.tsx +27 -38
- package/src/index.ts +9 -1
- package/src/preview/PropertyPreview.tsx +25 -5
- package/src/preview/compact_text.ts +68 -0
- package/src/preview/components/BooleanPreview.tsx +5 -2
- package/src/preview/components/StorageThumbnail.tsx +5 -2
- package/src/preview/property_previews/ArrayOfRelationsPreview.tsx +6 -3
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +26 -1
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +10 -1
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +10 -1
- package/src/preview/property_previews/MapPropertyPreview.tsx +52 -1
- package/src/preview/property_previews/NumberPropertyPreview.tsx +9 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +8 -5
- package/src/routes/RebaseRoute.tsx +62 -4
- package/src/types/components/PropertyPreviewProps.tsx +21 -0
- package/src/util/number_format.ts +46 -0
- package/src/util/previews.ts +8 -55
- package/src/util/property_utils.tsx +6 -1
- package/dist/util-GiwPgxnL.js.map +0 -1
|
@@ -10,11 +10,11 @@ import { CollectionViewBinding } from "./CollectionViewBinding/CollectionViewBin
|
|
|
10
10
|
import { EntityViewBinding } from "./EntityViewBinding";
|
|
11
11
|
import { EntityIdentityBar } from "./EntityIdentityBar";
|
|
12
12
|
import { SplitListCloseButton } from "./CollectionViewBinding/SplitListCloseButton";
|
|
13
|
+
import { SplitListShowButton } from "./CollectionViewBinding/SplitListShowButton";
|
|
13
14
|
import { EntityInspector, InspectorTab } from "./EntityInspector";
|
|
14
15
|
import { CircularProgressCenter, iconSize } from "@rebasepro/ui";
|
|
15
16
|
import {
|
|
16
17
|
Alert,
|
|
17
|
-
ArrowLeftIcon,
|
|
18
18
|
Button,
|
|
19
19
|
CenteredView,
|
|
20
20
|
cls,
|
|
@@ -34,6 +34,7 @@ import { ErrorBoundary } from "@rebasepro/ui";
|
|
|
34
34
|
import { ErrorView, createFormexStub, usePermissions, useTranslation, getIcon } from "@rebasepro/app";
|
|
35
35
|
|
|
36
36
|
import { removeInitialAndTrailingSlashes, resolveDefaultSelectedView } from "@rebasepro/app";
|
|
37
|
+
import { withViewMode } from "../util/view_mode";
|
|
37
38
|
import { resolvedSelectedEntityView } from "../util/resolutions";
|
|
38
39
|
import {
|
|
39
40
|
useCustomizationController,
|
|
@@ -45,9 +46,7 @@ import {
|
|
|
45
46
|
import { useUrlController } from "../hooks/navigation/contexts/UrlContext";
|
|
46
47
|
import { useCollectionRegistryController } from "../hooks/navigation/contexts/CollectionRegistryContext";
|
|
47
48
|
import { useNavigate } from "react-router";
|
|
48
|
-
import {
|
|
49
|
-
import { getEntityTitlePropertyKeyForEntity, isUserSelectProperty, resolveTitleToString } from "../util/previews";
|
|
50
|
-
import { getUserLabel, useResolvedUser } from "../hooks/useResolvedUsers";
|
|
49
|
+
import { useEntityDisplayTitle } from "../hooks/useEntityDisplayTitle";
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
import { MAIN_TAB_VALUE, JSON_TAB_VALUE, HISTORY_TAB_VALUE } from "../util/view_constants";
|
|
@@ -57,6 +56,8 @@ export type BarActionsParams = {
|
|
|
57
56
|
status: EntityStatus,
|
|
58
57
|
path: string,
|
|
59
58
|
entityId?: string | number;
|
|
59
|
+
/** Always false here — this view reads a record, it does not edit one. */
|
|
60
|
+
dirty: boolean;
|
|
60
61
|
};
|
|
61
62
|
|
|
62
63
|
export type OnTabChangeParams<M extends Record<string, unknown>> = {
|
|
@@ -75,6 +76,13 @@ export interface DetailViewBindingProps<M extends Record<string, unknown> = Reco
|
|
|
75
76
|
parentEntityIds: string[];
|
|
76
77
|
onTabChange?: (props: OnTabChangeParams<M>) => void;
|
|
77
78
|
onEditClick?: () => void;
|
|
79
|
+
/**
|
|
80
|
+
* Dismiss this record — the ✕ at the identity bar's trailing edge.
|
|
81
|
+
*
|
|
82
|
+
* Set by the layouts that own the record's place on screen but are not side
|
|
83
|
+
* dialogs: the split, where dismissing is navigating back to the collection.
|
|
84
|
+
*/
|
|
85
|
+
onCloseRequest?: () => void;
|
|
78
86
|
layout?: "side_panel" | "full_screen" | "split" | "dialog";
|
|
79
87
|
barActions?: (params: BarActionsParams) => React.ReactNode;
|
|
80
88
|
/**
|
|
@@ -82,6 +90,12 @@ export interface DetailViewBindingProps<M extends Record<string, unknown> = Reco
|
|
|
82
90
|
* of the breadcrumb — the side panel's close button.
|
|
83
91
|
*/
|
|
84
92
|
barActionsStart?: React.ReactNode;
|
|
93
|
+
/**
|
|
94
|
+
* Full screen only: bring the list back beside this record. Set when the
|
|
95
|
+
* record was opened out of a split collection, so folding the list away is
|
|
96
|
+
* reversible; it takes the place of the back arrow when present.
|
|
97
|
+
*/
|
|
98
|
+
onShowList?: () => void;
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
export function DetailViewBinding<M extends Record<string, unknown>>({
|
|
@@ -137,11 +151,13 @@ function DetailViewBindingInner<M extends Record<string, unknown>>({
|
|
|
137
151
|
parentEntityIds,
|
|
138
152
|
onTabChange,
|
|
139
153
|
onEditClick,
|
|
154
|
+
onCloseRequest,
|
|
140
155
|
entity,
|
|
141
156
|
dataLoading,
|
|
142
157
|
layout = "full_screen",
|
|
143
158
|
barActions,
|
|
144
|
-
barActionsStart
|
|
159
|
+
barActionsStart,
|
|
160
|
+
onShowList
|
|
145
161
|
}: DetailViewBindingProps<M> & {
|
|
146
162
|
entity?: Entity<M>,
|
|
147
163
|
dataLoading: boolean,
|
|
@@ -283,18 +299,13 @@ entityId }
|
|
|
283
299
|
const formViewConfig = (collection as AdminCollection<M> & { formView?: FormViewConfig<M> }).formView;
|
|
284
300
|
const FormViewBuilder = formViewConfig?.Builder ? resolveComponentRef<EntityCustomViewParams>(formViewConfig.Builder as ComponentRef<EntityCustomViewParams>) : null;
|
|
285
301
|
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const title = titleUser
|
|
294
|
-
? getUserLabel(titleUser)
|
|
295
|
-
: (rawTitle !== undefined && rawTitle !== null
|
|
296
|
-
? resolveTitleToString(rawTitle)
|
|
297
|
-
: (collection.singularName ?? collection.name));
|
|
302
|
+
// The heading, resolved the one way — this used to be a copy of
|
|
303
|
+
// `useEntityDisplayTitle`'s body, and the two had already drifted.
|
|
304
|
+
const title = useEntityDisplayTitle({
|
|
305
|
+
collection,
|
|
306
|
+
entity: usedEntity,
|
|
307
|
+
status: "existing"
|
|
308
|
+
});
|
|
298
309
|
|
|
299
310
|
// Non-action custom views
|
|
300
311
|
const nonActionCustomViews = useMemo(() =>
|
|
@@ -380,20 +391,31 @@ entityId }
|
|
|
380
391
|
}, [onTabChange, path, entityId, collection]);
|
|
381
392
|
|
|
382
393
|
const propertyDetailView = () => {
|
|
383
|
-
// formView.Builder replaces the default property display
|
|
394
|
+
// formView.Builder replaces the default property display. It gets the
|
|
395
|
+
// centred column the record used to be given here; the default display
|
|
396
|
+
// now lays itself out, rail included.
|
|
384
397
|
if (FormViewBuilder && usedEntity) {
|
|
385
|
-
return <
|
|
386
|
-
<
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
398
|
+
return <div className={"flex-1 min-w-0 overflow-y-auto flex justify-center items-start"}>
|
|
399
|
+
<div className={cls(
|
|
400
|
+
"w-full max-w-3xl 2xl:max-w-4xl flex flex-col",
|
|
401
|
+
layout === "dialog"
|
|
402
|
+
? "pt-5 pb-12 px-6 sm:px-8"
|
|
403
|
+
: "pt-6 pb-16 px-5 sm:px-8"
|
|
404
|
+
)}>
|
|
405
|
+
<ErrorBoundary>
|
|
406
|
+
<Suspense fallback={<CircularProgressCenter />}>
|
|
407
|
+
<FormViewBuilder
|
|
408
|
+
collection={collection}
|
|
409
|
+
parentCollectionSlugs={parentCollectionSlugs}
|
|
410
|
+
parentEntityIds={parentEntityIds}
|
|
411
|
+
entity={usedEntity}
|
|
412
|
+
modifiedValues={usedEntity?.values}
|
|
413
|
+
formContext={readOnlyFormContext as FormContext<Record<string, unknown>>}
|
|
414
|
+
/>
|
|
415
|
+
</Suspense>
|
|
416
|
+
</ErrorBoundary>
|
|
417
|
+
</div>
|
|
418
|
+
</div>;
|
|
397
419
|
}
|
|
398
420
|
|
|
399
421
|
return (
|
|
@@ -402,6 +424,9 @@ entityId }
|
|
|
402
424
|
entity={usedEntity}
|
|
403
425
|
collection={collection}
|
|
404
426
|
path={path}
|
|
427
|
+
asPage
|
|
428
|
+
openEntityMode={layout}
|
|
429
|
+
formContext={readOnlyFormContext}
|
|
405
430
|
/>}
|
|
406
431
|
</>
|
|
407
432
|
);
|
|
@@ -458,24 +483,27 @@ entityId }
|
|
|
458
483
|
);
|
|
459
484
|
});
|
|
460
485
|
|
|
486
|
+
// The breadcrumb's destination, and the back arrow's when it renders. Both
|
|
487
|
+
// keep the view mode: a collection reached from one of its own records must
|
|
488
|
+
// come back as the user left it.
|
|
489
|
+
const collectionUrl = withViewMode(urlController.buildUrlCollectionPath(path));
|
|
490
|
+
|
|
461
491
|
// Full screen is the one layout with no way out of its own: a side panel and a
|
|
462
492
|
// dialog can be dismissed, and a split keeps the list beside it, but opening an
|
|
463
493
|
// entity full screen replaces the collection entirely and left browser Back as
|
|
464
494
|
// the only route back to it — which is not an affordance the page shows, and is
|
|
465
495
|
// wrong anyway once the user has moved between tabs inside the entity.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const shouldShowTopBar = Boolean(barActions) || hasAdditionalViews || layout === "side_panel" || layout === "dialog" || Boolean(backToCollectionButton);
|
|
496
|
+
//
|
|
497
|
+
// Unless the list can be unfolded back beside the record: that chevron
|
|
498
|
+
// leads to the same collection while keeping the record open, so it stands
|
|
499
|
+
// alone rather than beside an arrow going almost the same place.
|
|
500
|
+
//
|
|
501
|
+
// It goes to the bar's leading edge — where a back control reads as back,
|
|
502
|
+
// and where the edit view has always put the same arrow — rather than to
|
|
503
|
+
// the trailing edge among the record's own actions.
|
|
504
|
+
const backToCollection = layout === "full_screen" && !onShowList
|
|
505
|
+
? () => navigate(collectionUrl)
|
|
506
|
+
: undefined;
|
|
479
507
|
|
|
480
508
|
const fullScreenButton = !barActions && // Not in split: the list panel beside it carries the close control,
|
|
481
509
|
// and an expand button there competes with it.
|
|
@@ -508,49 +536,53 @@ entityId }
|
|
|
508
536
|
// Main content view. The title, the `path/id` chip and the empty band under
|
|
509
537
|
// them have moved into the identity bar, and the `w-80 2xl:w-96` rail that
|
|
510
538
|
// held a single Edit button is gone — the bar holds it now.
|
|
539
|
+
//
|
|
540
|
+
// The scroll now lives on the record's own column rather than on this row,
|
|
541
|
+
// so the metadata rail beside it stays put while the record scrolls — the
|
|
542
|
+
// same arrangement the form uses.
|
|
511
543
|
const mainView = <div
|
|
512
544
|
className={cls(
|
|
513
|
-
"flex-1 flex flex-row w-full
|
|
545
|
+
"flex-1 flex flex-row w-full min-h-0",
|
|
514
546
|
!mainViewVisible ? "hidden" : ""
|
|
515
547
|
)}>
|
|
516
|
-
|
|
517
|
-
"w-full max-w-3xl 2xl:max-w-4xl flex flex-col",
|
|
518
|
-
layout === "dialog"
|
|
519
|
-
? "pt-5 pb-12 px-6 sm:px-8"
|
|
520
|
-
: "pt-6 pb-16 px-5 sm:px-8"
|
|
521
|
-
)}>
|
|
522
|
-
{propertyDetailView()}
|
|
523
|
-
</div>
|
|
548
|
+
{propertyDetailView()}
|
|
524
549
|
</div>;
|
|
525
550
|
|
|
526
551
|
let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-800">
|
|
527
552
|
|
|
528
553
|
<EntityIdentityBar
|
|
529
554
|
collection={collection as AdminCollection}
|
|
555
|
+
collectionUrl={layout === "full_screen" || layout === "split" ? collectionUrl : undefined}
|
|
530
556
|
title={title}
|
|
531
557
|
entityId={entityId}
|
|
532
558
|
status={"existing"}
|
|
533
559
|
dirty={false}
|
|
534
560
|
saving={false}
|
|
561
|
+
onBack={backToCollection}
|
|
562
|
+
onClose={onCloseRequest}
|
|
535
563
|
onInspect={includeJsonView ? () => setInspectorTab("json") : undefined}
|
|
536
564
|
onViewHistory={includeHistoryView ? () => setInspectorTab("history") : undefined}
|
|
565
|
+
externalLink={usedEntity
|
|
566
|
+
? customizationController?.entityLinkBuilder?.({ entity: usedEntity })
|
|
567
|
+
: undefined}
|
|
537
568
|
leading={<>
|
|
538
569
|
{barActionsStart}
|
|
539
570
|
{/* Split view: closing the list is opening this record
|
|
540
571
|
full screen, and the control for it belongs at this
|
|
541
|
-
bar's leading edge. */}
|
|
572
|
+
bar's leading edge. Full screen carries its mirror. */}
|
|
542
573
|
{layout === "split" && <SplitListCloseButton/>}
|
|
574
|
+
{layout === "full_screen" && onShowList && <SplitListShowButton onClick={onShowList}/>}
|
|
543
575
|
</>}
|
|
544
576
|
trailing={<>
|
|
545
577
|
{editButton}
|
|
546
578
|
{pluginActionsTop}
|
|
547
|
-
{backToCollectionButton}
|
|
548
579
|
{fullScreenButton}
|
|
549
580
|
{barActions?.({
|
|
550
581
|
path,
|
|
551
582
|
entityId,
|
|
552
583
|
values: usedEntity?.values ?? {},
|
|
553
|
-
status: "existing"
|
|
584
|
+
status: "existing",
|
|
585
|
+
dirty: false
|
|
554
586
|
})}
|
|
555
587
|
</>}
|
|
556
588
|
/>
|
|
@@ -28,11 +28,12 @@ export interface DrawerNavigationGroupProps {
|
|
|
28
28
|
*/
|
|
29
29
|
drawerOpen: boolean;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* @deprecated No longer read. Entry tooltips are uncontrolled — they follow the
|
|
32
|
+
* pointer and focus, and are suppressed wherever the label is already visible.
|
|
32
33
|
*/
|
|
33
|
-
tooltipsOpen
|
|
34
|
+
tooltipsOpen?: boolean;
|
|
34
35
|
/**
|
|
35
|
-
*
|
|
36
|
+
* @deprecated No longer read. See {@link tooltipsOpen}.
|
|
36
37
|
*/
|
|
37
38
|
adminMenuOpen?: boolean;
|
|
38
39
|
/**
|
|
@@ -50,8 +51,10 @@ export interface DrawerNavigationGroupProps {
|
|
|
50
51
|
/**
|
|
51
52
|
* Lucide icon name for the group header, from `NavigationGroupMapping.icon`.
|
|
52
53
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
54
|
+
* It decorates the header and nothing else: the entries below are untouched and
|
|
55
|
+
* keep their own icons. An app that wants the categorised look — rows giving up
|
|
56
|
+
* their icons to indent under the group — builds it in its own drawer, by
|
|
57
|
+
* overriding `Shell.DrawerNavigationItem` and passing `indented`.
|
|
55
58
|
*/
|
|
56
59
|
icon?: string;
|
|
57
60
|
}
|
|
@@ -66,8 +69,6 @@ export function DrawerNavigationGroup({
|
|
|
66
69
|
collapsed,
|
|
67
70
|
onToggleCollapsed,
|
|
68
71
|
drawerOpen,
|
|
69
|
-
tooltipsOpen,
|
|
70
|
-
adminMenuOpen,
|
|
71
72
|
headerActions,
|
|
72
73
|
onItemClick,
|
|
73
74
|
hideHeader,
|
|
@@ -76,17 +77,13 @@ export function DrawerNavigationGroup({
|
|
|
76
77
|
const { t } = useTranslation();
|
|
77
78
|
const ResolvedDrawerNavigationItem = useComponentOverride("Shell.DrawerNavigationItem", DrawerNavigationItem);
|
|
78
79
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// nothing to indent under, and collapsed to a rail the entry icons are the only
|
|
86
|
-
// affordance left to click.
|
|
80
|
+
// The icon decorates the header, and stops there. It used to also strip the
|
|
81
|
+
// entries of theirs and indent them, which made a per-app styling choice into
|
|
82
|
+
// framework behaviour: every project that labelled a group with an icon lost the
|
|
83
|
+
// icons on its rows, with nothing to turn it off. An app that wants that look
|
|
84
|
+
// now opts into it in its own drawer — see `indented` on
|
|
85
|
+
// {@link DrawerNavigationItem}.
|
|
87
86
|
const groupIcon = !hideHeader && drawerOpen ? getIcon(icon, undefined, undefined, "small") : undefined;
|
|
88
|
-
const categorised = Boolean(groupIcon);
|
|
89
|
-
const indentEntries = categorised;
|
|
90
87
|
return (
|
|
91
88
|
<div
|
|
92
89
|
className={"my-2 mx-2 flex flex-col"}
|
|
@@ -103,10 +100,7 @@ export function DrawerNavigationGroup({
|
|
|
103
100
|
<ChevronDownIcon
|
|
104
101
|
size={iconSize.small}
|
|
105
102
|
className={cls(
|
|
106
|
-
|
|
107
|
-
? "text-surface-500 dark:text-surface-400"
|
|
108
|
-
: "text-surface-400 dark:text-surface-400",
|
|
109
|
-
"transition-transform duration-200 mr-1",
|
|
103
|
+
"text-surface-400 dark:text-surface-400 transition-transform duration-200 mr-1",
|
|
110
104
|
collapsed ? "-rotate-90" : "rotate-0"
|
|
111
105
|
)}
|
|
112
106
|
/>
|
|
@@ -118,21 +112,7 @@ export function DrawerNavigationGroup({
|
|
|
118
112
|
<Typography
|
|
119
113
|
variant={"caption"}
|
|
120
114
|
color={"secondary"}
|
|
121
|
-
|
|
122
|
-
// itself. Without an icon this is byte-for-byte the original: the
|
|
123
|
-
// drawer is a flat list of same-weight rows, and a louder header
|
|
124
|
-
// would just compete with them.
|
|
125
|
-
//
|
|
126
|
-
// With one, the group becomes the thing you scan — its rows have
|
|
127
|
-
// given up their icons to indent beneath it — so the label steps up
|
|
128
|
-
// to match. At 11px in surface-400 it sat *below* the contrast of
|
|
129
|
-
// the rows it labels, which is backwards once it is the anchor.
|
|
130
|
-
className={cls(
|
|
131
|
-
"font-semibold uppercase flex-grow line-clamp-1",
|
|
132
|
-
categorised
|
|
133
|
-
? "text-[12px] tracking-wide text-surface-600 dark:text-surface-300"
|
|
134
|
-
: "text-[11px] tracking-wider text-surface-400 dark:text-surface-400"
|
|
135
|
-
)}
|
|
115
|
+
className="font-semibold text-[11px] uppercase tracking-wider flex-grow line-clamp-1 text-surface-400 dark:text-surface-400"
|
|
136
116
|
>
|
|
137
117
|
{(group || t("views_group"))}
|
|
138
118
|
</Typography>
|
|
@@ -158,13 +138,10 @@ export function DrawerNavigationGroup({
|
|
|
158
138
|
<ResolvedDrawerNavigationItem
|
|
159
139
|
key={entry.id}
|
|
160
140
|
icon={<IconForView collectionOrView={entry.collection ?? entry.view} size={"small"}/>}
|
|
161
|
-
tooltipsOpen={!collapsed && tooltipsOpen}
|
|
162
|
-
adminMenuOpen={adminMenuOpen}
|
|
163
141
|
drawerOpen={drawerOpen}
|
|
164
142
|
onClick={() => onItemClick?.(entry)}
|
|
165
143
|
url={entry.url}
|
|
166
144
|
name={entry.name}
|
|
167
|
-
indented={indentEntries}
|
|
168
145
|
/>
|
|
169
146
|
))}
|
|
170
147
|
</div>
|
|
@@ -3,30 +3,39 @@ import React from "react";
|
|
|
3
3
|
import { NavLink } from "react-router";
|
|
4
4
|
import { cls, Tooltip } from "@rebasepro/ui";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
tooltipsOpen,
|
|
12
|
-
url,
|
|
13
|
-
onClick,
|
|
14
|
-
indented = false
|
|
15
|
-
}: {
|
|
6
|
+
/**
|
|
7
|
+
* Props of a drawer navigation row, named so an app overriding
|
|
8
|
+
* `Shell.DrawerNavigationItem` can type its wrapper against them.
|
|
9
|
+
*/
|
|
10
|
+
export type DrawerNavigationItemProps = {
|
|
16
11
|
icon: React.ReactElement,
|
|
17
12
|
name: string,
|
|
18
|
-
|
|
13
|
+
/** @deprecated No longer read: the tooltip is uncontrolled. */
|
|
14
|
+
tooltipsOpen?: boolean,
|
|
19
15
|
drawerOpen: boolean,
|
|
16
|
+
/** @deprecated No longer read: the tooltip is uncontrolled. */
|
|
20
17
|
adminMenuOpen?: boolean,
|
|
21
18
|
url: string,
|
|
22
19
|
onClick?: () => void,
|
|
23
20
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Drop the row's icon and indent the label into the space it occupied, so the
|
|
22
|
+
* row reads as a child of the group header above it.
|
|
23
|
+
*
|
|
24
|
+
* Nothing in the framework sets this: the stock drawer always passes `false`,
|
|
25
|
+
* and an app that wants the categorised look opts into it by overriding
|
|
26
|
+
* `Shell.DrawerNavigationItem` and deciding for itself which rows get it.
|
|
27
27
|
*/
|
|
28
28
|
indented?: boolean,
|
|
29
|
-
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function DrawerNavigationItem({
|
|
32
|
+
name,
|
|
33
|
+
icon,
|
|
34
|
+
drawerOpen,
|
|
35
|
+
url,
|
|
36
|
+
onClick,
|
|
37
|
+
indented = false
|
|
38
|
+
}: DrawerNavigationItemProps) {
|
|
30
39
|
|
|
31
40
|
// Indented rows give up the icon rather than keeping it *and* indenting: a
|
|
32
41
|
// per-row icon repeated down a group is what flattens the hierarchy, since
|
|
@@ -40,6 +49,15 @@ export function DrawerNavigationItem({
|
|
|
40
49
|
{icon}
|
|
41
50
|
</div>;
|
|
42
51
|
|
|
52
|
+
const [wantsTooltip, setWantsTooltip] = React.useState(false);
|
|
53
|
+
|
|
54
|
+
// Radix will not report a close it never noticed: while the tooltip is masked
|
|
55
|
+
// the pointer can leave the row without `onOpenChange(false)` ever firing. So
|
|
56
|
+
// the stale `true` is dropped on the way *into* the masked state — otherwise
|
|
57
|
+
// it surfaces the moment the mask lifts, as a tooltip hanging over a rail the
|
|
58
|
+
// pointer left long ago.
|
|
59
|
+
if (drawerOpen && wantsTooltip) setWantsTooltip(false);
|
|
60
|
+
|
|
43
61
|
const listItem = <div>
|
|
44
62
|
<NavLink
|
|
45
63
|
onClick={onClick}
|
|
@@ -70,8 +88,18 @@ export function DrawerNavigationItem({
|
|
|
70
88
|
</NavLink>
|
|
71
89
|
</div>;
|
|
72
90
|
|
|
91
|
+
// Per row, and always controlled. The old shared flag could only say "every
|
|
92
|
+
// tooltip" or "none", and the state it needed was unreachable, so no entry
|
|
93
|
+
// tooltip ever opened — leaving a bare rail of unlabelled icons. Radix decides
|
|
94
|
+
// when this one wants to be open, from the pointer and from focus; the drawer
|
|
95
|
+
// only masks it once the label says the same thing.
|
|
96
|
+
//
|
|
97
|
+
// Masked rather than withheld: dropping `open`, or the title, would move the
|
|
98
|
+
// tooltip between controlled and uncontrolled as the drawer opens, which
|
|
99
|
+
// strands the old state — a tooltip left up over a pointer nowhere near it.
|
|
73
100
|
return <Tooltip
|
|
74
|
-
open={drawerOpen
|
|
101
|
+
open={!drawerOpen && wantsTooltip}
|
|
102
|
+
onOpenChange={setWantsTooltip}
|
|
75
103
|
side="right"
|
|
76
104
|
title={name}>
|
|
77
105
|
{listItem}
|