@modufolio/panel 0.1.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 -0
- package/README.md +165 -0
- package/dist/Builder/ImageNodeView.d.ts +33 -0
- package/dist/Builder/document.d.ts +17 -0
- package/dist/Builder/dragHandle.d.ts +13 -0
- package/dist/Builder/editing.d.ts +53 -0
- package/dist/Builder/plugins.d.ts +27 -0
- package/dist/Builder/schema.d.ts +20 -0
- package/dist/Components/Actions/Action.vue.d.ts +116 -0
- package/dist/Components/Actions/ActionGroup.vue.d.ts +25 -0
- package/dist/Components/Actions/ActionGroupItem.vue.d.ts +48 -0
- package/dist/Components/Auth/ForgotPassword.vue.d.ts +17 -0
- package/dist/Components/Auth/Login.vue.d.ts +33 -0
- package/dist/Components/Auth/ResetPassword.vue.d.ts +27 -0
- package/dist/Components/Auth/TwoFactor.vue.d.ts +32 -0
- package/dist/Components/Auth/TwoFactorVerify.vue.d.ts +31 -0
- package/dist/Components/Columns/BadgeColumn.vue.d.ts +34 -0
- package/dist/Components/Columns/BooleanColumn.vue.d.ts +78 -0
- package/dist/Components/Columns/CellActions.vue.d.ts +34 -0
- package/dist/Components/Columns/ColorColumn.vue.d.ts +84 -0
- package/dist/Components/Columns/CopyButton.vue.d.ts +15 -0
- package/dist/Components/Columns/DateColumn.vue.d.ts +60 -0
- package/dist/Components/Columns/IconColumn.vue.d.ts +56 -0
- package/dist/Components/Columns/ImageColumn.vue.d.ts +46 -0
- package/dist/Components/Columns/SelectColumn.vue.d.ts +71 -0
- package/dist/Components/Columns/TextColumn.vue.d.ts +69 -0
- package/dist/Components/Columns/TextInputColumn.vue.d.ts +75 -0
- package/dist/Components/Columns/ToggleColumn.vue.d.ts +91 -0
- package/dist/Components/Columns/TreeColumn.vue.d.ts +60 -0
- package/dist/Components/Columns/columnRegistry.d.ts +6 -0
- package/dist/Components/Composables/useInlineEdit.d.ts +27 -0
- package/dist/Components/Composables/useRelationship.d.ts +38 -0
- package/dist/Components/Core/Badge.vue.d.ts +47 -0
- package/dist/Components/Core/Button.vue.d.ts +131 -0
- package/dist/Components/Core/Dropdown.vue.d.ts +24 -0
- package/dist/Components/Core/Empty.vue.d.ts +54 -0
- package/dist/Components/Core/ErrorBoundary.vue.d.ts +24 -0
- package/dist/Components/Core/FlashMessages.vue.d.ts +7 -0
- package/dist/Components/Core/Icon.vue.d.ts +23 -0
- package/dist/Components/Core/Icons/DocumentLinesIcon.vue.d.ts +3 -0
- package/dist/Components/Core/Icons/SitemapIcon.vue.d.ts +3 -0
- package/dist/Components/Core/Label.vue.d.ts +52 -0
- package/dist/Components/Core/LoadingButton.vue.d.ts +18 -0
- package/dist/Components/Core/Modal.vue.d.ts +26 -0
- package/dist/Components/Core/Pagination.vue.d.ts +10 -0
- package/dist/Components/Core/SelectInput.vue.d.ts +26 -0
- package/dist/Components/Core/Tag.vue.d.ts +65 -0
- package/dist/Components/Core/TextInput.vue.d.ts +25 -0
- package/dist/Components/Core/iconRegistry.d.ts +3 -0
- package/dist/Components/Dialogs/ConfirmDialog.vue.d.ts +16 -0
- package/dist/Components/Dialogs/DeleteConfirmDialog.vue.d.ts +30 -0
- package/dist/Components/Dialogs/Dialog.vue.d.ts +81 -0
- package/dist/Components/Drawer/Drawer.vue.d.ts +130 -0
- package/dist/Components/Drawer/DrawerFieldGrid.vue.d.ts +39 -0
- package/dist/Components/Drawer/DrawerLink.vue.d.ts +96 -0
- package/dist/Components/Drawer/DrawerRelationList.vue.d.ts +81 -0
- package/dist/Components/Drawer/DrawerStack.vue.d.ts +93 -0
- package/dist/Components/Drawer/DrawerTabs.vue.d.ts +42 -0
- package/dist/Components/Drawer/NestedDrawerForm.vue.d.ts +55 -0
- package/dist/Components/Drawer/drawerFieldGrid.d.ts +25 -0
- package/dist/Components/Drawer/drawerTabs.d.ts +16 -0
- package/dist/Components/Drawer/useDrawerPage.d.ts +34 -0
- package/dist/Components/Drawer/useDrawerStack.d.ts +93 -0
- package/dist/Components/Drawer/useFocusedStackRow.d.ts +22 -0
- package/dist/Components/Drawer/useIsDrawer.d.ts +66 -0
- package/dist/Components/Drawer/visitDrawer.d.ts +48 -0
- package/dist/Components/Fields/BelongsToSelect.vue.d.ts +247 -0
- package/dist/Components/Fields/BlueprintForm.vue.d.ts +96 -0
- package/dist/Components/Fields/Calendar/CalendarPanel.vue.d.ts +63 -0
- package/dist/Components/Fields/Calendar/MonthGrid.vue.d.ts +82 -0
- package/dist/Components/Fields/CheckboxField.vue.d.ts +92 -0
- package/dist/Components/Fields/ColorPickerField.vue.d.ts +105 -0
- package/dist/Components/Fields/DatePickerField.vue.d.ts +102 -0
- package/dist/Components/Fields/DateRangePickerField.vue.d.ts +138 -0
- package/dist/Components/Fields/DateTimePickerField.vue.d.ts +134 -0
- package/dist/Components/Fields/FieldGrid.vue.d.ts +13 -0
- package/dist/Components/Fields/FileUploadField.vue.d.ts +117 -0
- package/dist/Components/Fields/MultiSelectField.vue.d.ts +129 -0
- package/dist/Components/Fields/ProseMirrorBuilderField.vue.d.ts +71 -0
- package/dist/Components/Fields/RangeField.vue.d.ts +122 -0
- package/dist/Components/Fields/RepeaterField.vue.d.ts +174 -0
- package/dist/Components/Fields/RichTextEditorField.vue.d.ts +118 -0
- package/dist/Components/Fields/SelectField.vue.d.ts +102 -0
- package/dist/Components/Fields/TagsField.vue.d.ts +102 -0
- package/dist/Components/Fields/TextField.vue.d.ts +138 -0
- package/dist/Components/Fields/TextareaField.vue.d.ts +111 -0
- package/dist/Components/Fields/TimePickerField.vue.d.ts +115 -0
- package/dist/Components/Fields/ToggleButtonsField.vue.d.ts +93 -0
- package/dist/Components/Fields/ToggleField.vue.d.ts +95 -0
- package/dist/Components/Fields/fieldRegistry.d.ts +25 -0
- package/dist/Components/Fields/fieldsFromSpec.d.ts +10 -0
- package/dist/Components/Fields/useBlueprint.d.ts +94 -0
- package/dist/Components/Fields/useFieldWidth.d.ts +10 -0
- package/dist/Components/Fields/validation.d.ts +43 -0
- package/dist/Components/Filters/DateRangeFilter.vue.d.ts +92 -0
- package/dist/Components/Filters/FacetedFilter.vue.d.ts +41 -0
- package/dist/Components/Filters/FilterIndicators.vue.d.ts +40 -0
- package/dist/Components/Filters/FilterPopover.vue.d.ts +38 -0
- package/dist/Components/Filters/MultiSelectFilter.vue.d.ts +51 -0
- package/dist/Components/Filters/NumberFilter.vue.d.ts +61 -0
- package/dist/Components/Filters/QueryBuilder.vue.d.ts +32 -0
- package/dist/Components/Filters/SelectFilter.vue.d.ts +61 -0
- package/dist/Components/Filters/TernaryFilter.vue.d.ts +73 -0
- package/dist/Components/Layout/AppLayout.vue.d.ts +137 -0
- package/dist/Components/Layout/Breadcrumbs.vue.d.ts +44 -0
- package/dist/Components/Layout/Cluster.vue.d.ts +88 -0
- package/dist/Components/Layout/Container.vue.d.ts +69 -0
- package/dist/Components/Layout/Grid.vue.d.ts +110 -0
- package/dist/Components/Layout/PageHeader.vue.d.ts +62 -0
- package/dist/Components/Layout/Sidebar.vue.d.ts +59 -0
- package/dist/Components/Layout/Stack.vue.d.ts +69 -0
- package/dist/Components/Layout/TopNavigation.vue.d.ts +124 -0
- package/dist/Components/Media/MediaPickerDialog.vue.d.ts +20 -0
- package/dist/Components/Media/mediaEndpoints.d.ts +18 -0
- package/dist/Components/Notifications/Toast.vue.d.ts +17 -0
- package/dist/Components/Notifications/useToast.d.ts +43 -0
- package/dist/Components/Relations/RelationManager.vue.d.ts +232 -0
- package/dist/Components/Sections/FieldsSection.vue.d.ts +56 -0
- package/dist/Components/Sections/FilesSection.vue.d.ts +120 -0
- package/dist/Components/Sections/FormSection.vue.d.ts +111 -0
- package/dist/Components/Sections/InfoSection.vue.d.ts +77 -0
- package/dist/Components/Sections/Section.vue.d.ts +67 -0
- package/dist/Components/Table/ColumnToggle.vue.d.ts +42 -0
- package/dist/Components/Table/ExportButton.vue.d.ts +93 -0
- package/dist/Components/Table/SchemaCell.d.ts +50 -0
- package/dist/Components/Table/SchemaFilterPanel.vue.d.ts +64 -0
- package/dist/Components/Table/SchemaTable.vue.d.ts +255 -0
- package/dist/Components/Table/Table.vue.d.ts +232 -0
- package/dist/Components/Table/TableEmptyState.vue.d.ts +24 -0
- package/dist/Components/Table/TablePagination.vue.d.ts +71 -0
- package/dist/Components/Table/TableSkeletonRows.vue.d.ts +52 -0
- package/dist/Components/Table/TableSortButton.vue.d.ts +38 -0
- package/dist/Components/Table/TableToolbar.vue.d.ts +62 -0
- package/dist/Components/Table/schemaLinks.d.ts +16 -0
- package/dist/Components/Table/tableSchema.d.ts +243 -0
- package/dist/Components/Table/tableTypes.d.ts +13 -0
- package/dist/Components/Table/useSchemaActions.d.ts +82 -0
- package/dist/Components/Table/useSchemaFilters.d.ts +28 -0
- package/dist/Components/Table/useTableExport.d.ts +16 -0
- package/dist/Components/Table/useTableGrouping.d.ts +9 -0
- package/dist/Components/Table/useTableRowFocus.d.ts +27 -0
- package/dist/Components/Table/useTableSelection.d.ts +15 -0
- package/dist/Components/Table/useTableTree.d.ts +23 -0
- package/dist/Components/Widgets/StatCard.vue.d.ts +81 -0
- package/dist/Components/Widgets/StatsWidget.vue.d.ts +27 -0
- package/dist/Components/Wizard/Wizard.vue.d.ts +99 -0
- package/dist/Composables/useAsyncData.d.ts +48 -0
- package/dist/Composables/useDeleteConfirmation.d.ts +86 -0
- package/dist/Composables/useDragReorder.d.ts +12 -0
- package/dist/Composables/useFieldSaver.d.ts +15 -0
- package/dist/Composables/useFocusTrap.d.ts +5 -0
- package/dist/Composables/useLocalStoragePersistence.d.ts +18 -0
- package/dist/Composables/useNestedDrawerForm.d.ts +58 -0
- package/dist/Composables/usePagination.d.ts +23 -0
- package/dist/Composables/usePendingKeys.d.ts +30 -0
- package/dist/Composables/useQuery.d.ts +61 -0
- package/dist/Composables/useReconciled.d.ts +22 -0
- package/dist/Composables/useUnsavedChangesWarning.d.ts +16 -0
- package/dist/Primitives/hideOthers.d.ts +12 -0
- package/dist/Primitives/teleportTarget.d.ts +2 -0
- package/dist/Primitives/useAnchoredPosition.d.ts +32 -0
- package/dist/Primitives/useArrowNavigation.d.ts +30 -0
- package/dist/Primitives/useBodyScrollLock.d.ts +9 -0
- package/dist/Primitives/useDismissableLayer.d.ts +46 -0
- package/dist/Primitives/useId.d.ts +13 -0
- package/dist/Primitives/useTypeahead.d.ts +11 -0
- package/dist/Utils/apiFetch.d.ts +28 -0
- package/dist/Utils/csrf.d.ts +2 -0
- package/dist/Utils/dates.d.ts +50 -0
- package/dist/Utils/moduleSingleton.d.ts +21 -0
- package/dist/Utils/optimistic.d.ts +33 -0
- package/dist/Utils/reconcile.d.ts +17 -0
- package/dist/Utils/tagsChanged.d.ts +16 -0
- package/dist/Utils/url.d.ts +40 -0
- package/dist/Utils/writeGate.d.ts +82 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +157 -0
- package/dist/index.js +27193 -0
- package/dist/index.js.map +1 -0
- package/dist/injectionKeys.d.ts +10 -0
- package/dist/plugin.d.ts +36 -0
- package/dist/types/menu.d.ts +11 -0
- package/docs/async-writes.md +159 -0
- package/docs/custom-fields.md +71 -0
- package/docs/drawer-protocol.md +130 -0
- package/docs/overlays.md +106 -0
- package/docs/relation-fields.md +112 -0
- package/docs/roadmap.md +38 -0
- package/docs/table-schema.md +371 -0
- package/package.json +150 -0
- package/styles/buttons.css +31 -0
- package/styles/form.css +74 -0
- package/styles/index.css +15 -0
- package/styles/tokens.css +79 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DrawerTab } from './drawerTabs';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
tabs: Array<DrawerTab | string>;
|
|
4
|
+
modelValue?: string;
|
|
5
|
+
ariaLabel?: string;
|
|
6
|
+
/** Keep visited panels mounted so their local state survives tab switches. */
|
|
7
|
+
keepAlive?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare var __VLS_2: `tab-${string}`, __VLS_3: {
|
|
10
|
+
tab: DrawerTab;
|
|
11
|
+
active: boolean;
|
|
12
|
+
}, __VLS_10: {
|
|
13
|
+
activeKey: string;
|
|
14
|
+
}, __VLS_13: string, __VLS_14: {
|
|
15
|
+
tab: DrawerTab;
|
|
16
|
+
};
|
|
17
|
+
type __VLS_Slots = {} & {
|
|
18
|
+
[K in NonNullable<typeof __VLS_2>]?: (props: typeof __VLS_3) => any;
|
|
19
|
+
} & {
|
|
20
|
+
[K in NonNullable<typeof __VLS_13>]?: (props: typeof __VLS_14) => any;
|
|
21
|
+
} & {
|
|
22
|
+
actions?: (props: typeof __VLS_10) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
25
|
+
"update:modelValue": (key: string) => any;
|
|
26
|
+
change: (key: string) => any;
|
|
27
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
28
|
+
"onUpdate:modelValue"?: ((key: string) => any) | undefined;
|
|
29
|
+
onChange?: ((key: string) => any) | undefined;
|
|
30
|
+
}>, {
|
|
31
|
+
modelValue: string;
|
|
32
|
+
ariaLabel: string;
|
|
33
|
+
keepAlive: boolean;
|
|
34
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
35
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
36
|
+
declare const _default: typeof __VLS_export;
|
|
37
|
+
export default _default;
|
|
38
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
39
|
+
new (): {
|
|
40
|
+
$slots: S;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FieldConfig, FormState } from '../../Composables/useNestedDrawerForm';
|
|
2
|
+
declare const __VLS_export: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
|
|
3
|
+
fields: {
|
|
4
|
+
type: () => FieldConfig[];
|
|
5
|
+
required: true;
|
|
6
|
+
};
|
|
7
|
+
state: {
|
|
8
|
+
type: () => FormState;
|
|
9
|
+
required: true;
|
|
10
|
+
};
|
|
11
|
+
errors: {
|
|
12
|
+
type: () => Record<string, string>;
|
|
13
|
+
required: true;
|
|
14
|
+
};
|
|
15
|
+
serverError: {
|
|
16
|
+
type: () => string | null;
|
|
17
|
+
default: null;
|
|
18
|
+
};
|
|
19
|
+
saving: {
|
|
20
|
+
type: BooleanConstructor;
|
|
21
|
+
default: boolean;
|
|
22
|
+
};
|
|
23
|
+
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
24
|
+
submit: () => any;
|
|
25
|
+
"update:field": (field: string, value: unknown) => any;
|
|
26
|
+
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
|
|
27
|
+
fields: {
|
|
28
|
+
type: () => FieldConfig[];
|
|
29
|
+
required: true;
|
|
30
|
+
};
|
|
31
|
+
state: {
|
|
32
|
+
type: () => FormState;
|
|
33
|
+
required: true;
|
|
34
|
+
};
|
|
35
|
+
errors: {
|
|
36
|
+
type: () => Record<string, string>;
|
|
37
|
+
required: true;
|
|
38
|
+
};
|
|
39
|
+
serverError: {
|
|
40
|
+
type: () => string | null;
|
|
41
|
+
default: null;
|
|
42
|
+
};
|
|
43
|
+
saving: {
|
|
44
|
+
type: BooleanConstructor;
|
|
45
|
+
default: boolean;
|
|
46
|
+
};
|
|
47
|
+
}>> & Readonly<{
|
|
48
|
+
onSubmit?: (() => any) | undefined;
|
|
49
|
+
"onUpdate:field"?: ((field: string, value: unknown) => any) | undefined;
|
|
50
|
+
}>, {
|
|
51
|
+
saving: boolean;
|
|
52
|
+
serverError: string | null;
|
|
53
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
54
|
+
declare const _default: typeof __VLS_export;
|
|
55
|
+
export default _default;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One entry in a {@link DrawerFieldGrid}.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than inside the SFC so consumers can import the type
|
|
5
|
+
* (`<script setup>` cannot export type declarations).
|
|
6
|
+
*/
|
|
7
|
+
export interface DrawerField {
|
|
8
|
+
/** Stable identifier — also the per-field slot name (`#field-{key}`). */
|
|
9
|
+
key: string;
|
|
10
|
+
label: string;
|
|
11
|
+
/** Display text; already stringified, with blanks rendered as an em dash. */
|
|
12
|
+
value: string;
|
|
13
|
+
/** Claim the full row rather than one column. */
|
|
14
|
+
wide?: boolean;
|
|
15
|
+
/** The value before stringification, for slot consumers. */
|
|
16
|
+
raw?: unknown;
|
|
17
|
+
/**
|
|
18
|
+
* A thumbnail to render instead of `value` — recognised from a raw value
|
|
19
|
+
* shaped `{ thumbnail_url, url }` (the convention presenters already use
|
|
20
|
+
* for a media reference, e.g. a post's cover). Absent for every other
|
|
21
|
+
* field, including a plain URL string, which stays text: only a presenter
|
|
22
|
+
* that opted into the object shape gets the image treatment.
|
|
23
|
+
*/
|
|
24
|
+
image?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A section in a {@link DrawerTabs} bar.
|
|
3
|
+
*
|
|
4
|
+
* Declared here rather than inside the SFC so consumers can import the type
|
|
5
|
+
* (`<script setup>` cannot export type declarations).
|
|
6
|
+
*/
|
|
7
|
+
export interface DrawerTab {
|
|
8
|
+
/** Stable identifier — also the panel slot name. */
|
|
9
|
+
key: string;
|
|
10
|
+
label: string;
|
|
11
|
+
/** Registered icon name, rendered before the label. */
|
|
12
|
+
icon?: string;
|
|
13
|
+
/** Count or short string shown in a pill after the label. Hidden when null/undefined/''. */
|
|
14
|
+
badge?: number | string | null;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
2
|
+
import { DrawerContext } from './useIsDrawer';
|
|
3
|
+
/**
|
|
4
|
+
* Context-aware page data accessor for components that render
|
|
5
|
+
* in both full-page and drawer contexts.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by Tofandel/inertia-vue3-modal's custom usePage():
|
|
8
|
+
* components call useDrawerPage() instead of usePage() and get
|
|
9
|
+
* the correct data regardless of context — no `if (isDrawer)` checks.
|
|
10
|
+
*
|
|
11
|
+
* When rendered as a full page:
|
|
12
|
+
* - Returns the standard Inertia page props
|
|
13
|
+
* - `isDrawer` is false
|
|
14
|
+
* - `drawerContext` is null
|
|
15
|
+
*
|
|
16
|
+
* When rendered inside a drawer:
|
|
17
|
+
* - `props` returns the drawer item's data
|
|
18
|
+
* - `parentProps` gives access to the parent page's props
|
|
19
|
+
* - `isDrawer` is true
|
|
20
|
+
* - `drawerContext` has level, close, back
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* const { props, isDrawer, parentProps } = useDrawerPage()
|
|
24
|
+
*/
|
|
25
|
+
export declare function useDrawerPage(): {
|
|
26
|
+
/** The entity data: drawer item data when in a drawer, page props otherwise */
|
|
27
|
+
props: ComputedRef<Record<string, unknown>>;
|
|
28
|
+
/** Whether this component is inside a drawer */
|
|
29
|
+
isDrawer: ComputedRef<boolean>;
|
|
30
|
+
/** The Inertia page props (always the parent page, even inside a drawer) */
|
|
31
|
+
parentProps: ComputedRef<Record<string, unknown>>;
|
|
32
|
+
/** Drawer context (level, close, back) — null when not in a drawer */
|
|
33
|
+
drawerContext: DrawerContext | false;
|
|
34
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* A section the server declared for this frame. Absent or empty means the
|
|
4
|
+
* frame renders as one undivided body, which is what every frame did before
|
|
5
|
+
* tabs existed.
|
|
6
|
+
*/
|
|
7
|
+
export interface StackItemTab {
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
/** 'custom' bodies are rendered by the page, not the shared components. */
|
|
11
|
+
type: 'details' | 'relation' | 'custom';
|
|
12
|
+
/** Details tabs only: the relation lists rendered inline beneath the grid. */
|
|
13
|
+
sections?: StackItemTab[];
|
|
14
|
+
/**
|
|
15
|
+
* Details tabs only: which record keys this grid shows and in what order,
|
|
16
|
+
* as `key => label override`. Absent means every eligible key.
|
|
17
|
+
*/
|
|
18
|
+
fields?: Record<string, string | null>;
|
|
19
|
+
/** Relation tabs only: whether a row drills into a frame or visits a page. */
|
|
20
|
+
navigation?: 'drawer' | 'visit';
|
|
21
|
+
/** Row list styling: one bordered list, or a card per row. */
|
|
22
|
+
variant?: 'list' | 'cards';
|
|
23
|
+
deletable?: boolean;
|
|
24
|
+
/** Row drill-down pattern over `{parent}` and `{id}`. */
|
|
25
|
+
recordUrl?: string | null;
|
|
26
|
+
/** Relation tabs only: the key in `data` holding the rows. */
|
|
27
|
+
source?: string;
|
|
28
|
+
primary?: string | null;
|
|
29
|
+
secondary?: string | null;
|
|
30
|
+
/** Short classifying value shown before the primary, in its own column. */
|
|
31
|
+
category?: string | null;
|
|
32
|
+
empty?: string;
|
|
33
|
+
badge?: number | null;
|
|
34
|
+
addable?: boolean;
|
|
35
|
+
addLabel?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One frame of the drawer stack, as the server builds it.
|
|
39
|
+
*
|
|
40
|
+
* The single definition: DrawerStack.vue used to declare its own copy, and the
|
|
41
|
+
* two had already drifted (only one knew about record navigation). Slot types
|
|
42
|
+
* come from here now, so a field the server adds is visible to every consumer.
|
|
43
|
+
*/
|
|
44
|
+
export interface StackItem {
|
|
45
|
+
type: string;
|
|
46
|
+
data: Record<string, any>;
|
|
47
|
+
title?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
width?: string;
|
|
50
|
+
key?: string;
|
|
51
|
+
href?: string;
|
|
52
|
+
nextRecordUrl?: string;
|
|
53
|
+
previousRecordUrl?: string;
|
|
54
|
+
tabs?: StackItemTab[];
|
|
55
|
+
/**
|
|
56
|
+
* Which frame renders this item: the side panel a record is read in, or a
|
|
57
|
+
* centred dialog for one decision or one short form.
|
|
58
|
+
*
|
|
59
|
+
* Absent means `drawer`, so every frame built before dialogs existed keeps
|
|
60
|
+
* rendering exactly as it did.
|
|
61
|
+
*/
|
|
62
|
+
presentation?: 'drawer' | 'dialog';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Composable for URL-driven hierarchical drawer stack navigation.
|
|
66
|
+
*
|
|
67
|
+
* The stack is driven by the server via Inertia props — no client-side state management needed.
|
|
68
|
+
* The URL represents the full navigation state, so browser back/forward works natively.
|
|
69
|
+
*
|
|
70
|
+
* All visits include the X-Inertia-Drawer-Stack header so the server can detect
|
|
71
|
+
* drawer context for redirect interception (inspired by Tofandel/inertia-vue3-modal).
|
|
72
|
+
*
|
|
73
|
+
* Usage in a page component:
|
|
74
|
+
*
|
|
75
|
+
* const props = defineProps({ stack: Array })
|
|
76
|
+
* const { stack, isOpen, push, pop, closeAll } = useDrawerStack(props, '/contacts')
|
|
77
|
+
*
|
|
78
|
+
* The server controller builds the stack array and passes it as an Inertia prop.
|
|
79
|
+
* Each `push()` call navigates to a deeper URL; `pop()` goes back.
|
|
80
|
+
*/
|
|
81
|
+
export declare function useDrawerStack(props: {
|
|
82
|
+
stack?: StackItem[];
|
|
83
|
+
}, baseUrl: string): {
|
|
84
|
+
stack: ComputedRef<StackItem[]>;
|
|
85
|
+
isOpen: ComputedRef<boolean>;
|
|
86
|
+
depth: ComputedRef<number>;
|
|
87
|
+
topItem: ComputedRef<StackItem | null>;
|
|
88
|
+
push: (href: string) => void;
|
|
89
|
+
pushWithParams: (id: number | string, params?: Record<string, string>) => void;
|
|
90
|
+
pop: () => void;
|
|
91
|
+
closeAll: () => void;
|
|
92
|
+
closeFrom: (index: number) => void;
|
|
93
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComputedRef } from 'vue';
|
|
2
|
+
import { StackItem } from './useDrawerStack';
|
|
3
|
+
/**
|
|
4
|
+
* Index of the table row the drawer stack is currently showing, for
|
|
5
|
+
* `<SchemaTable :external-focused-row-index>`.
|
|
6
|
+
*
|
|
7
|
+
* The drawer's record pagination (arrow keys) changes the stack without a
|
|
8
|
+
* click, so the highlighted row must be derived from the top stack item
|
|
9
|
+
* rather than from the row that opened the drawer.
|
|
10
|
+
*
|
|
11
|
+
* Returns -1 when no drawer is open, the top item is a different `type`
|
|
12
|
+
* (e.g. a nested drawer), or the record is not in the current page of rows.
|
|
13
|
+
* Omitting `type` matches any top item by id — safe with UUID ids, where a
|
|
14
|
+
* nested drawer's record can never collide with a row of the listing.
|
|
15
|
+
*
|
|
16
|
+
* const focusedRow = useFocusedStackRow(props, 'submission', () => props.submissions.data)
|
|
17
|
+
*/
|
|
18
|
+
export declare function useFocusedStackRow(props: {
|
|
19
|
+
stack?: StackItem[];
|
|
20
|
+
}, type: string | undefined, records: () => Array<{
|
|
21
|
+
id?: unknown;
|
|
22
|
+
}> | undefined): ComputedRef<number>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { StackItem } from './useDrawerStack';
|
|
3
|
+
/**
|
|
4
|
+
* Injection keys for drawer context.
|
|
5
|
+
*
|
|
6
|
+
* Inspired by Tofandel/inertia-vue3-modal's provide/inject pattern:
|
|
7
|
+
* any component rendered inside a drawer can detect its context
|
|
8
|
+
* without prop drilling.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DRAWER_CONTEXT_KEY = "DrawerContext";
|
|
11
|
+
export declare const DRAWER_STACK_KEY = "DrawerStackContext";
|
|
12
|
+
/**
|
|
13
|
+
* HTTP header sent with drawer navigation requests.
|
|
14
|
+
* Mirrors the PHP DrawerStack::HEADER constant.
|
|
15
|
+
* Used by DrawerLink and useDrawerStack to signal the server
|
|
16
|
+
* that this request originated from within a drawer.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DRAWER_HEADER = "X-Inertia-Drawer-Stack";
|
|
19
|
+
export interface DrawerContext {
|
|
20
|
+
/** The current stack item for this drawer */
|
|
21
|
+
item: StackItem;
|
|
22
|
+
/** Zero-based depth index of this drawer in the stack */
|
|
23
|
+
level: number;
|
|
24
|
+
/** Close this drawer (and all above it) */
|
|
25
|
+
close: () => void;
|
|
26
|
+
/** Go back one level */
|
|
27
|
+
back: () => void;
|
|
28
|
+
}
|
|
29
|
+
export interface DrawerStackContext {
|
|
30
|
+
/** Full stack array (shallow — avoids deep reactivity on large data) */
|
|
31
|
+
stack: Ref<StackItem[]>;
|
|
32
|
+
/** Base URL of the parent listing page */
|
|
33
|
+
baseUrl: string;
|
|
34
|
+
/** Push a new entity onto the stack */
|
|
35
|
+
push: (href: string) => void;
|
|
36
|
+
/** Pop the top drawer */
|
|
37
|
+
pop: () => void;
|
|
38
|
+
/** Close the entire stack */
|
|
39
|
+
closeAll: () => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Detect if the current component is rendered inside a drawer.
|
|
43
|
+
*
|
|
44
|
+
* Returns the DrawerContext for the nearest ancestor drawer,
|
|
45
|
+
* or `false` if not inside a drawer.
|
|
46
|
+
*
|
|
47
|
+
* Usage:
|
|
48
|
+
* const drawer = useIsDrawer()
|
|
49
|
+
* if (drawer) {
|
|
50
|
+
* console.log(drawer.item.type, drawer.level)
|
|
51
|
+
* }
|
|
52
|
+
*/
|
|
53
|
+
export declare function useIsDrawer(): DrawerContext | false;
|
|
54
|
+
/**
|
|
55
|
+
* Access the drawer stack context from any descendant component.
|
|
56
|
+
*
|
|
57
|
+
* Returns the DrawerStackContext with push/pop/closeAll methods,
|
|
58
|
+
* or `null` if not inside a DrawerStack.
|
|
59
|
+
*
|
|
60
|
+
* Usage:
|
|
61
|
+
* const stackCtx = useDrawerStackContext()
|
|
62
|
+
* if (stackCtx) {
|
|
63
|
+
* stackCtx.push('/contacts/12/organization/4')
|
|
64
|
+
* }
|
|
65
|
+
*/
|
|
66
|
+
export declare function useDrawerStackContext(): DrawerStackContext | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One way to navigate the drawer stack.
|
|
3
|
+
*
|
|
4
|
+
* The drawer protocol is a convention held in three places at once — a header
|
|
5
|
+
* string, an `only: ['stack']` partial reload, and the preserve flags that
|
|
6
|
+
* keep the page underneath mounted. Every caller that re-typed that trio was
|
|
7
|
+
* a chance to get one third of it wrong, and one did: a hand-written
|
|
8
|
+
* `X-Drawer` header meant the server never took the drawer path, while
|
|
9
|
+
* `only: ['stack']` still fetched enough for the drawer to *look* right.
|
|
10
|
+
*
|
|
11
|
+
* So this is the only place the trio is written. Anything that opens, drills
|
|
12
|
+
* into, or closes a drawer goes through here.
|
|
13
|
+
*/
|
|
14
|
+
export interface VisitDrawerOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Appended to the URL — the listing's filter/sort state, so a drawer's
|
|
17
|
+
* record pagination stays inside the set the reader was looking at.
|
|
18
|
+
*/
|
|
19
|
+
queryParams?: Record<string, unknown>;
|
|
20
|
+
/** Inertia partial-reload keys. Defaults to the stack alone. */
|
|
21
|
+
only?: string[];
|
|
22
|
+
preserveState?: boolean;
|
|
23
|
+
preserveScroll?: boolean;
|
|
24
|
+
replace?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The visit options a drawer navigation needs, for the rare caller that must
|
|
28
|
+
* hand them to Inertia itself (a form submission, say) rather than navigate.
|
|
29
|
+
*/
|
|
30
|
+
export declare function drawerVisitOptions(options?: VisitDrawerOptions): {
|
|
31
|
+
headers: {
|
|
32
|
+
"X-Inertia-Drawer-Stack": string;
|
|
33
|
+
};
|
|
34
|
+
replace?: boolean | undefined;
|
|
35
|
+
only: string[];
|
|
36
|
+
preserveState: boolean;
|
|
37
|
+
preserveScroll: boolean;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Append query parameters to a URL.
|
|
41
|
+
*
|
|
42
|
+
* Empty strings are kept: the server distinguishes "this filter is set to
|
|
43
|
+
* nothing" from "this filter was not sent", and dropping them silently reset
|
|
44
|
+
* filters when a drawer opened.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withDrawerParams(url: string, params?: Record<string, unknown>): string;
|
|
47
|
+
/** Navigate the drawer stack: open, drill into, go back, or close. */
|
|
48
|
+
export declare function visitDrawer(url: string, options?: VisitDrawerOptions): void;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { PropType } from 'vue';
|
|
2
|
+
declare var __VLS_1: {
|
|
3
|
+
option: any;
|
|
4
|
+
};
|
|
5
|
+
type __VLS_Slots = {} & {
|
|
6
|
+
option?: (props: typeof __VLS_1) => any;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_base: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
|
|
9
|
+
modelValue: {
|
|
10
|
+
type: (StringConstructor | NumberConstructor | null)[];
|
|
11
|
+
default: null;
|
|
12
|
+
};
|
|
13
|
+
label: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
default: string;
|
|
16
|
+
};
|
|
17
|
+
placeholder: {
|
|
18
|
+
type: StringConstructor;
|
|
19
|
+
default: string;
|
|
20
|
+
};
|
|
21
|
+
helperText: {
|
|
22
|
+
type: StringConstructor;
|
|
23
|
+
default: string;
|
|
24
|
+
};
|
|
25
|
+
error: {
|
|
26
|
+
type: StringConstructor;
|
|
27
|
+
default: string;
|
|
28
|
+
};
|
|
29
|
+
required: {
|
|
30
|
+
type: BooleanConstructor;
|
|
31
|
+
default: boolean;
|
|
32
|
+
};
|
|
33
|
+
disabled: {
|
|
34
|
+
type: BooleanConstructor;
|
|
35
|
+
default: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Options array or endpoint for fetching options
|
|
39
|
+
*/
|
|
40
|
+
options: {
|
|
41
|
+
type: PropType<any[]>;
|
|
42
|
+
default: () => never[];
|
|
43
|
+
};
|
|
44
|
+
endpoint: {
|
|
45
|
+
type: StringConstructor;
|
|
46
|
+
default: null;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Server-side search endpoint for a relation too large to preload.
|
|
50
|
+
*
|
|
51
|
+
* Answers `?q=` with matches and `?values=` with the labels for identifiers
|
|
52
|
+
* the field already holds — the second is what lets an edit form show its
|
|
53
|
+
* current selection when the list it came from was never sent.
|
|
54
|
+
*/
|
|
55
|
+
searchUrl: {
|
|
56
|
+
type: StringConstructor;
|
|
57
|
+
default: null;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Offer an explicit way back to "no selection".
|
|
61
|
+
*
|
|
62
|
+
* A lookup can otherwise only ever tighten: once a value is chosen, the
|
|
63
|
+
* input shows its label and there is nothing to press to mean "none". Set
|
|
64
|
+
* for optional relations.
|
|
65
|
+
*/
|
|
66
|
+
clearable: {
|
|
67
|
+
type: BooleanConstructor;
|
|
68
|
+
default: boolean;
|
|
69
|
+
};
|
|
70
|
+
relationship: {
|
|
71
|
+
type: StringConstructor;
|
|
72
|
+
default: null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Keys for option object
|
|
76
|
+
*/
|
|
77
|
+
valueKey: {
|
|
78
|
+
type: StringConstructor;
|
|
79
|
+
default: string;
|
|
80
|
+
};
|
|
81
|
+
labelKey: {
|
|
82
|
+
type: StringConstructor;
|
|
83
|
+
default: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Search configuration
|
|
87
|
+
*/
|
|
88
|
+
searchable: {
|
|
89
|
+
type: BooleanConstructor;
|
|
90
|
+
default: boolean;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Allow creating new records
|
|
94
|
+
*/
|
|
95
|
+
allowCreate: {
|
|
96
|
+
type: BooleanConstructor;
|
|
97
|
+
default: boolean;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Minimum characters before searching
|
|
101
|
+
*/
|
|
102
|
+
minSearchLength: {
|
|
103
|
+
type: NumberConstructor;
|
|
104
|
+
default: number;
|
|
105
|
+
};
|
|
106
|
+
width: {
|
|
107
|
+
readonly type: StringConstructor;
|
|
108
|
+
readonly default: "full";
|
|
109
|
+
readonly validator: (v: string) => boolean;
|
|
110
|
+
};
|
|
111
|
+
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
112
|
+
"update:modelValue": (...args: any[]) => void;
|
|
113
|
+
create: (...args: any[]) => void;
|
|
114
|
+
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
|
|
115
|
+
modelValue: {
|
|
116
|
+
type: (StringConstructor | NumberConstructor | null)[];
|
|
117
|
+
default: null;
|
|
118
|
+
};
|
|
119
|
+
label: {
|
|
120
|
+
type: StringConstructor;
|
|
121
|
+
default: string;
|
|
122
|
+
};
|
|
123
|
+
placeholder: {
|
|
124
|
+
type: StringConstructor;
|
|
125
|
+
default: string;
|
|
126
|
+
};
|
|
127
|
+
helperText: {
|
|
128
|
+
type: StringConstructor;
|
|
129
|
+
default: string;
|
|
130
|
+
};
|
|
131
|
+
error: {
|
|
132
|
+
type: StringConstructor;
|
|
133
|
+
default: string;
|
|
134
|
+
};
|
|
135
|
+
required: {
|
|
136
|
+
type: BooleanConstructor;
|
|
137
|
+
default: boolean;
|
|
138
|
+
};
|
|
139
|
+
disabled: {
|
|
140
|
+
type: BooleanConstructor;
|
|
141
|
+
default: boolean;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Options array or endpoint for fetching options
|
|
145
|
+
*/
|
|
146
|
+
options: {
|
|
147
|
+
type: PropType<any[]>;
|
|
148
|
+
default: () => never[];
|
|
149
|
+
};
|
|
150
|
+
endpoint: {
|
|
151
|
+
type: StringConstructor;
|
|
152
|
+
default: null;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Server-side search endpoint for a relation too large to preload.
|
|
156
|
+
*
|
|
157
|
+
* Answers `?q=` with matches and `?values=` with the labels for identifiers
|
|
158
|
+
* the field already holds — the second is what lets an edit form show its
|
|
159
|
+
* current selection when the list it came from was never sent.
|
|
160
|
+
*/
|
|
161
|
+
searchUrl: {
|
|
162
|
+
type: StringConstructor;
|
|
163
|
+
default: null;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Offer an explicit way back to "no selection".
|
|
167
|
+
*
|
|
168
|
+
* A lookup can otherwise only ever tighten: once a value is chosen, the
|
|
169
|
+
* input shows its label and there is nothing to press to mean "none". Set
|
|
170
|
+
* for optional relations.
|
|
171
|
+
*/
|
|
172
|
+
clearable: {
|
|
173
|
+
type: BooleanConstructor;
|
|
174
|
+
default: boolean;
|
|
175
|
+
};
|
|
176
|
+
relationship: {
|
|
177
|
+
type: StringConstructor;
|
|
178
|
+
default: null;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Keys for option object
|
|
182
|
+
*/
|
|
183
|
+
valueKey: {
|
|
184
|
+
type: StringConstructor;
|
|
185
|
+
default: string;
|
|
186
|
+
};
|
|
187
|
+
labelKey: {
|
|
188
|
+
type: StringConstructor;
|
|
189
|
+
default: string;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Search configuration
|
|
193
|
+
*/
|
|
194
|
+
searchable: {
|
|
195
|
+
type: BooleanConstructor;
|
|
196
|
+
default: boolean;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Allow creating new records
|
|
200
|
+
*/
|
|
201
|
+
allowCreate: {
|
|
202
|
+
type: BooleanConstructor;
|
|
203
|
+
default: boolean;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Minimum characters before searching
|
|
207
|
+
*/
|
|
208
|
+
minSearchLength: {
|
|
209
|
+
type: NumberConstructor;
|
|
210
|
+
default: number;
|
|
211
|
+
};
|
|
212
|
+
width: {
|
|
213
|
+
readonly type: StringConstructor;
|
|
214
|
+
readonly default: "full";
|
|
215
|
+
readonly validator: (v: string) => boolean;
|
|
216
|
+
};
|
|
217
|
+
}>> & Readonly<{
|
|
218
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
219
|
+
onCreate?: ((...args: any[]) => any) | undefined;
|
|
220
|
+
}>, {
|
|
221
|
+
required: boolean;
|
|
222
|
+
modelValue: string | number | null;
|
|
223
|
+
label: string;
|
|
224
|
+
placeholder: string;
|
|
225
|
+
error: string;
|
|
226
|
+
disabled: boolean;
|
|
227
|
+
width: string;
|
|
228
|
+
options: any[];
|
|
229
|
+
searchable: boolean;
|
|
230
|
+
searchUrl: string;
|
|
231
|
+
endpoint: string;
|
|
232
|
+
relationship: string;
|
|
233
|
+
helperText: string;
|
|
234
|
+
clearable: boolean;
|
|
235
|
+
valueKey: string;
|
|
236
|
+
labelKey: string;
|
|
237
|
+
allowCreate: boolean;
|
|
238
|
+
minSearchLength: number;
|
|
239
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
240
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
241
|
+
declare const _default: typeof __VLS_export;
|
|
242
|
+
export default _default;
|
|
243
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
244
|
+
new (): {
|
|
245
|
+
$slots: S;
|
|
246
|
+
};
|
|
247
|
+
};
|