@lattice-php/lattice 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action/components/action-form.d.ts +6 -1
- package/dist/action/components/action-form.js +34 -49
- package/dist/action/components/action-form.js.map +1 -1
- package/dist/action/components/action-trigger-provider.d.ts +1 -1
- package/dist/action/components/action-trigger-provider.js.map +1 -1
- package/dist/action/hooks/use-action.d.ts +1 -1
- package/dist/action/hooks/use-action.js +3 -1
- package/dist/action/hooks/use-action.js.map +1 -1
- package/dist/action/index.d.ts +0 -2
- package/dist/action/index.js +1 -2
- package/dist/chat/plugin.d.ts +0 -1
- package/dist/chat/plugin.js.map +1 -1
- package/dist/clipboard/index.d.ts +0 -4
- package/dist/clipboard/index.js +1 -15
- package/dist/{events → core}/event-names.js +1 -1
- package/dist/core/event-names.js.map +1 -0
- package/dist/core/hooks/use-window-event.d.ts +8 -0
- package/dist/core/hooks/use-window-event.js +22 -0
- package/dist/core/hooks/use-window-event.js.map +1 -0
- package/dist/core/index.js +1 -1
- package/dist/core/types.d.ts +8 -61
- package/dist/create-app.d.ts +31 -3
- package/dist/create-app.js +48 -10
- package/dist/create-app.js.map +1 -1
- package/dist/effects/dispatch.js +1 -1
- package/dist/effects/dispatch.js.map +1 -1
- package/dist/effects/registry.d.ts +2 -18
- package/dist/effects/registry.js +5 -9
- package/dist/effects/registry.js.map +1 -1
- package/dist/event-bridge.js +10 -23
- package/dist/event-bridge.js.map +1 -1
- package/dist/form/components/base/field.d.ts +2 -2
- package/dist/form/components/base/field.js +2 -2
- package/dist/form/components/base/field.js.map +1 -1
- package/dist/form/components/fields/color-picker-field.d.ts +2 -0
- package/dist/form/components/fields/color-picker-field.js +57 -0
- package/dist/form/components/fields/color-picker-field.js.map +1 -0
- package/dist/form/components/fields/date-input.js +1 -1
- package/dist/form/components/fields/date-time-input.js +1 -1
- package/dist/form/components/fields/file-upload.js +11 -18
- package/dist/form/components/fields/file-upload.js.map +1 -1
- package/dist/form/components/fields/number-input.js +1 -1
- package/dist/form/components/fields/rich-editor-field.js +35 -276
- package/dist/form/components/fields/rich-editor-field.js.map +1 -1
- package/dist/form/components/fields/row-action-menu.js +2 -2
- package/dist/form/components/fields/row-action-menu.js.map +1 -1
- package/dist/form/components/fields/row-actions.js +3 -1
- package/dist/form/components/fields/row-actions.js.map +1 -1
- package/dist/form/components/fields/select.js +60 -17
- package/dist/form/components/fields/select.js.map +1 -1
- package/dist/form/components/fields/table-rows.js +5 -17
- package/dist/form/components/fields/table-rows.js.map +1 -1
- package/dist/form/components/fields/text-input.js +8 -1
- package/dist/form/components/fields/text-input.js.map +1 -1
- package/dist/form/components/fields/time-input.js +1 -1
- package/dist/form/components/form.js +8 -23
- package/dist/form/components/form.js.map +1 -1
- package/dist/form/components/index.d.ts +1 -0
- package/dist/form/components/index.js +2 -1
- package/dist/form/embed.d.ts +5 -0
- package/dist/form/embed.js +4 -1
- package/dist/form/hooks/use-form-resolver.js.map +1 -1
- package/dist/form/index.js +2 -1
- package/dist/form/lib/collect-fields.d.ts +7 -0
- package/dist/form/lib/collect-fields.js +19 -0
- package/dist/form/lib/collect-fields.js.map +1 -0
- package/dist/form/lib/conditions.d.ts +4 -10
- package/dist/form/lib/conditions.js.map +1 -1
- package/dist/form/lib/field-errors.d.ts +3 -0
- package/dist/form/lib/field-errors.js +11 -0
- package/dist/form/lib/field-errors.js.map +1 -0
- package/dist/form/lib/field-props.d.ts +4 -18
- package/dist/form/lib/field-props.js.map +1 -1
- package/dist/form/plugin.js +2 -0
- package/dist/form/plugin.js.map +1 -1
- package/dist/form/rich-editor/builtins.d.ts +6 -0
- package/dist/form/rich-editor/builtins.js +400 -0
- package/dist/form/rich-editor/builtins.js.map +1 -0
- package/dist/form/rich-editor/index.d.ts +7 -0
- package/dist/form/rich-editor/index.js +3 -0
- package/dist/form/rich-editor/registry.d.ts +67 -0
- package/dist/form/rich-editor/registry.js +79 -0
- package/dist/form/rich-editor/registry.js.map +1 -0
- package/dist/form/rich-editor/toolbar-button.d.ts +12 -0
- package/dist/form/rich-editor/toolbar-button.js +28 -0
- package/dist/form/rich-editor/toolbar-button.js.map +1 -0
- package/dist/form/types.d.ts +1 -6
- package/dist/format/date-time.d.ts +3 -2
- package/dist/format/date-time.js.map +1 -1
- package/dist/format/format-context.d.ts +6 -0
- package/dist/format/format-context.js +17 -0
- package/dist/format/format-context.js.map +1 -0
- package/dist/i18n/date-time.d.ts +3 -2
- package/dist/i18n/date-time.js.map +1 -1
- package/dist/i18n/index.js +3 -2
- package/dist/i18n/locale-reload.d.ts +1 -1
- package/dist/i18n/locale-reload.js +7 -6
- package/dist/i18n/locale-reload.js.map +1 -1
- package/dist/i18n/locale.js +1 -1
- package/dist/i18n/locale.js.map +1 -1
- package/dist/i18n/page-props.d.ts +3 -2
- package/dist/i18n/page-props.js +1 -15
- package/dist/i18n/page-props.js.map +1 -1
- package/dist/i18n/shared-props.d.ts +7 -0
- package/dist/i18n/shared-props.js +23 -0
- package/dist/i18n/shared-props.js.map +1 -0
- package/dist/i18n/timezone.js +1 -1
- package/dist/i18n/timezone.js.map +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.js +5 -5
- package/dist/lattice.css +212 -47
- package/dist/layout/components/breadcrumbs.js +3 -1
- package/dist/layout/components/breadcrumbs.js.map +1 -1
- package/dist/layout/components/sidebar.js +15 -48
- package/dist/layout/components/sidebar.js.map +1 -1
- package/dist/layout/plugin.d.ts +0 -1
- package/dist/layout/plugin.js.map +1 -1
- package/dist/lib/color.d.ts +9 -0
- package/dist/lib/color.js +48 -0
- package/dist/lib/color.js.map +1 -0
- package/dist/lib/is-truthy.d.ts +2 -0
- package/dist/lib/is-truthy.js +9 -0
- package/dist/lib/is-truthy.js.map +1 -0
- package/dist/lib/use-debounced-callback.d.ts +10 -0
- package/dist/lib/use-debounced-callback.js +34 -0
- package/dist/lib/use-debounced-callback.js.map +1 -0
- package/dist/lib/use-media-query.d.ts +5 -0
- package/dist/lib/use-media-query.js +26 -0
- package/dist/lib/use-media-query.js.map +1 -0
- package/dist/lib/use-persistent-state.d.ts +13 -0
- package/dist/lib/use-persistent-state.js +62 -0
- package/dist/lib/use-persistent-state.js.map +1 -0
- package/dist/notifications/api.d.ts +6 -6
- package/dist/notifications/api.js.map +1 -1
- package/dist/notifications/components/notifications.js +3 -1
- package/dist/notifications/components/notifications.js.map +1 -1
- package/dist/notifications/plugin.d.ts +0 -1
- package/dist/notifications/plugin.js.map +1 -1
- package/dist/notifications/types.d.ts +2 -10
- package/dist/provider-base.js +1 -1
- package/dist/realtime/build-effects.js +5 -5
- package/dist/realtime/build-effects.js.map +1 -1
- package/dist/realtime/listeners.d.ts +2 -2
- package/dist/realtime/listeners.js +1 -1
- package/dist/realtime/listeners.js.map +1 -1
- package/dist/realtime/subscriptions.d.ts +2 -2
- package/dist/realtime/subscriptions.js.map +1 -1
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/components/data-list.js +1 -1
- package/dist/remote/plugin.d.ts +0 -1
- package/dist/remote/plugin.js.map +1 -1
- package/dist/table/components/bulk-bar.js +7 -5
- package/dist/table/components/bulk-bar.js.map +1 -1
- package/dist/table/components/cells/badge-cell.js +4 -1
- package/dist/table/components/cells/badge-cell.js.map +1 -1
- package/dist/table/components/cells/boolean-cell.js +4 -4
- package/dist/table/components/cells/boolean-cell.js.map +1 -1
- package/dist/table/components/cells/copyable-cell.d.ts +9 -0
- package/dist/table/components/cells/copyable-cell.js +17 -0
- package/dist/table/components/cells/copyable-cell.js.map +1 -0
- package/dist/table/components/cells/icon-cell.js +5 -2
- package/dist/table/components/cells/icon-cell.js.map +1 -1
- package/dist/table/components/cells/image-cell.js +8 -9
- package/dist/table/components/cells/image-cell.js.map +1 -1
- package/dist/table/components/cells/money-cell.js +7 -10
- package/dist/table/components/cells/money-cell.js.map +1 -1
- package/dist/table/components/cells/number-cell.js +14 -19
- package/dist/table/components/cells/number-cell.js.map +1 -1
- package/dist/table/components/cells/numeric-cell.d.ts +10 -0
- package/dist/table/components/cells/numeric-cell.js +25 -0
- package/dist/table/components/cells/numeric-cell.js.map +1 -0
- package/dist/table/components/cells/stack-cell.js +1 -1
- package/dist/table/components/cells/text-cell.js +8 -6
- package/dist/table/components/cells/text-cell.js.map +1 -1
- package/dist/table/components/column-filter-control.js +25 -32
- package/dist/table/components/column-filter-control.js.map +1 -1
- package/dist/table/components/column-header.d.ts +3 -3
- package/dist/table/components/column-header.js +5 -3
- package/dist/table/components/column-header.js.map +1 -1
- package/dist/table/components/column-visibility-menu.js +6 -11
- package/dist/table/components/column-visibility-menu.js.map +1 -1
- package/dist/table/components/filter-bar.d.ts +2 -2
- package/dist/table/components/filter-bar.js +13 -22
- package/dist/table/components/filter-bar.js.map +1 -1
- package/dist/table/components/filter-controls.d.ts +2 -1
- package/dist/table/components/filter-controls.js +37 -38
- package/dist/table/components/filter-controls.js.map +1 -1
- package/dist/table/components/filter-value-input.d.ts +0 -1
- package/dist/table/components/filter-value-input.js +21 -20
- package/dist/table/components/filter-value-input.js.map +1 -1
- package/dist/table/components/pagination.js +16 -20
- package/dist/table/components/pagination.js.map +1 -1
- package/dist/table/components/sort-bar.d.ts +3 -3
- package/dist/table/components/sort-bar.js +11 -12
- package/dist/table/components/sort-bar.js.map +1 -1
- package/dist/table/components/table-cell.js.map +1 -1
- package/dist/table/components/table-search.d.ts +9 -0
- package/dist/table/components/table-search.js +72 -0
- package/dist/table/components/table-search.js.map +1 -0
- package/dist/table/components/table.js +73 -21
- package/dist/table/components/table.js.map +1 -1
- package/dist/table/hooks/use-column-visibility.js +29 -58
- package/dist/table/hooks/use-column-visibility.js.map +1 -1
- package/dist/table/hooks/use-expanded-rows.d.ts +8 -0
- package/dist/table/hooks/use-expanded-rows.js +24 -0
- package/dist/table/hooks/use-expanded-rows.js.map +1 -0
- package/dist/table/hooks/use-table.d.ts +5 -3
- package/dist/table/hooks/use-table.js +59 -55
- package/dist/table/hooks/use-table.js.map +1 -1
- package/dist/table/lib/bulk.d.ts +2 -0
- package/dist/table/lib/bulk.js +3 -1
- package/dist/table/lib/bulk.js.map +1 -1
- package/dist/table/lib/payload.d.ts +3 -2
- package/dist/table/lib/payload.js +16 -10
- package/dist/table/lib/payload.js.map +1 -1
- package/dist/table/lib/query.d.ts +5 -5
- package/dist/table/lib/query.js +21 -19
- package/dist/table/lib/query.js.map +1 -1
- package/dist/table/plugin.d.ts +0 -1
- package/dist/table/plugin.js.map +1 -1
- package/dist/table/types.d.ts +5 -81
- package/dist/toast/callout.js +2 -4
- package/dist/toast/callout.js.map +1 -1
- package/dist/toast/index.d.ts +1 -1
- package/dist/toast/index.js +2 -2
- package/dist/toast/toast.d.ts +1 -7
- package/dist/toast/toast.js +3 -15
- package/dist/toast/toast.js.map +1 -1
- package/dist/toast/toaster.js.map +1 -1
- package/dist/types/generated.d.ts +444 -225
- package/dist/types/index.d.ts +1 -1
- package/dist/ui/affix-group.d.ts +2 -1
- package/dist/ui/affix-group.js +9 -7
- package/dist/ui/affix-group.js.map +1 -1
- package/dist/ui/avatar.d.ts +3 -0
- package/dist/ui/avatar.js +52 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/button.d.ts +5 -3
- package/dist/ui/button.js +10 -3
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/chart-view.js +155 -28
- package/dist/ui/chart-view.js.map +1 -1
- package/dist/ui/click-behavior.d.ts +4 -4
- package/dist/ui/click-behavior.js.map +1 -1
- package/dist/ui/collapsible.js +3 -15
- package/dist/ui/collapsible.js.map +1 -1
- package/dist/ui/color-picker.d.ts +8 -0
- package/dist/ui/color-picker.js +59 -0
- package/dist/ui/color-picker.js.map +1 -0
- package/dist/ui/combobox.d.ts +11 -2
- package/dist/ui/combobox.js +57 -11
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/confirm-dialog.js +1 -1
- package/dist/ui/confirm-dialog.js.map +1 -1
- package/dist/ui/control.d.ts +1 -1
- package/dist/ui/copyable-text.d.ts +7 -0
- package/dist/ui/copyable-text.js +21 -13
- package/dist/ui/copyable-text.js.map +1 -1
- package/dist/ui/dialog.d.ts +6 -2
- package/dist/ui/dialog.js +29 -5
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/fragment.js +1 -1
- package/dist/ui/fragment.js.map +1 -1
- package/dist/ui/heading.js +39 -21
- package/dist/ui/heading.js.map +1 -1
- package/dist/ui/icon-button.d.ts +22 -0
- package/dist/ui/icon-button.js +51 -0
- package/dist/ui/icon-button.js.map +1 -0
- package/dist/ui/icon.js +10 -11
- package/dist/ui/icon.js.map +1 -1
- package/dist/ui/image-preview.d.ts +12 -0
- package/dist/ui/image-preview.js +65 -0
- package/dist/ui/image-preview.js.map +1 -0
- package/dist/ui/image.d.ts +3 -0
- package/dist/ui/image.js +21 -0
- package/dist/ui/image.js.map +1 -0
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +4 -3
- package/dist/ui/info-tooltip.js +1 -1
- package/dist/ui/info-tooltip.js.map +1 -1
- package/dist/ui/input.d.ts +3 -1
- package/dist/ui/input.js +2 -2
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/modal.js +17 -4
- package/dist/ui/modal.js.map +1 -1
- package/dist/ui/native-select.d.ts +10 -0
- package/dist/ui/native-select.js +23 -0
- package/dist/ui/native-select.js.map +1 -0
- package/dist/ui/pill.d.ts +2 -0
- package/dist/ui/pill.js +10 -0
- package/dist/ui/pill.js.map +1 -0
- package/dist/ui/plugin.js +11 -1
- package/dist/ui/plugin.js.map +1 -1
- package/dist/ui/progress.d.ts +3 -0
- package/dist/ui/progress.js +114 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/section.js +2 -15
- package/dist/ui/section.js.map +1 -1
- package/dist/ui/segmented-pills.js +2 -1
- package/dist/ui/segmented-pills.js.map +1 -1
- package/dist/ui/separator.d.ts +3 -0
- package/dist/ui/separator.js +15 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/tabs.js +12 -10
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/text.js +5 -10
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/tree-context.d.ts +33 -0
- package/dist/ui/tree-context.js +135 -0
- package/dist/ui/tree-context.js.map +1 -0
- package/dist/ui/tree.d.ts +19 -0
- package/dist/ui/tree.js +187 -0
- package/dist/ui/tree.js.map +1 -0
- package/dist/ui/use-collapsible-state.d.ts +7 -0
- package/dist/ui/use-collapsible-state.js +21 -0
- package/dist/ui/use-collapsible-state.js.map +1 -0
- package/dist-standalone/chunks/chart-view-C6R5iPra.js +36 -0
- package/dist-standalone/chunks/date-picker-field-DhhEB-Mh.js +1 -0
- package/dist-standalone/chunks/jsx-runtime-Drll_-DD.js +1 -0
- package/dist-standalone/chunks/locale-CXqr7LPR.js +1 -0
- package/dist-standalone/chunks/page-props-DOfg30l5.js +1 -0
- package/dist-standalone/chunks/rich-editor-field-DORXTHPw.js +154 -0
- package/dist-standalone/chunks/{subscriptions-B3UuDBmx.js → subscriptions-B_ISgA7V.js} +1 -1
- package/dist-standalone/chunks/use-effect-dispatcher-D1wPPwHj.js +97 -0
- package/dist-standalone/lattice.css +1 -1
- package/dist-standalone/lattice.js +15 -15
- package/dist-standalone/manifest.json +11 -9
- package/dist-standalone/sprite.svg +1 -1
- package/package.json +6 -1
- package/resources/icons/code-xml.svg +17 -0
- package/resources/icons/heading.svg +17 -0
- package/dist/clipboard/index.js.map +0 -1
- package/dist/events/event-names.js.map +0 -1
- package/dist/table/components/table-action-node.d.ts +0 -4
- package/dist/table/components/table-action-node.js +0 -24
- package/dist/table/components/table-action-node.js.map +0 -1
- package/dist-standalone/chunks/chart-view-CK5fKIkR.js +0 -36
- package/dist-standalone/chunks/date-picker-field-BlCPFhZd.js +0 -1
- package/dist-standalone/chunks/jsx-runtime-CJ_btYLc.js +0 -1
- package/dist-standalone/chunks/rich-editor-field-DH5dS5c1.js +0 -154
- package/dist-standalone/chunks/use-effect-dispatcher-k98Nzf9M.js +0 -97
- /package/dist/{events → core}/event-names.d.ts +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { DialogPlacement } from '../../ui/dialog.js';
|
|
1
2
|
import { Node } from '../../core/types.js';
|
|
3
|
+
import { ModalWidth } from '../../types/generated.js';
|
|
2
4
|
import { ActionResponse } from '../../effects/dispatch.js';
|
|
3
5
|
type ActionFormProps = {
|
|
4
6
|
cancelLabel: string;
|
|
@@ -12,13 +14,16 @@ type ActionFormProps = {
|
|
|
12
14
|
method: string;
|
|
13
15
|
onClose: () => void;
|
|
14
16
|
onSuccess: (response: ActionResponse) => void;
|
|
17
|
+
/** Dialog placement for the form modal; sheets dock to a viewport edge. */
|
|
18
|
+
placement?: DialogPlacement;
|
|
15
19
|
submitLabel: string;
|
|
16
20
|
title: string;
|
|
21
|
+
width?: ModalWidth;
|
|
17
22
|
};
|
|
18
23
|
/**
|
|
19
24
|
* Fetch a lazily-served form schema from the action endpoint while `enabled`,
|
|
20
25
|
* so it can be prefilled per record. Returns null until it arrives.
|
|
21
26
|
*/
|
|
22
27
|
export declare function useLazyActionForm(endpoint: string, componentRef: string, enabled: boolean): Node | null;
|
|
23
|
-
export declare function ActionForm({ description, formNode, onClose, title, ...rest }: ActionFormProps): import("react").JSX.Element;
|
|
28
|
+
export declare function ActionForm({ description, formNode, onClose, placement, title, width, ...rest }: ActionFormProps): import("react").JSX.Element;
|
|
24
29
|
export {};
|
|
@@ -8,11 +8,13 @@ import { apiFetch } from "../../core/api.js";
|
|
|
8
8
|
import { Skeleton } from "../../ui/skeleton.js";
|
|
9
9
|
import { FormProvider } from "../../form/hooks/context.js";
|
|
10
10
|
import { PrefillProvider } from "../../form/hooks/prefill-context.js";
|
|
11
|
-
import { walkFields } from "../../form/lib/field-props.js";
|
|
12
11
|
import { ResolvedNodesProvider } from "../../form/hooks/resolved-nodes.js";
|
|
13
12
|
import { FormValuesProvider, useFormValues } from "../../form/hooks/values.js";
|
|
14
13
|
import "../../form/lib/form-transport.js";
|
|
15
14
|
import { useFormResolver } from "../../form/hooks/use-form-resolver.js";
|
|
15
|
+
import { collectFields } from "../../form/lib/collect-fields.js";
|
|
16
|
+
import { firstErrors } from "../../form/lib/field-errors.js";
|
|
17
|
+
import { useDebouncedCallback } from "../../lib/use-debounced-callback.js";
|
|
16
18
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
20
|
//#region resources/js/action/components/action-form.tsx
|
|
@@ -43,11 +45,6 @@ function useLazyActionForm(endpoint, componentRef, enabled) {
|
|
|
43
45
|
]);
|
|
44
46
|
return node;
|
|
45
47
|
}
|
|
46
|
-
function firstErrors(errors) {
|
|
47
|
-
const result = {};
|
|
48
|
-
for (const [key, value] of Object.entries(errors ?? {})) result[key] = Array.isArray(value) ? value[0] : value;
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
48
|
function ActionFormSkeleton() {
|
|
52
49
|
return /* @__PURE__ */ jsxs("div", {
|
|
53
50
|
className: "space-y-4",
|
|
@@ -59,22 +56,6 @@ function ActionFormSkeleton() {
|
|
|
59
56
|
]
|
|
60
57
|
});
|
|
61
58
|
}
|
|
62
|
-
function collectFields(formNode) {
|
|
63
|
-
const labels = {};
|
|
64
|
-
const values = {};
|
|
65
|
-
walkFields(formNode.schema, (props) => {
|
|
66
|
-
if (!props.name) return;
|
|
67
|
-
if (props.label) labels[props.name] = props.label;
|
|
68
|
-
if (props.value !== void 0) values[props.name] = props.value;
|
|
69
|
-
});
|
|
70
|
-
return {
|
|
71
|
-
labels,
|
|
72
|
-
values: {
|
|
73
|
-
...values,
|
|
74
|
-
...formNode.props?.state
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
59
|
function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldLabels, formNode, method, onClose, onSuccess, precognitive, submitLabel }) {
|
|
79
60
|
const values = useFormValues();
|
|
80
61
|
const valuesRef = useRef(values);
|
|
@@ -84,7 +65,6 @@ function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldL
|
|
|
84
65
|
const { nodes: resolvedNodes, markUserEdit } = useFormResolver(endpoint, componentRef, formNode.schema);
|
|
85
66
|
const [errors, setErrors] = useState({});
|
|
86
67
|
const [processing, setProcessing] = useState(false);
|
|
87
|
-
const timer = useRef(void 0);
|
|
88
68
|
const request = useCallback((extraHeaders) => apiFetch(endpoint, {
|
|
89
69
|
body: JSON.stringify({
|
|
90
70
|
...valuesRef.current,
|
|
@@ -105,30 +85,25 @@ function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldL
|
|
|
105
85
|
[field]: void 0
|
|
106
86
|
});
|
|
107
87
|
}, []);
|
|
88
|
+
const runValidation = useDebouncedCallback((field) => {
|
|
89
|
+
request({
|
|
90
|
+
Precognition: "true",
|
|
91
|
+
"Precognition-Validate-Only": field
|
|
92
|
+
}).then(async (response) => {
|
|
93
|
+
if (response.status === 422) {
|
|
94
|
+
const body = await response.json();
|
|
95
|
+
setErrors((current) => ({
|
|
96
|
+
...current,
|
|
97
|
+
...firstErrors(body.errors)
|
|
98
|
+
}));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
clearErrors(field);
|
|
102
|
+
}).catch(() => {});
|
|
103
|
+
}, 250);
|
|
108
104
|
const validate = useCallback((field) => {
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
timer.current = window.setTimeout(() => {
|
|
112
|
-
request({
|
|
113
|
-
Precognition: "true",
|
|
114
|
-
"Precognition-Validate-Only": field
|
|
115
|
-
}).then(async (response) => {
|
|
116
|
-
if (response.status === 422) {
|
|
117
|
-
const body = await response.json();
|
|
118
|
-
setErrors((current) => ({
|
|
119
|
-
...current,
|
|
120
|
-
...firstErrors(body.errors)
|
|
121
|
-
}));
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
clearErrors(field);
|
|
125
|
-
}).catch(() => {});
|
|
126
|
-
}, 250);
|
|
127
|
-
}, [
|
|
128
|
-
clearErrors,
|
|
129
|
-
precognitive,
|
|
130
|
-
request
|
|
131
|
-
]);
|
|
105
|
+
if (precognitive) runValidation(field);
|
|
106
|
+
}, [precognitive, runValidation]);
|
|
132
107
|
const submit = useCallback(() => {
|
|
133
108
|
setProcessing(true);
|
|
134
109
|
request().then(async (response) => {
|
|
@@ -196,7 +171,16 @@ function ActionFormBody({ cancelLabel, componentRef, endpoint, extraData, fieldL
|
|
|
196
171
|
}
|
|
197
172
|
function ActionFormContent({ formNode, ...rest }) {
|
|
198
173
|
const precognitive = Boolean(formNode.props?.precognitive);
|
|
199
|
-
const { labels: fieldLabels, values: initialValues } = useMemo(() =>
|
|
174
|
+
const { labels: fieldLabels, values: initialValues } = useMemo(() => {
|
|
175
|
+
const { labels, values } = collectFields(formNode.schema);
|
|
176
|
+
return {
|
|
177
|
+
labels,
|
|
178
|
+
values: {
|
|
179
|
+
...values,
|
|
180
|
+
...formNode.props?.state
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}, [formNode]);
|
|
200
184
|
return /* @__PURE__ */ jsx(FormValuesProvider, {
|
|
201
185
|
initial: initialValues,
|
|
202
186
|
children: /* @__PURE__ */ jsx(ActionFormBody, {
|
|
@@ -207,7 +191,7 @@ function ActionFormContent({ formNode, ...rest }) {
|
|
|
207
191
|
})
|
|
208
192
|
});
|
|
209
193
|
}
|
|
210
|
-
function ActionForm({ description, formNode, onClose, title, ...rest }) {
|
|
194
|
+
function ActionForm({ description, formNode, onClose, placement, title, width, ...rest }) {
|
|
211
195
|
const { t } = useT("lattice");
|
|
212
196
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
213
197
|
open: true,
|
|
@@ -216,7 +200,8 @@ function ActionForm({ description, formNode, onClose, title, ...rest }) {
|
|
|
216
200
|
},
|
|
217
201
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
218
202
|
...description ? {} : { "aria-describedby": void 0 },
|
|
219
|
-
|
|
203
|
+
placement,
|
|
204
|
+
width,
|
|
220
205
|
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
221
206
|
closeLabel: t("common.close", "Close"),
|
|
222
207
|
description,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-form.js","names":[],"sources":["../../../resources/js/action/components/action-form.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/ui/dialog\";\nimport { Skeleton } from \"@lattice-php/lattice/ui/skeleton\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport {\n FORM_DEBOUNCE_MS,\n FormProvider,\n FormValuesProvider,\n PrefillProvider,\n ResolvedNodesProvider,\n useFormResolver,\n useFormValues,\n walkFields,\n} from \"@lattice-php/lattice/form/embed\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { dispatchActionError } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\n\ntype FieldErrors = Record<string, string | undefined>;\n\ntype ActionFormProps = {\n cancelLabel: string;\n componentRef: string;\n description?: string;\n endpoint: string;\n /** Extra payload merged into every request, e.g. a bulk action's selection. */\n extraData?: Record<string, unknown>;\n /** The form to render; null while a lazy schema is still being fetched. */\n formNode: Node | null;\n method: string;\n onClose: () => void;\n onSuccess: (response: ActionResponse) => void;\n submitLabel: string;\n title: string;\n};\n\n/**\n * Fetch a lazily-served form schema from the action endpoint while `enabled`,\n * so it can be prefilled per record. Returns null until it arrives.\n */\nexport function useLazyActionForm(\n endpoint: string,\n componentRef: string,\n enabled: boolean,\n): Node | null {\n const [node, setNode] = useState<Node | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n setNode(null);\n\n return;\n }\n\n const controller = new AbortController();\n\n void apiFetch(endpoint, {\n body: JSON.stringify({ _form: true }),\n ref: componentRef,\n method: \"POST\",\n signal: controller.signal,\n throwOnError: false,\n })\n .then((response) => (response.ok ? (response.json() as Promise<Node>) : null))\n .then((fetched) => setNode(fetched))\n .catch(() => {});\n\n return () => controller.abort();\n }, [enabled, endpoint, componentRef]);\n\n return node;\n}\n\nfunction firstErrors(errors: Record<string, string[] | string> | undefined): FieldErrors {\n const result: FieldErrors = {};\n\n for (const [key, value] of Object.entries(errors ?? {})) {\n result[key] = Array.isArray(value) ? value[0] : value;\n }\n\n return result;\n}\n\nfunction ActionFormSkeleton() {\n return (\n <div className=\"space-y-4\" data-lattice-action-form-loading>\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n );\n}\n\ntype CollectedFields = {\n labels: Record<string, string>;\n values: Record<string, unknown>;\n};\n\nfunction collectFields(formNode: Node): CollectedFields {\n const labels: Record<string, string> = {};\n const values: Record<string, unknown> = {};\n\n walkFields(formNode.schema, (props) => {\n if (!props.name) {\n return;\n }\n if (props.label) {\n labels[props.name] = props.label;\n }\n if (props.value !== undefined) {\n values[props.name] = props.value;\n }\n });\n\n return {\n labels,\n values: { ...values, ...(formNode.props?.state as Record<string, unknown> | undefined) },\n };\n}\n\nfunction ActionFormBody({\n cancelLabel,\n componentRef,\n endpoint,\n extraData,\n fieldLabels,\n formNode,\n method,\n onClose,\n onSuccess,\n precognitive,\n submitLabel,\n}: Omit<ActionFormProps, \"description\" | \"title\"> & {\n fieldLabels: Record<string, string>;\n formNode: Node;\n precognitive: boolean;\n}) {\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const extraDataRef = useRef(extraData);\n extraDataRef.current = extraData;\n const { nodes: resolvedNodes, markUserEdit } = useFormResolver(\n endpoint,\n componentRef,\n formNode.schema,\n );\n\n const [errors, setErrors] = useState<FieldErrors>({});\n const [processing, setProcessing] = useState(false);\n const timer = useRef<number | undefined>(undefined);\n\n const request = useCallback(\n (extraHeaders?: Record<string, string>): Promise<Response> =>\n apiFetch(endpoint, {\n body: JSON.stringify({ ...valuesRef.current, ...extraDataRef.current }),\n method,\n ref: componentRef,\n headers: extraHeaders,\n throwOnError: false,\n }),\n [componentRef, endpoint, method],\n );\n\n const clearErrors = useCallback((field: string) => {\n setErrors((current) =>\n current[field] === undefined ? current : { ...current, [field]: undefined },\n );\n }, []);\n\n const validate = useCallback(\n (field: string) => {\n if (!precognitive) {\n return;\n }\n\n window.clearTimeout(timer.current);\n timer.current = window.setTimeout(() => {\n void request({ Precognition: \"true\", \"Precognition-Validate-Only\": field })\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors((current) => ({ ...current, ...firstErrors(body.errors) }));\n\n return;\n }\n\n clearErrors(field);\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n },\n [clearErrors, precognitive, request],\n );\n\n const submit = useCallback(() => {\n setProcessing(true);\n\n void request()\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors(firstErrors(body.errors));\n\n return;\n }\n\n if (!response.ok) {\n dispatchActionError(new Error(`Action request failed with status ${response.status}`));\n\n return;\n }\n\n onSuccess((await response.json()) as ActionResponse);\n })\n .catch((error: unknown) => dispatchActionError(error))\n .finally(() => setProcessing(false));\n }, [onSuccess, request]);\n\n const context = useMemo(\n () => ({\n action: endpoint,\n clearErrors,\n componentRef,\n errors,\n fieldLabels,\n precognitive,\n processing,\n validate,\n }),\n [clearErrors, componentRef, endpoint, errors, fieldLabels, precognitive, processing, validate],\n );\n\n return (\n <FormProvider value={context}>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n <PrefillProvider value={{ markUserEdit }}>\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <Renderer nodes={formNode.schema ?? []} />\n </ResolvedNodesProvider>\n </PrefillProvider>\n\n <div className=\"flex justify-end gap-3\">\n <Button\n data-test=\"action-form-cancel\"\n disabled={processing}\n onClick={onClose}\n type=\"button\"\n variant=\"ghost\"\n >\n {cancelLabel}\n </Button>\n\n <Button data-test=\"action-form-submit\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {submitLabel}\n </Button>\n </div>\n </form>\n </FormProvider>\n );\n}\n\nfunction ActionFormContent({\n formNode,\n ...rest\n}: Omit<ActionFormProps, \"description\" | \"title\"> & { formNode: Node }) {\n const precognitive = Boolean(formNode.props?.precognitive);\n const { labels: fieldLabels, values: initialValues } = useMemo(\n () => collectFields(formNode),\n [formNode],\n );\n\n return (\n <FormValuesProvider initial={initialValues}>\n <ActionFormBody\n fieldLabels={fieldLabels}\n formNode={formNode}\n precognitive={precognitive}\n {...rest}\n />\n </FormValuesProvider>\n );\n}\n\nexport function ActionForm({ description, formNode, onClose, title, ...rest }: ActionFormProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) {\n onClose();\n }\n }}\n >\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n className=\"max-h-[min(680px,calc(100vh-2rem))] w-full max-w-lg overflow-y-auto\"\n >\n <DialogHeader\n closeLabel={t(\"common.close\", \"Close\")}\n description={description}\n title={title}\n />\n\n <div className=\"mt-6\">\n {formNode ? (\n <ActionFormContent formNode={formNode} onClose={onClose} {...rest} />\n ) : (\n <ActionFormSkeleton />\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"action-form.js","names":[],"sources":["../../../resources/js/action/components/action-form.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n type DialogPlacement,\n} from \"@lattice-php/lattice/ui/dialog\";\nimport { Skeleton } from \"@lattice-php/lattice/ui/skeleton\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { ModalWidth } from \"@lattice-php/lattice/types/generated\";\nimport {\n collectFields,\n FORM_DEBOUNCE_MS,\n FormProvider,\n FormValuesProvider,\n firstErrors,\n PrefillProvider,\n ResolvedNodesProvider,\n useFormResolver,\n useFormValues,\n} from \"@lattice-php/lattice/form/embed\";\nimport type { FieldErrors } from \"@lattice-php/lattice/form/embed\";\nimport { useDebouncedCallback } from \"@lattice-php/lattice/lib/use-debounced-callback\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { dispatchActionError } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\n\ntype ActionFormProps = {\n cancelLabel: string;\n componentRef: string;\n description?: string;\n endpoint: string;\n /** Extra payload merged into every request, e.g. a bulk action's selection. */\n extraData?: Record<string, unknown>;\n /** The form to render; null while a lazy schema is still being fetched. */\n formNode: Node | null;\n method: string;\n onClose: () => void;\n onSuccess: (response: ActionResponse) => void;\n /** Dialog placement for the form modal; sheets dock to a viewport edge. */\n placement?: DialogPlacement;\n submitLabel: string;\n title: string;\n width?: ModalWidth;\n};\n\n/**\n * Fetch a lazily-served form schema from the action endpoint while `enabled`,\n * so it can be prefilled per record. Returns null until it arrives.\n */\nexport function useLazyActionForm(\n endpoint: string,\n componentRef: string,\n enabled: boolean,\n): Node | null {\n const [node, setNode] = useState<Node | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n setNode(null);\n\n return;\n }\n\n const controller = new AbortController();\n\n void apiFetch(endpoint, {\n body: JSON.stringify({ _form: true }),\n ref: componentRef,\n method: \"POST\",\n signal: controller.signal,\n throwOnError: false,\n })\n .then((response) => (response.ok ? (response.json() as Promise<Node>) : null))\n .then((fetched) => setNode(fetched))\n .catch(() => {});\n\n return () => controller.abort();\n }, [enabled, endpoint, componentRef]);\n\n return node;\n}\n\nfunction ActionFormSkeleton() {\n return (\n <div className=\"space-y-4\" data-lattice-action-form-loading>\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-10 w-full\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n );\n}\n\nfunction ActionFormBody({\n cancelLabel,\n componentRef,\n endpoint,\n extraData,\n fieldLabels,\n formNode,\n method,\n onClose,\n onSuccess,\n precognitive,\n submitLabel,\n}: Omit<ActionFormProps, \"description\" | \"title\"> & {\n fieldLabels: Record<string, string>;\n formNode: Node;\n precognitive: boolean;\n}) {\n const values = useFormValues();\n const valuesRef = useRef(values);\n valuesRef.current = values;\n const extraDataRef = useRef(extraData);\n extraDataRef.current = extraData;\n const { nodes: resolvedNodes, markUserEdit } = useFormResolver(\n endpoint,\n componentRef,\n formNode.schema,\n );\n\n const [errors, setErrors] = useState<FieldErrors>({});\n const [processing, setProcessing] = useState(false);\n\n const request = useCallback(\n (extraHeaders?: Record<string, string>): Promise<Response> =>\n apiFetch(endpoint, {\n body: JSON.stringify({ ...valuesRef.current, ...extraDataRef.current }),\n method,\n ref: componentRef,\n headers: extraHeaders,\n throwOnError: false,\n }),\n [componentRef, endpoint, method],\n );\n\n const clearErrors = useCallback((field: string) => {\n setErrors((current) =>\n current[field] === undefined ? current : { ...current, [field]: undefined },\n );\n }, []);\n\n const runValidation = useDebouncedCallback((field: string) => {\n void request({ Precognition: \"true\", \"Precognition-Validate-Only\": field })\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors((current) => ({ ...current, ...firstErrors(body.errors) }));\n\n return;\n }\n\n clearErrors(field);\n })\n .catch(() => {});\n }, FORM_DEBOUNCE_MS);\n\n const validate = useCallback(\n (field: string) => {\n if (precognitive) {\n runValidation(field);\n }\n },\n [precognitive, runValidation],\n );\n\n const submit = useCallback(() => {\n setProcessing(true);\n\n void request()\n .then(async (response) => {\n if (response.status === 422) {\n const body = (await response.json()) as { errors?: Record<string, string[]> };\n setErrors(firstErrors(body.errors));\n\n return;\n }\n\n if (!response.ok) {\n dispatchActionError(new Error(`Action request failed with status ${response.status}`));\n\n return;\n }\n\n onSuccess((await response.json()) as ActionResponse);\n })\n .catch((error: unknown) => dispatchActionError(error))\n .finally(() => setProcessing(false));\n }, [onSuccess, request]);\n\n const context = useMemo(\n () => ({\n action: endpoint,\n clearErrors,\n componentRef,\n errors,\n fieldLabels,\n precognitive,\n processing,\n validate,\n }),\n [clearErrors, componentRef, endpoint, errors, fieldLabels, precognitive, processing, validate],\n );\n\n return (\n <FormProvider value={context}>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(event) => {\n event.preventDefault();\n submit();\n }}\n >\n <PrefillProvider value={{ markUserEdit }}>\n <ResolvedNodesProvider nodes={resolvedNodes}>\n <Renderer nodes={formNode.schema ?? []} />\n </ResolvedNodesProvider>\n </PrefillProvider>\n\n <div className=\"flex justify-end gap-3\">\n <Button\n data-test=\"action-form-cancel\"\n disabled={processing}\n onClick={onClose}\n type=\"button\"\n variant=\"ghost\"\n >\n {cancelLabel}\n </Button>\n\n <Button data-test=\"action-form-submit\" disabled={processing} type=\"submit\">\n {processing && <Spinner />}\n {submitLabel}\n </Button>\n </div>\n </form>\n </FormProvider>\n );\n}\n\nfunction ActionFormContent({\n formNode,\n ...rest\n}: Omit<ActionFormProps, \"description\" | \"title\"> & { formNode: Node }) {\n const precognitive = Boolean(formNode.props?.precognitive);\n const { labels: fieldLabels, values: initialValues } = useMemo(() => {\n const { labels, values } = collectFields(formNode.schema);\n\n return {\n labels,\n values: { ...values, ...(formNode.props?.state as Record<string, unknown> | undefined) },\n };\n }, [formNode]);\n\n return (\n <FormValuesProvider initial={initialValues}>\n <ActionFormBody\n fieldLabels={fieldLabels}\n formNode={formNode}\n precognitive={precognitive}\n {...rest}\n />\n </FormValuesProvider>\n );\n}\n\nexport function ActionForm({\n description,\n formNode,\n onClose,\n placement,\n title,\n width,\n ...rest\n}: ActionFormProps) {\n const { t } = useT(\"lattice\");\n\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) {\n onClose();\n }\n }}\n >\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n placement={placement}\n width={width}\n >\n <DialogHeader\n closeLabel={t(\"common.close\", \"Close\")}\n description={description}\n title={title}\n />\n\n <div className=\"mt-6\">\n {formNode ? (\n <ActionFormContent formNode={formNode} onClose={onClose} {...rest} />\n ) : (\n <ActionFormSkeleton />\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
import { Node } from '../../core/types.js';
|
|
3
3
|
import { TriggerState } from '../../ui/click-behavior.js';
|
|
4
4
|
export declare function ActionTrigger({ action, children, }: {
|
|
5
|
-
action: Node<"action">;
|
|
5
|
+
action: Node<"action" | "action.bulk">;
|
|
6
6
|
children: (trigger: TriggerState) => ReactNode;
|
|
7
7
|
}): import("react").JSX.Element;
|
|
8
8
|
export declare function ActionInteractionProvider({ children }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-trigger-provider.js","names":[],"sources":["../../../resources/js/action/components/action-trigger-provider.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { ActionTriggerProvider, type TriggerState } from \"@lattice-php/lattice/ui/click-behavior\";\nimport { useAction } from \"@lattice-php/lattice/action/hooks/use-action\";\n\nexport function ActionTrigger({\n action,\n children,\n}: {\n action: Node<\"action\">;\n children: (trigger: TriggerState) => ReactNode;\n}) {\n const { processing, requestSubmit, overlays } = useAction(action);\n\n return (\n <>\n {children({ onClick: requestSubmit, processing })}\n {overlays}\n </>\n );\n}\n\nexport function ActionInteractionProvider({ children }: { children: ReactNode }) {\n return (\n <ActionTriggerProvider\n render={(props) => <ActionTrigger action={props.action}>{props.children}</ActionTrigger>}\n >\n {children}\n </ActionTriggerProvider>\n );\n}\n"],"mappings":";;;;AAKA,SAAgB,cAAc,EAC5B,QACA,YAIC;CACD,MAAM,EAAE,YAAY,eAAe,aAAa,UAAU,MAAM;CAEhE,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,SAAS;EAAE,SAAS;EAAe;CAAW,CAAC,GAC/C,QACD,EAAA,CAAA;AAEN;AAEA,SAAgB,0BAA0B,EAAE,YAAqC;CAC/E,OACE,oBAAC,uBAAD;EACE,SAAS,UAAU,oBAAC,eAAD;GAAe,QAAQ,MAAM;aAAS,MAAM;EAAwB,CAAA;EAEtF;CACoB,CAAA;AAE3B"}
|
|
1
|
+
{"version":3,"file":"action-trigger-provider.js","names":[],"sources":["../../../resources/js/action/components/action-trigger-provider.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { ActionTriggerProvider, type TriggerState } from \"@lattice-php/lattice/ui/click-behavior\";\nimport { useAction } from \"@lattice-php/lattice/action/hooks/use-action\";\n\nexport function ActionTrigger({\n action,\n children,\n}: {\n action: Node<\"action\" | \"action.bulk\">;\n children: (trigger: TriggerState) => ReactNode;\n}) {\n const { processing, requestSubmit, overlays } = useAction(action);\n\n return (\n <>\n {children({ onClick: requestSubmit, processing })}\n {overlays}\n </>\n );\n}\n\nexport function ActionInteractionProvider({ children }: { children: ReactNode }) {\n return (\n <ActionTriggerProvider\n render={(props) => <ActionTrigger action={props.action}>{props.children}</ActionTrigger>}\n >\n {children}\n </ActionTriggerProvider>\n );\n}\n"],"mappings":";;;;AAKA,SAAgB,cAAc,EAC5B,QACA,YAIC;CACD,MAAM,EAAE,YAAY,eAAe,aAAa,UAAU,MAAM;CAEhE,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,SAAS;EAAE,SAAS;EAAe;CAAW,CAAC,GAC/C,QACD,EAAA,CAAA;AAEN;AAEA,SAAgB,0BAA0B,EAAE,YAAqC;CAC/E,OACE,oBAAC,uBAAD;EACE,SAAS,UAAU,oBAAC,eAAD;GAAe,QAAQ,MAAM;aAAS,MAAM;EAAwB,CAAA;EAEtF;CACoB,CAAA;AAE3B"}
|
|
@@ -14,5 +14,5 @@ type UseAction = {
|
|
|
14
14
|
* otherwise dispatch) and renders the matching overlays. The host owns the
|
|
15
15
|
* trigger element so each surface keeps its own styling.
|
|
16
16
|
*/
|
|
17
|
-
export declare function useAction(node: Node<"action">): UseAction;
|
|
17
|
+
export declare function useAction(node: Node<"action" | "action.bulk">): UseAction;
|
|
18
18
|
export {};
|
|
@@ -75,8 +75,10 @@ function useAction(node) {
|
|
|
75
75
|
dispatch(getActionEffects(response.effects));
|
|
76
76
|
setIsFilling(false);
|
|
77
77
|
},
|
|
78
|
+
placement: node.props.modalSide ?? "center",
|
|
78
79
|
submitLabel: confirmationConfirmLabel,
|
|
79
|
-
title: confirmationTitle
|
|
80
|
+
title: confirmationTitle,
|
|
81
|
+
width: node.props.modalWidth ?? void 0
|
|
80
82
|
})] });
|
|
81
83
|
return {
|
|
82
84
|
processing: http.processing,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-action.js","names":[],"sources":["../../../resources/js/action/hooks/use-action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { runAction } from \"@lattice-php/lattice/action/lib/run-action\";\nimport { ActionForm, useLazyActionForm } from \"@lattice-php/lattice/action/components/action-form\";\n\ntype UseAction = {\n /** Whether the action request is in flight. */\n processing: boolean;\n /** Gate then run the action: open the form, confirm, or dispatch directly. */\n requestSubmit: () => void;\n /** The confirm dialog and action form rendered next to the trigger. */\n overlays: ReactNode;\n};\n\n/**\n * The shared action machinery behind the Action button, action menu items, and\n * action links: it gates submission (form → modal, confirmation → confirm,\n * otherwise dispatch) and renders the matching overlays. The host owns the\n * trigger element so each surface keeps its own styling.\n */\nexport function useAction(node: Node<\"action\">): UseAction {\n const endpoint = node.props.endpoint ?? \"\";\n const componentRef = node.props.ref ?? \"\";\n const method: Method = node.props.method ?? \"post\";\n const label = node.props.label ?? \"Run action\";\n const variant = node.props.variant ?? \"default\";\n const confirmation = node.props.confirmation;\n const inlineForm = node.props.form;\n const lazyForm = node.props.lazyForm === true;\n const hasForm = Boolean(inlineForm) || lazyForm;\n\n const http = useHttp<Record<string, never>, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [isConfirming, setIsConfirming] = useState(false);\n const [isFilling, setIsFilling] = useState(false);\n const lazyNode = useLazyActionForm(endpoint, componentRef, isFilling && lazyForm);\n const formNode = lazyForm ? lazyNode : inlineForm;\n\n const submit = async (): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n if (method === \"get\") {\n router.visit(endpoint, { headers: withHeaders(componentRef) });\n setIsConfirming(false);\n\n return;\n }\n\n const ok = await runAction(\n () => http[method](endpoint, { headers: withHeaders(componentRef) }),\n dispatch,\n );\n\n if (ok) {\n setIsConfirming(false);\n }\n };\n\n const requestSubmit = (): void => {\n if (hasForm) {\n setIsFilling(true);\n\n return;\n }\n\n if (confirmation) {\n setIsConfirming(true);\n\n return;\n }\n\n void submit();\n };\n\n const confirmationTitle = confirmation?.title ?? label;\n const confirmationConfirmLabel = confirmation?.confirmLabel ?? label;\n const confirmationCancelLabel = confirmation?.cancelLabel ?? \"Cancel\";\n\n const overlays = (\n <>\n {isConfirming && confirmation && (\n <ConfirmDialog\n title={confirmationTitle}\n description={confirmation.description ?? undefined}\n confirmLabel={confirmationConfirmLabel}\n cancelLabel={confirmationCancelLabel}\n confirmVariant={variant}\n processing={http.processing}\n confirmDisabled={!endpoint}\n onConfirm={() => void submit()}\n onCancel={() => setIsConfirming(false)}\n />\n )}\n\n {isFilling && hasForm && (\n <ActionForm\n cancelLabel={confirmationCancelLabel}\n componentRef={componentRef}\n description={confirmation?.description ?? undefined}\n endpoint={endpoint}\n formNode={formNode}\n method={method}\n onClose={() => setIsFilling(false)}\n onSuccess={(response) => {\n dispatch(getActionEffects(response.effects));\n setIsFilling(false);\n }}\n submitLabel={confirmationConfirmLabel}\n title={confirmationTitle}\n />\n )}\n </>\n );\n\n return { processing: http.processing, requestSubmit, overlays };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4BA,SAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"use-action.js","names":[],"sources":["../../../resources/js/action/hooks/use-action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { runAction } from \"@lattice-php/lattice/action/lib/run-action\";\nimport { ActionForm, useLazyActionForm } from \"@lattice-php/lattice/action/components/action-form\";\n\ntype UseAction = {\n /** Whether the action request is in flight. */\n processing: boolean;\n /** Gate then run the action: open the form, confirm, or dispatch directly. */\n requestSubmit: () => void;\n /** The confirm dialog and action form rendered next to the trigger. */\n overlays: ReactNode;\n};\n\n/**\n * The shared action machinery behind the Action button, action menu items, and\n * action links: it gates submission (form → modal, confirmation → confirm,\n * otherwise dispatch) and renders the matching overlays. The host owns the\n * trigger element so each surface keeps its own styling.\n */\nexport function useAction(node: Node<\"action\" | \"action.bulk\">): UseAction {\n const endpoint = node.props.endpoint ?? \"\";\n const componentRef = node.props.ref ?? \"\";\n const method: Method = node.props.method ?? \"post\";\n const label = node.props.label ?? \"Run action\";\n const variant = node.props.variant ?? \"default\";\n const confirmation = node.props.confirmation;\n const inlineForm = node.props.form;\n const lazyForm = node.props.lazyForm === true;\n const hasForm = Boolean(inlineForm) || lazyForm;\n\n const http = useHttp<Record<string, never>, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [isConfirming, setIsConfirming] = useState(false);\n const [isFilling, setIsFilling] = useState(false);\n const lazyNode = useLazyActionForm(endpoint, componentRef, isFilling && lazyForm);\n const formNode = lazyForm ? lazyNode : inlineForm;\n\n const submit = async (): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n if (method === \"get\") {\n router.visit(endpoint, { headers: withHeaders(componentRef) });\n setIsConfirming(false);\n\n return;\n }\n\n const ok = await runAction(\n () => http[method](endpoint, { headers: withHeaders(componentRef) }),\n dispatch,\n );\n\n if (ok) {\n setIsConfirming(false);\n }\n };\n\n const requestSubmit = (): void => {\n if (hasForm) {\n setIsFilling(true);\n\n return;\n }\n\n if (confirmation) {\n setIsConfirming(true);\n\n return;\n }\n\n void submit();\n };\n\n const confirmationTitle = confirmation?.title ?? label;\n const confirmationConfirmLabel = confirmation?.confirmLabel ?? label;\n const confirmationCancelLabel = confirmation?.cancelLabel ?? \"Cancel\";\n\n const overlays = (\n <>\n {isConfirming && confirmation && (\n <ConfirmDialog\n title={confirmationTitle}\n description={confirmation.description ?? undefined}\n confirmLabel={confirmationConfirmLabel}\n cancelLabel={confirmationCancelLabel}\n confirmVariant={variant}\n processing={http.processing}\n confirmDisabled={!endpoint}\n onConfirm={() => void submit()}\n onCancel={() => setIsConfirming(false)}\n />\n )}\n\n {isFilling && hasForm && (\n <ActionForm\n cancelLabel={confirmationCancelLabel}\n componentRef={componentRef}\n description={confirmation?.description ?? undefined}\n endpoint={endpoint}\n formNode={formNode}\n method={method}\n onClose={() => setIsFilling(false)}\n onSuccess={(response) => {\n dispatch(getActionEffects(response.effects));\n setIsFilling(false);\n }}\n placement={node.props.modalSide ?? \"center\"}\n submitLabel={confirmationConfirmLabel}\n title={confirmationTitle}\n width={node.props.modalWidth ?? undefined}\n />\n )}\n </>\n );\n\n return { processing: http.processing, requestSubmit, overlays };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4BA,SAAgB,UAAU,MAAiD;CACzE,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,eAAe,KAAK,MAAM,OAAO;CACvC,MAAM,SAAiB,KAAK,MAAM,UAAU;CAC5C,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,eAAe,KAAK,MAAM;CAChC,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,WAAW,KAAK,MAAM,aAAa;CACzC,MAAM,UAAU,QAAQ,UAAU,KAAK;CAEvC,MAAM,OAAO,QAA+C,CAAC,CAAC;CAC9D,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,WAAW,kBAAkB,UAAU,cAAc,aAAa,QAAQ;CAChF,MAAM,WAAW,WAAW,WAAW;CAEvC,MAAM,SAAS,YAA2B;EACxC,IAAI,CAAC,UACH;EAGF,IAAI,WAAW,OAAO;GACpB,OAAO,MAAM,UAAU,EAAE,SAAS,YAAY,YAAY,EAAE,CAAC;GAC7D,gBAAgB,KAAK;GAErB;EACF;EAOA,IAAI,MALa,gBACT,KAAK,QAAQ,UAAU,EAAE,SAAS,YAAY,YAAY,EAAE,CAAC,GACnE,QACF,GAGE,gBAAgB,KAAK;CAEzB;CAEA,MAAM,sBAA4B;EAChC,IAAI,SAAS;GACX,aAAa,IAAI;GAEjB;EACF;EAEA,IAAI,cAAc;GAChB,gBAAgB,IAAI;GAEpB;EACF;EAEA,OAAY;CACd;CAEA,MAAM,oBAAoB,cAAc,SAAS;CACjD,MAAM,2BAA2B,cAAc,gBAAgB;CAC/D,MAAM,0BAA0B,cAAc,eAAe;CAE7D,MAAM,WACJ,qBAAA,YAAA,EAAA,UAAA,CACG,gBAAgB,gBACf,oBAAC,eAAD;EACE,OAAO;EACP,aAAa,aAAa,eAAe,KAAA;EACzC,cAAc;EACd,aAAa;EACb,gBAAgB;EAChB,YAAY,KAAK;EACjB,iBAAiB,CAAC;EAClB,iBAAiB,KAAK,OAAO;EAC7B,gBAAgB,gBAAgB,KAAK;CACtC,CAAA,GAGF,aAAa,WACZ,oBAAC,YAAD;EACE,aAAa;EACC;EACd,aAAa,cAAc,eAAe,KAAA;EAChC;EACA;EACF;EACR,eAAe,aAAa,KAAK;EACjC,YAAY,aAAa;GACvB,SAAS,iBAAiB,SAAS,OAAO,CAAC;GAC3C,aAAa,KAAK;EACpB;EACA,WAAW,KAAK,MAAM,aAAa;EACnC,aAAa;EACb,OAAO;EACP,OAAO,KAAK,MAAM,cAAc,KAAA;CACjC,CAAA,CAEH,EAAA,CAAA;CAGJ,OAAO;EAAE,YAAY,KAAK;EAAY;EAAe;CAAS;AAChE"}
|
package/dist/action/index.d.ts
CHANGED
|
@@ -4,7 +4,5 @@ export { default as ActionGroupComponent } from './components/action-group.js';
|
|
|
4
4
|
export { ActionInteractionProvider, ActionTrigger } from './components/action-trigger-provider.js';
|
|
5
5
|
export { ActionMenuProvider, actionMenuItemClassName, useActionMenu, } from '../ui/action-menu-context.js';
|
|
6
6
|
export { useAction } from './hooks/use-action.js';
|
|
7
|
-
export { useClickBehavior } from '../ui/click-behavior.js';
|
|
8
|
-
export type { ClickBehavior, TriggerState } from '../ui/click-behavior.js';
|
|
9
7
|
export { runAction } from './lib/run-action.js';
|
|
10
8
|
export { actionComponents } from './plugin.js';
|
package/dist/action/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useClickBehavior } from "../ui/click-behavior.js";
|
|
2
1
|
import { runAction } from "./lib/run-action.js";
|
|
3
2
|
import { ActionForm } from "./components/action-form.js";
|
|
4
3
|
import { useAction } from "./hooks/use-action.js";
|
|
@@ -7,4 +6,4 @@ import { ActionMenuProvider, actionMenuItemClassName, useActionMenu } from "../u
|
|
|
7
6
|
import ActionComponent from "./components/action.js";
|
|
8
7
|
import ActionGroupComponent from "./components/action-group.js";
|
|
9
8
|
import { actionComponents } from "./plugin.js";
|
|
10
|
-
export { ActionComponent, ActionForm, ActionGroupComponent, ActionInteractionProvider, ActionMenuProvider, ActionTrigger, actionComponents, actionMenuItemClassName, runAction, useAction, useActionMenu
|
|
9
|
+
export { ActionComponent, ActionForm, ActionGroupComponent, ActionInteractionProvider, ActionMenuProvider, ActionTrigger, actionComponents, actionMenuItemClassName, runAction, useAction, useActionMenu };
|
package/dist/chat/plugin.d.ts
CHANGED
package/dist/chat/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/chat/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport ChatBoxComponent from \"./components/chat-box\";\nimport { TextPart } from \"./parts/text\";\nimport {
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/chat/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport ChatBoxComponent from \"./components/chat-box\";\nimport { TextPart } from \"./parts/text\";\nimport type { ChatNodeType } from \"@lattice-php/lattice/types/generated\";\nimport { ToolCallPart } from \"./parts/tool-call\";\n\nexport const chatComponents = createPlugin({\n name: \"lattice/chat\",\n components: {\n \"chat.box\": eagerComponent(ChatBoxComponent),\n \"chat.part.text\": eagerComponent(TextPart),\n \"chat.part.tool-call\": eagerComponent(ToolCallPart),\n } satisfies ComponentRegistryFor<ChatNodeType>,\n});\n"],"mappings":";;;;;AAUA,IAAa,iBAAiB,aAAa;CACzC,MAAM;CACN,YAAY;EACV,YAAY,eAAe,OAAgB;EAC3C,kBAAkB,eAAe,QAAQ;EACzC,uBAAuB,eAAe,YAAY;CACpD;AACF,CAAC"}
|
|
@@ -1,5 +1 @@
|
|
|
1
1
|
export { CopyableText, copyToClipboard } from '../ui/copyable-text.js';
|
|
2
|
-
export type CopiedValue = string | null;
|
|
3
|
-
export type CopyFn = (text: string) => Promise<boolean>;
|
|
4
|
-
export type UseClipboardReturn = [CopiedValue, CopyFn];
|
|
5
|
-
export declare function useClipboard(): UseClipboardReturn;
|
package/dist/clipboard/index.js
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
1
|
import { CopyableText, copyToClipboard } from "../ui/copyable-text.js";
|
|
2
|
-
|
|
3
|
-
//#region resources/js/clipboard/index.ts
|
|
4
|
-
function useClipboard() {
|
|
5
|
-
const [copiedText, setCopiedText] = useState(null);
|
|
6
|
-
const copy = async (text) => {
|
|
7
|
-
const copied = await copyToClipboard(text);
|
|
8
|
-
setCopiedText(copied ? text : null);
|
|
9
|
-
return copied;
|
|
10
|
-
};
|
|
11
|
-
return [copiedText, copy];
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { CopyableText, copyToClipboard, useClipboard };
|
|
15
|
-
|
|
16
|
-
//# sourceMappingURL=index.js.map
|
|
2
|
+
export { CopyableText, copyToClipboard };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-names.js","names":[],"sources":["../../resources/js/core/event-names.ts"],"sourcesContent":["/**\n * Single source of truth for the `lattice:*` DOM events the runtime dispatches\n * and listens for. The built-in effect handlers in effects/registry.ts bridge\n * effects to these events; the rest are framework events with no PHP counterpart.\n */\nexport const LATTICE_EVENT = {\n callout: \"lattice:callout\",\n toast: \"lattice:toast\",\n reloadComponent: \"lattice:reload-component\",\n openModal: \"lattice:open-modal\",\n closeModal: \"lattice:close-modal\",\n resetForm: \"lattice:reset-form\",\n toggleSidebar: \"lattice:toggle-sidebar\",\n appearanceChange: \"lattice:appearance-change\",\n localeChange: \"lattice:locale-change\",\n timezoneChange: \"lattice:timezone-change\",\n actionError: \"lattice:action-error\",\n} as const;\n\nexport type ReloadComponentEvent = CustomEvent<{\n component?: string;\n type?: string;\n}>;\n"],"mappings":";;;;;;AAKA,IAAa,gBAAgB;CAC3B,SAAS;CACT,OAAO;CACP,iBAAiB;CACjB,WAAW;CACX,YAAY;CACZ,WAAW;CACX,eAAe;CACf,kBAAkB;CAClB,cAAc;CACd,gBAAgB;CAChB,aAAa;AACf"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscribe to a window event for the lifetime of the component. The handler is
|
|
3
|
+
* read through a ref, so a fresh handler each render never re-subscribes; pass
|
|
4
|
+
* `enabled: false` to detach without unmounting.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useWindowEvent(type: string, handler: (event: Event) => void, options?: {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
}): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
//#region resources/js/core/hooks/use-window-event.ts
|
|
3
|
+
/**
|
|
4
|
+
* Subscribe to a window event for the lifetime of the component. The handler is
|
|
5
|
+
* read through a ref, so a fresh handler each render never re-subscribes; pass
|
|
6
|
+
* `enabled: false` to detach without unmounting.
|
|
7
|
+
*/
|
|
8
|
+
function useWindowEvent(type, handler, options = {}) {
|
|
9
|
+
const { enabled = true } = options;
|
|
10
|
+
const handlerRef = useRef(handler);
|
|
11
|
+
handlerRef.current = handler;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!enabled || typeof window === "undefined") return;
|
|
14
|
+
const listener = (event) => handlerRef.current(event);
|
|
15
|
+
window.addEventListener(type, listener);
|
|
16
|
+
return () => window.removeEventListener(type, listener);
|
|
17
|
+
}, [type, enabled]);
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { useWindowEvent };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=use-window-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-window-event.js","names":[],"sources":["../../../resources/js/core/hooks/use-window-event.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\n/**\n * Subscribe to a window event for the lifetime of the component. The handler is\n * read through a ref, so a fresh handler each render never re-subscribes; pass\n * `enabled: false` to detach without unmounting.\n */\nexport function useWindowEvent(\n type: string,\n handler: (event: Event) => void,\n options: { enabled?: boolean } = {},\n): void {\n const { enabled = true } = options;\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n if (!enabled || typeof window === \"undefined\") {\n return;\n }\n\n const listener = (event: Event): void => handlerRef.current(event);\n\n window.addEventListener(type, listener);\n\n return () => window.removeEventListener(type, listener);\n }, [type, enabled]);\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,eACd,MACA,SACA,UAAiC,CAAC,GAC5B;CACN,MAAM,EAAE,UAAU,SAAS;CAC3B,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CAErB,gBAAgB;EACd,IAAI,CAAC,WAAW,OAAO,WAAW,aAChC;EAGF,MAAM,YAAY,UAAuB,WAAW,QAAQ,KAAK;EAEjE,OAAO,iBAAiB,MAAM,QAAQ;EAEtC,aAAa,OAAO,oBAAoB,MAAM,QAAQ;CACxD,GAAG,CAAC,MAAM,OAAO,CAAC;AACpB"}
|
package/dist/core/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createPlugin, createRegistry, eagerComponent, extendRegistry, lazyComponent } from "./registry.js";
|
|
2
2
|
import { RegistryContext, setDefaultRegistry, useColumnRegistry, useComponentRegistry, useEffectHandlerRegistry } from "./registry-context.js";
|
|
3
|
+
import { dataBindings, isRecord, materializeNode, materializeProps, materializeSchema, rowValue } from "./materialize.js";
|
|
3
4
|
import { LATTICE_REF_HEADER, withRefHeader } from "./component-ref.js";
|
|
4
5
|
import { withHeaders } from "./headers.js";
|
|
5
6
|
import { toNodes } from "./nodes.js";
|
|
6
7
|
import { CollapsedContext, useCollapsed } from "./collapsed-context.js";
|
|
7
8
|
import { RenderNode, Renderer } from "./renderer.js";
|
|
8
9
|
import { ApiError, apiFetch, apiJson, clearRemoteTokenCache, invalidateRemoteToken, remoteFetch, remoteJson, remoteToken } from "./api.js";
|
|
9
|
-
import { dataBindings, isRecord, materializeNode, materializeProps, materializeSchema, rowValue } from "./materialize.js";
|
|
10
10
|
export { ApiError, CollapsedContext, LATTICE_REF_HEADER, RegistryContext, RenderNode, Renderer, apiFetch, apiJson, clearRemoteTokenCache, createPlugin, createRegistry, dataBindings, eagerComponent, extendRegistry, invalidateRemoteToken, isRecord, lazyComponent, materializeNode, materializeProps, materializeSchema, remoteFetch, remoteJson, remoteToken, rowValue, setDefaultRegistry, toNodes, useCollapsed, useColumnRegistry, useComponentRegistry, useEffectHandlerRegistry, withHeaders, withRefHeader };
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,69 +1,16 @@
|
|
|
1
1
|
import { ComponentType as ReactComponentType, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
export type { KnownPageContainer, NodeType, Option,
|
|
4
|
-
export type NodeProps = Record<string, unknown>;
|
|
5
|
-
export type CommonNodeProps = {
|
|
6
|
-
dataBindings?: Record<string, string> | null;
|
|
7
|
-
hideWhenCollapsed?: boolean | null;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Augmentable map of wire `type` string → props for consumer components. Apps
|
|
11
|
-
* extend it via `declare module "@lattice-php/lattice"` so their custom components
|
|
12
|
-
* gain strong prop types; the entries are generated by `php artisan lattice:typescript`.
|
|
13
|
-
* Built-in components resolve through the generated `ComponentPropsMap` below, the
|
|
14
|
-
* same way `ColumnProps` augments `ColumnPropsMap`. Types in neither fall back to a
|
|
15
|
-
* loose bag.
|
|
16
|
-
*/
|
|
17
|
-
export interface ComponentProps {
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Resolves a `type` string to its payload: consumer augmentations (`TAugment`)
|
|
21
|
-
* win over generated built-ins (`TBuiltins`), then a loose fallback. The one
|
|
22
|
-
* resolver behind the component, column and effect maps.
|
|
23
|
-
*/
|
|
24
|
-
export type ResolveProps<TAugment, TBuiltins, TType extends string, TFallback> = TType extends keyof TAugment ? TAugment[TType] : TType extends keyof TBuiltins ? TBuiltins[TType] : TFallback;
|
|
25
|
-
export type PropsOf<TType extends string> = ResolveProps<ComponentProps, ComponentPropsMap, TType, NodeProps> & CommonNodeProps;
|
|
26
|
-
/**
|
|
27
|
-
* Built-in `props` is required, not optional — the wire serializes the full prop
|
|
28
|
-
* object, so reads need no optional chaining. Unknown types fall back to `WireNode`.
|
|
29
|
-
*/
|
|
30
|
-
export type NodeOfType<TType extends string = string> = string extends TType ? WireNode : {
|
|
31
|
-
id?: string;
|
|
32
|
-
key?: string;
|
|
33
|
-
props: PropsOf<TType>;
|
|
34
|
-
schema?: Schema;
|
|
35
|
-
type: TType;
|
|
36
|
-
};
|
|
37
|
-
export type Node<TType extends string = string> = NodeOfType<TType>;
|
|
38
|
-
/**
|
|
39
|
-
* Distributes so `NodeUnionOf<"a" | "b">` is `NodeOfType<"a"> | NodeOfType<"b">`
|
|
40
|
-
* — a discriminated union where `node.type` narrows `node.props`. Domains build
|
|
41
|
-
* their node union from a generated `…NodeType` string union with this.
|
|
42
|
-
*/
|
|
43
|
-
export type NodeUnionOf<TTypes extends string> = TTypes extends string ? NodeOfType<TTypes> : never;
|
|
44
|
-
export type Schema = Node[];
|
|
2
|
+
import { CommonNodeProps, ComponentProps, Node, NodeProps, NodeType, NodeUnionOf, Option, PageContainer as KnownPageContainer, ComponentPropsOf, ResolveProps, Schema, Breadcrumb, PageLayoutPayload, PagePayload as GeneratedPagePayload } from '../types/generated.js';
|
|
3
|
+
export type { CommonNodeProps, ComponentProps, KnownPageContainer, Node, NodeProps, NodeType, NodeUnionOf, Option, ComponentPropsOf, ResolveProps, Schema, };
|
|
45
4
|
/** Its `schema` holds exactly one Outlet node. */
|
|
46
|
-
export type LayoutPayload =
|
|
47
|
-
|
|
48
|
-
schema: Schema;
|
|
49
|
-
};
|
|
5
|
+
export type LayoutPayload = PageLayoutPayload;
|
|
6
|
+
export type PageBreadcrumb = Breadcrumb;
|
|
50
7
|
/**
|
|
51
|
-
* The page payload the server hydrates onto `lattice`
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* final encode), so they cannot be derived from a value object as typed `Node[]`.
|
|
8
|
+
* The page payload the server hydrates onto `lattice` — the generated
|
|
9
|
+
* `PagePayload` (PHP `Http\PagePayload`), with `container` refined to the
|
|
10
|
+
* known-container union custom containers extend.
|
|
55
11
|
*/
|
|
56
|
-
export type PagePayload = {
|
|
57
|
-
breadcrumbs: PageBreadcrumb[];
|
|
12
|
+
export type PagePayload = Omit<GeneratedPagePayload, "container"> & {
|
|
58
13
|
container: PageContainer;
|
|
59
|
-
layout: LayoutPayload | null;
|
|
60
|
-
listeners?: ListenerPayload[];
|
|
61
|
-
schema: Schema;
|
|
62
|
-
title: string | null;
|
|
63
|
-
};
|
|
64
|
-
export type PageBreadcrumb = {
|
|
65
|
-
href: string;
|
|
66
|
-
title: string;
|
|
67
14
|
};
|
|
68
15
|
export type PageContainer = KnownPageContainer | (string & {});
|
|
69
16
|
export type RendererComponentProps<TType extends string = string> = {
|
package/dist/create-app.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { Page as InertiaPage } from '@inertiajs/core';
|
|
1
2
|
import { createInertiaApp } from '@inertiajs/react';
|
|
2
3
|
import { ReactElement } from 'react';
|
|
3
4
|
import { Plugin, Registry } from './core/registry.js';
|
|
4
5
|
import { SpriteValue } from './icons/sprite.js';
|
|
5
6
|
import { CreateLayoutResolverOptions, PageModules } from './inertia.js';
|
|
6
7
|
type InertiaAppOptions = NonNullable<Parameters<typeof createInertiaApp>[0]>;
|
|
8
|
+
export type CreateLatticeAppI18nOptions = {
|
|
9
|
+
/** i18next namespaces to load, e.g. `["lattice", "app"]`. Defaults to the package's own. */
|
|
10
|
+
namespaces?: string[];
|
|
11
|
+
};
|
|
7
12
|
export type CreateLatticeAppOptions = Omit<InertiaAppOptions, "resolve" | "layout" | "setup" | "withApp" | "pages"> & {
|
|
8
13
|
registry?: Registry;
|
|
9
14
|
/**
|
|
@@ -16,12 +21,35 @@ export type CreateLatticeAppOptions = Omit<InertiaAppOptions, "resolve" | "layou
|
|
|
16
21
|
/** Normal Inertia page modules, e.g. `import.meta.glob('./pages/**\/*.tsx')`. */
|
|
17
22
|
pages?: PageModules;
|
|
18
23
|
defaultLayout?: CreateLayoutResolverOptions["defaultLayout"];
|
|
24
|
+
/**
|
|
25
|
+
* Lattice's i18n bootstrap, on by default: when the backend shares the
|
|
26
|
+
* `lattice.i18n` prop, the first render waits for the translation setup (no
|
|
27
|
+
* flash of untranslated fallbacks), `LocaleReload` re-fetches the page after
|
|
28
|
+
* a locale switch, and every visit carries the locale/timezone headers. The
|
|
29
|
+
* i18next chunk only loads when the backend actually shares the prop. Pass
|
|
30
|
+
* `false` to opt out entirely.
|
|
31
|
+
*/
|
|
32
|
+
i18n?: CreateLatticeAppI18nOptions | false;
|
|
33
|
+
/**
|
|
34
|
+
* App bootstrap that needs the initial page — e.g. `configureEcho` from a
|
|
35
|
+
* shared connection prop. Runs on the client before the first render; a
|
|
36
|
+
* returned promise delays that render until it resolves.
|
|
37
|
+
*/
|
|
38
|
+
boot?: (context: {
|
|
39
|
+
page: InertiaPage;
|
|
40
|
+
}) => void | Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Compose providers or siblings around the app. Applied inside the Lattice
|
|
43
|
+
* Provider, so the registry, sprite, and toaster contexts are available.
|
|
44
|
+
*/
|
|
45
|
+
wrap?: (app: ReactElement) => ReactElement;
|
|
19
46
|
};
|
|
20
47
|
/**
|
|
21
48
|
* Bootstrap an Inertia app with the Lattice shell: the page/layout resolvers
|
|
22
49
|
* (server-driven Lattice pages and normal Inertia pages alike), the Provider —
|
|
23
|
-
* registry, sprite, flash toasts via Lattice's own Toaster —
|
|
24
|
-
* initialization. Forwards any other createInertiaApp
|
|
50
|
+
* registry, sprite, flash toasts via Lattice's own Toaster — theme
|
|
51
|
+
* initialization, and the i18n bootstrap. Forwards any other createInertiaApp
|
|
52
|
+
* option.
|
|
25
53
|
*/
|
|
26
|
-
export declare function createLatticeApp({ registry, plugins, sprite, pages, defaultLayout, strictMode, ...inertiaOptions }?: CreateLatticeAppOptions): Promise<void | ((page:
|
|
54
|
+
export declare function createLatticeApp({ registry, plugins, sprite, pages, defaultLayout, strictMode, i18n, boot, wrap, ...inertiaOptions }?: CreateLatticeAppOptions): Promise<void | ((page: InertiaPage<import('@inertiajs/core').PageProps>, renderToString: (element: ReactElement) => string) => Promise<import('@inertiajs/core').InertiaAppSSRResponse>)>;
|
|
27
55
|
export {};
|