@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
package/dist/ui/collapsible.js
CHANGED
|
@@ -3,29 +3,17 @@ import { Icon } from "../icons/sprite.js";
|
|
|
3
3
|
import { toNodes } from "../core/nodes.js";
|
|
4
4
|
import { Renderer } from "../core/renderer.js";
|
|
5
5
|
import { nodeIdentity, prefixedTestId } from "../core/test-id.js";
|
|
6
|
+
import { useCollapsibleState } from "./use-collapsible-state.js";
|
|
6
7
|
import { InfoTooltip } from "./info-tooltip.js";
|
|
7
|
-
import { useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region resources/js/ui/collapsible.tsx
|
|
10
|
-
function readStored(key, remember, fallback) {
|
|
11
|
-
if (!remember || typeof window === "undefined") return fallback;
|
|
12
|
-
const stored = window.localStorage.getItem(key);
|
|
13
|
-
return stored === null ? fallback : stored === "true";
|
|
14
|
-
}
|
|
15
10
|
var CollapsibleComponent = ({ children, node }) => {
|
|
16
|
-
const rememberState = node.props.rememberState
|
|
11
|
+
const rememberState = node.props.rememberState !== false;
|
|
17
12
|
const trigger = toNodes(node.props.trigger);
|
|
18
13
|
const identity = nodeIdentity(node);
|
|
19
14
|
const storageKey = `lattice:collapsible:${identity ?? "default"}`;
|
|
20
15
|
const contentId = `${identity ?? "collapsible"}-content`;
|
|
21
|
-
const [open,
|
|
22
|
-
function toggle() {
|
|
23
|
-
setOpen((value) => {
|
|
24
|
-
const next = !value;
|
|
25
|
-
if (rememberState && typeof window !== "undefined") window.localStorage.setItem(storageKey, String(next));
|
|
26
|
-
return next;
|
|
27
|
-
});
|
|
28
|
-
}
|
|
16
|
+
const [open, toggle] = useCollapsibleState(storageKey, node.props.collapsed === false, rememberState);
|
|
29
17
|
return /* @__PURE__ */ jsxs("div", {
|
|
30
18
|
"data-slot": "collapsible",
|
|
31
19
|
"data-lattice-component": identity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapsible.js","names":[],"sources":["../../resources/js/ui/collapsible.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"collapsible.js","names":[],"sources":["../../resources/js/ui/collapsible.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport { InfoTooltip } from \"./info-tooltip\";\nimport { nodeIdentity, prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { toNodes } from \"@lattice-php/lattice/core/nodes\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useCollapsibleState } from \"./use-collapsible-state\";\n\nconst CollapsibleComponent: RendererComponent<\"collapsible\"> = ({ children, node }) => {\n const rememberState = node.props.rememberState !== false;\n const trigger = toNodes(node.props.trigger);\n const identity = nodeIdentity(node);\n const storageKey = `lattice:collapsible:${identity ?? \"default\"}`;\n const contentId = `${identity ?? \"collapsible\"}-content`;\n\n const [open, toggle] = useCollapsibleState(\n storageKey,\n node.props.collapsed === false,\n rememberState,\n );\n\n return (\n <div data-slot=\"collapsible\" data-lattice-component={identity}>\n <div\n aria-controls={contentId}\n aria-expanded={open}\n data-test={prefixedTestId(\"collapsible-toggle\", identity) ?? \"collapsible-toggle-default\"}\n className=\"flex w-full cursor-pointer items-center justify-between gap-4 rounded-lt-sm py-2 text-left text-lt-fg transition-colors hover:bg-lt-muted\"\n onClick={toggle}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n toggle();\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Renderer nodes={trigger} />\n {node.props.tooltip && (\n <span\n role=\"presentation\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <InfoTooltip content={node.props.tooltip} />\n </span>\n )}\n </div>\n <Icon\n name=\"chevron-down\"\n className={cn(\n \"size-lt-icon-md shrink-0 text-lt-muted-fg transition-transform\",\n !open && \"-rotate-90\",\n )}\n />\n </div>\n\n {open && children && (\n <div id={contentId} className=\"flex flex-col gap-4 pt-2\">\n {children}\n </div>\n )}\n </div>\n );\n};\n\nexport default CollapsibleComponent;\n"],"mappings":";;;;;;;;;AASA,IAAM,wBAA0D,EAAE,UAAU,WAAW;CACrF,MAAM,gBAAgB,KAAK,MAAM,kBAAkB;CACnD,MAAM,UAAU,QAAQ,KAAK,MAAM,OAAO;CAC1C,MAAM,WAAW,aAAa,IAAI;CAClC,MAAM,aAAa,uBAAuB,YAAY;CACtD,MAAM,YAAY,GAAG,YAAY,cAAc;CAE/C,MAAM,CAAC,MAAM,UAAU,oBACrB,YACA,KAAK,MAAM,cAAc,OACzB,aACF;CAEA,OACE,qBAAC,OAAD;EAAK,aAAU;EAAc,0BAAwB;YAArD,CACE,qBAAC,OAAD;GACE,iBAAe;GACf,iBAAe;GACf,aAAW,eAAe,sBAAsB,QAAQ,KAAK;GAC7D,WAAU;GACV,SAAS;GACT,YAAY,UAAU;IACpB,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAC9C,MAAM,eAAe;KACrB,OAAO;IACT;GACF;GACA,MAAK;GACL,UAAU;aAbZ,CAeE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,UAAD,EAAU,OAAO,QAAU,CAAA,GAC1B,KAAK,MAAM,WACV,oBAAC,QAAD;KACE,MAAK;KACL,UAAU,UAAU,MAAM,gBAAgB;KAC1C,YAAY,UAAU,MAAM,gBAAgB;eAE5C,oBAAC,aAAD,EAAa,SAAS,KAAK,MAAM,QAAU,CAAA;IACvC,CAAA,CAEL;OACL,oBAAC,MAAD;IACE,MAAK;IACL,WAAW,GACT,kEACA,CAAC,QAAQ,YACX;GACD,CAAA,CACE;MAEJ,QAAQ,YACP,oBAAC,OAAD;GAAK,IAAI;GAAW,WAAU;GAC3B;EACE,CAAA,CAEJ;;AAET"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function normalizeHex(input: string): string | null;
|
|
2
|
+
export declare function ColorPicker({ value, onChange, palette, hexLabel, paletteLabel, }: {
|
|
3
|
+
value: string;
|
|
4
|
+
onChange: (hex: string) => void;
|
|
5
|
+
palette: string[];
|
|
6
|
+
hexLabel?: string;
|
|
7
|
+
paletteLabel?: string;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Input } from "./input.js";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { HexColorPicker } from "react-colorful";
|
|
6
|
+
//#region resources/js/ui/color-picker.tsx
|
|
7
|
+
function normalizeHex(input) {
|
|
8
|
+
const raw = input.trim().replace(/^#/, "").toLowerCase();
|
|
9
|
+
if (/^[0-9a-f]{6}$/.test(raw)) return `#${raw}`;
|
|
10
|
+
if (/^[0-9a-f]{3}$/.test(raw)) return `#${raw[0]}${raw[0]}${raw[1]}${raw[1]}${raw[2]}${raw[2]}`;
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function ColorPicker({ value, onChange, palette, hexLabel = "Hex color", paletteLabel = "Color palette" }) {
|
|
14
|
+
const [draft, setDraft] = useState(null);
|
|
15
|
+
const color = normalizeHex(value) ?? "#6b7280";
|
|
16
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
17
|
+
className: "flex w-56 flex-col gap-3",
|
|
18
|
+
"data-slot": "color-picker",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsx(HexColorPicker, {
|
|
21
|
+
className: "!w-full",
|
|
22
|
+
color,
|
|
23
|
+
onChange
|
|
24
|
+
}),
|
|
25
|
+
palette.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"aria-label": paletteLabel,
|
|
27
|
+
className: "flex flex-wrap gap-1.5",
|
|
28
|
+
role: "listbox",
|
|
29
|
+
children: palette.map((swatch) => {
|
|
30
|
+
const normalized = normalizeHex(swatch) ?? swatch;
|
|
31
|
+
return /* @__PURE__ */ jsx("button", {
|
|
32
|
+
"aria-label": normalized,
|
|
33
|
+
"aria-selected": normalized === color,
|
|
34
|
+
className: cn("size-6 shrink-0 rounded-full border border-lt-border", normalized === color && "ring-2 ring-lt-ring ring-offset-1"),
|
|
35
|
+
onClick: () => onChange(normalized),
|
|
36
|
+
role: "option",
|
|
37
|
+
style: { background: swatch },
|
|
38
|
+
type: "button"
|
|
39
|
+
}, swatch);
|
|
40
|
+
})
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ jsx(Input, {
|
|
43
|
+
"aria-label": hexLabel,
|
|
44
|
+
onBlur: () => setDraft(null),
|
|
45
|
+
onChange: (event) => {
|
|
46
|
+
const text = event.target.value;
|
|
47
|
+
const hex = normalizeHex(text);
|
|
48
|
+
setDraft(text);
|
|
49
|
+
if (hex !== null) onChange(hex);
|
|
50
|
+
},
|
|
51
|
+
value: draft ?? color
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
export { ColorPicker, normalizeHex };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=color-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-picker.js","names":[],"sources":["../../resources/js/ui/color-picker.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { HexColorPicker } from \"react-colorful\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { Input } from \"./input\";\n\nexport function normalizeHex(input: string): string | null {\n const raw = input.trim().replace(/^#/, \"\").toLowerCase();\n\n if (/^[0-9a-f]{6}$/.test(raw)) {\n return `#${raw}`;\n }\n\n if (/^[0-9a-f]{3}$/.test(raw)) {\n return `#${raw[0]}${raw[0]}${raw[1]}${raw[1]}${raw[2]}${raw[2]}`;\n }\n\n return null;\n}\n\nexport function ColorPicker({\n value,\n onChange,\n palette,\n hexLabel = \"Hex color\",\n paletteLabel = \"Color palette\",\n}: {\n value: string;\n onChange: (hex: string) => void;\n palette: string[];\n hexLabel?: string;\n paletteLabel?: string;\n}) {\n const [draft, setDraft] = useState<string | null>(null);\n const color = normalizeHex(value) ?? \"#6b7280\";\n\n return (\n <div className=\"flex w-56 flex-col gap-3\" data-slot=\"color-picker\">\n <HexColorPicker className=\"!w-full\" color={color} onChange={onChange} />\n {palette.length > 0 && (\n <div aria-label={paletteLabel} className=\"flex flex-wrap gap-1.5\" role=\"listbox\">\n {palette.map((swatch) => {\n const normalized = normalizeHex(swatch) ?? swatch;\n\n return (\n <button\n aria-label={normalized}\n aria-selected={normalized === color}\n className={cn(\n \"size-6 shrink-0 rounded-full border border-lt-border\",\n normalized === color && \"ring-2 ring-lt-ring ring-offset-1\",\n )}\n key={swatch}\n onClick={() => onChange(normalized)}\n role=\"option\"\n style={{ background: swatch }}\n type=\"button\"\n />\n );\n })}\n </div>\n )}\n <Input\n aria-label={hexLabel}\n onBlur={() => setDraft(null)}\n onChange={(event) => {\n const text = event.target.value;\n const hex = normalizeHex(text);\n setDraft(text);\n\n if (hex !== null) {\n onChange(hex);\n }\n }}\n value={draft ?? color}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,SAAgB,aAAa,OAA8B;CACzD,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,MAAM,EAAE,EAAE,YAAY;CAEvD,IAAI,gBAAgB,KAAK,GAAG,GAC1B,OAAO,IAAI;CAGb,IAAI,gBAAgB,KAAK,GAAG,GAC1B,OAAO,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI;CAG9D,OAAO;AACT;AAEA,SAAgB,YAAY,EAC1B,OACA,UACA,SACA,WAAW,aACX,eAAe,mBAOd;CACD,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,QAAQ,aAAa,KAAK,KAAK;CAErC,OACE,qBAAC,OAAD;EAAK,WAAU;EAA2B,aAAU;YAApD;GACE,oBAAC,gBAAD;IAAgB,WAAU;IAAiB;IAAiB;GAAW,CAAA;GACtE,QAAQ,SAAS,KAChB,oBAAC,OAAD;IAAK,cAAY;IAAc,WAAU;IAAyB,MAAK;cACpE,QAAQ,KAAK,WAAW;KACvB,MAAM,aAAa,aAAa,MAAM,KAAK;KAE3C,OACE,oBAAC,UAAD;MACE,cAAY;MACZ,iBAAe,eAAe;MAC9B,WAAW,GACT,wDACA,eAAe,SAAS,mCAC1B;MAEA,eAAe,SAAS,UAAU;MAClC,MAAK;MACL,OAAO,EAAE,YAAY,OAAO;MAC5B,MAAK;KACN,GALM,MAKN;IAEL,CAAC;GACE,CAAA;GAEP,oBAAC,OAAD;IACE,cAAY;IACZ,cAAc,SAAS,IAAI;IAC3B,WAAW,UAAU;KACnB,MAAM,OAAO,MAAM,OAAO;KAC1B,MAAM,MAAM,aAAa,IAAI;KAC7B,SAAS,IAAI;KAEb,IAAI,QAAQ,MACV,SAAS,GAAG;IAEhB;IACA,OAAO,SAAS;GACjB,CAAA;EACE;;AAET"}
|
package/dist/ui/combobox.d.ts
CHANGED
|
@@ -7,18 +7,27 @@ import * as React from "react";
|
|
|
7
7
|
* consumer also owns option fetching. Pass `onSearch` for remote search (the
|
|
8
8
|
* combobox debounces the query and renders `options` as given); omit it to
|
|
9
9
|
* filter the provided `options` locally by label. The combobox closes itself
|
|
10
|
-
* after a single-select.
|
|
10
|
+
* after a single-select. Pass `renderOption` to render rich option rows; the
|
|
11
|
+
* option's label stays the accessible name. `onSelect` toggles selection
|
|
12
|
+
* (used by dropdown-row clicks); tag-entry commits (Enter/comma/paste) that
|
|
13
|
+
* match an existing option call `onCommit` instead, falling back to
|
|
14
|
+
* `onSelect` when it is not provided, so consumers can make tag entry
|
|
15
|
+
* additive instead of toggling.
|
|
11
16
|
*/
|
|
12
|
-
declare function Combobox({ contentClassName, emptyLabel, loading, multiple, onSearch, onSelect, open, onOpenChange, options, searchLabel, searchPlaceholder, selected, showSearch, testId, trigger, triggerClassName, triggerProps, }: {
|
|
17
|
+
declare function Combobox({ contentClassName, creatable, emptyLabel, loading, multiple, onCommit, onCreate, onSearch, onSelect, open, onOpenChange, options, renderOption, searchLabel, searchPlaceholder, selected, showSearch, testId, trigger, triggerClassName, triggerProps, }: {
|
|
13
18
|
contentClassName?: string;
|
|
19
|
+
creatable?: boolean;
|
|
14
20
|
emptyLabel?: string;
|
|
15
21
|
loading?: boolean;
|
|
16
22
|
multiple?: boolean;
|
|
23
|
+
onCommit?: (value: string) => void;
|
|
24
|
+
onCreate?: (label: string) => void;
|
|
17
25
|
onSearch?: (query: string) => void;
|
|
18
26
|
onSelect: (value: string) => void;
|
|
19
27
|
open: boolean;
|
|
20
28
|
onOpenChange: (open: boolean) => void;
|
|
21
29
|
options: Option[];
|
|
30
|
+
renderOption?: (option: Option) => React.ReactNode;
|
|
22
31
|
searchLabel?: string;
|
|
23
32
|
searchPlaceholder?: string;
|
|
24
33
|
selected: string[];
|
package/dist/ui/combobox.js
CHANGED
|
@@ -2,6 +2,7 @@ import { cn } from "../lib/utils.js";
|
|
|
2
2
|
import { Icon } from "../icons/sprite.js";
|
|
3
3
|
import { useT } from "../i18n/instance.js";
|
|
4
4
|
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
5
|
+
import { useDebouncedCallback } from "../lib/use-debounced-callback.js";
|
|
5
6
|
import { useEffect, useState } from "react";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
//#region resources/js/ui/combobox.tsx
|
|
@@ -13,19 +14,37 @@ var SEARCH_DEBOUNCE_MS = 250;
|
|
|
13
14
|
* consumer also owns option fetching. Pass `onSearch` for remote search (the
|
|
14
15
|
* combobox debounces the query and renders `options` as given); omit it to
|
|
15
16
|
* filter the provided `options` locally by label. The combobox closes itself
|
|
16
|
-
* after a single-select.
|
|
17
|
+
* after a single-select. Pass `renderOption` to render rich option rows; the
|
|
18
|
+
* option's label stays the accessible name. `onSelect` toggles selection
|
|
19
|
+
* (used by dropdown-row clicks); tag-entry commits (Enter/comma/paste) that
|
|
20
|
+
* match an existing option call `onCommit` instead, falling back to
|
|
21
|
+
* `onSelect` when it is not provided, so consumers can make tag entry
|
|
22
|
+
* additive instead of toggling.
|
|
17
23
|
*/
|
|
18
|
-
function Combobox({ contentClassName, emptyLabel, loading = false, multiple = false, onSearch, onSelect, open, onOpenChange, options, searchLabel, searchPlaceholder, selected, showSearch = true, testId, trigger, triggerClassName, triggerProps }) {
|
|
24
|
+
function Combobox({ contentClassName, creatable = false, emptyLabel, loading = false, multiple = false, onCommit, onCreate, onSearch, onSelect, open, onOpenChange, options, renderOption, searchLabel, searchPlaceholder, selected, showSearch = true, testId, trigger, triggerClassName, triggerProps }) {
|
|
19
25
|
const { t } = useT("lattice");
|
|
20
26
|
const [query, setQuery] = useState("");
|
|
27
|
+
function commitCreate(raw) {
|
|
28
|
+
const tokens = raw.split(",").map((token) => token.trim()).filter(Boolean);
|
|
29
|
+
for (const token of tokens) {
|
|
30
|
+
const match = options.find((option) => option.label.toLowerCase() === token.toLowerCase());
|
|
31
|
+
if (match) (onCommit ?? onSelect)(match.value);
|
|
32
|
+
else onCreate?.(token);
|
|
33
|
+
}
|
|
34
|
+
if (multiple) setQuery("");
|
|
35
|
+
else close();
|
|
36
|
+
}
|
|
37
|
+
const exactMatch = options.some((option) => option.label.toLowerCase() === query.trim().toLowerCase());
|
|
38
|
+
const runSearch = useDebouncedCallback((next) => onSearch?.(next), SEARCH_DEBOUNCE_MS);
|
|
21
39
|
useEffect(() => {
|
|
22
40
|
if (!onSearch || !open) return;
|
|
23
|
-
|
|
24
|
-
return () =>
|
|
41
|
+
runSearch(query);
|
|
42
|
+
return () => runSearch.cancel();
|
|
25
43
|
}, [
|
|
26
44
|
query,
|
|
27
45
|
onSearch,
|
|
28
|
-
open
|
|
46
|
+
open,
|
|
47
|
+
runSearch
|
|
29
48
|
]);
|
|
30
49
|
const visibleOptions = onSearch ? options : options.filter((option) => option.label.toLowerCase().includes(query.toLowerCase()));
|
|
31
50
|
function close() {
|
|
@@ -53,11 +72,24 @@ function Combobox({ contentClassName, emptyLabel, loading = false, multiple = fa
|
|
|
53
72
|
children: [showSearch && /* @__PURE__ */ jsxs("div", {
|
|
54
73
|
className: "flex items-center gap-2 border-b border-lt-border px-3 py-2",
|
|
55
74
|
children: [/* @__PURE__ */ jsx("input", {
|
|
56
|
-
"aria-label": searchLabel ?? t("form.
|
|
75
|
+
"aria-label": searchLabel ?? t("form.search-options", "Search options"),
|
|
57
76
|
"data-slot": "combobox-search",
|
|
58
77
|
"data-test": testId ? `${testId}-search` : void 0,
|
|
59
78
|
className: "w-full bg-transparent text-sm outline-none placeholder:text-lt-muted-fg",
|
|
60
|
-
onChange: (event) =>
|
|
79
|
+
onChange: (event) => {
|
|
80
|
+
const next = event.target.value;
|
|
81
|
+
if (creatable && next.includes(",")) {
|
|
82
|
+
commitCreate(next);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
setQuery(next);
|
|
86
|
+
},
|
|
87
|
+
onKeyDown: (event) => {
|
|
88
|
+
if (creatable && event.key === "Enter" && query.trim() !== "") {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
commitCreate(query);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
61
93
|
placeholder: searchPlaceholder,
|
|
62
94
|
value: query
|
|
63
95
|
}), loading && /* @__PURE__ */ jsx(Icon, {
|
|
@@ -65,15 +97,26 @@ function Combobox({ contentClassName, emptyLabel, loading = false, multiple = fa
|
|
|
65
97
|
"aria-hidden": "true",
|
|
66
98
|
className: "size-lt-icon-md shrink-0 animate-spin text-lt-muted-fg"
|
|
67
99
|
})]
|
|
68
|
-
}), /* @__PURE__ */
|
|
100
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
69
101
|
className: "max-h-60 overflow-y-auto p-1",
|
|
70
102
|
role: "listbox",
|
|
71
|
-
children:
|
|
103
|
+
children: [creatable && query.trim() !== "" && !exactMatch && /* @__PURE__ */ jsxs("button", {
|
|
104
|
+
className: "flex w-full items-center gap-2 rounded-lt-sm px-3 py-1.5 text-left text-sm transition-colors hover:bg-lt-accent hover:text-lt-accent-fg",
|
|
105
|
+
"data-test": testId ? `${testId}-create` : void 0,
|
|
106
|
+
onClick: () => commitCreate(query),
|
|
107
|
+
type: "button",
|
|
108
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
109
|
+
name: "plus",
|
|
110
|
+
"aria-hidden": "true",
|
|
111
|
+
className: "size-lt-icon-md shrink-0"
|
|
112
|
+
}), t("form.create-option", "Create \"{{label}}\"", { label: query.trim() })]
|
|
113
|
+
}), visibleOptions.length === 0 && !(creatable && query.trim() !== "" && !exactMatch) ? /* @__PURE__ */ jsx("p", {
|
|
72
114
|
className: "px-3 py-2 text-sm text-lt-muted-fg",
|
|
73
115
|
children: emptyLabel
|
|
74
116
|
}) : visibleOptions.map((option) => {
|
|
75
117
|
const isSelected = selected.includes(option.value);
|
|
76
118
|
return /* @__PURE__ */ jsxs("button", {
|
|
119
|
+
"aria-label": renderOption ? option.label : void 0,
|
|
77
120
|
"aria-selected": isSelected,
|
|
78
121
|
className: cn("flex w-full items-center justify-between gap-2 rounded-lt-sm px-3 py-1.5 text-left text-sm transition-colors hover:bg-lt-accent hover:text-lt-accent-fg", isSelected && "bg-lt-accent/60"),
|
|
79
122
|
"data-slot": "combobox-option",
|
|
@@ -82,13 +125,16 @@ function Combobox({ contentClassName, emptyLabel, loading = false, multiple = fa
|
|
|
82
125
|
onClick: () => choose(option.value),
|
|
83
126
|
role: "option",
|
|
84
127
|
type: "button",
|
|
85
|
-
children: [
|
|
128
|
+
children: [renderOption ? /* @__PURE__ */ jsx("span", {
|
|
129
|
+
className: "flex min-w-0 flex-1 items-center gap-2",
|
|
130
|
+
children: renderOption(option)
|
|
131
|
+
}) : option.label, isSelected && /* @__PURE__ */ jsx(Icon, {
|
|
86
132
|
name: "check",
|
|
87
133
|
"aria-hidden": "true",
|
|
88
134
|
className: "size-lt-icon-md shrink-0"
|
|
89
135
|
})]
|
|
90
136
|
}, option.value);
|
|
91
|
-
})
|
|
137
|
+
})]
|
|
92
138
|
})]
|
|
93
139
|
})]
|
|
94
140
|
});
|
package/dist/ui/combobox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","names":[],"sources":["../../resources/js/ui/combobox.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { Option } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\nconst SEARCH_DEBOUNCE_MS = 250;\n\n/**\n * A popover select list with an optional search box and single/multi selection.\n *\n * Selection state is controlled by the consumer (`selected` + `onSelect`); the\n * consumer also owns option fetching. Pass `onSearch` for remote search (the\n * combobox debounces the query and renders `options` as given); omit it to\n * filter the provided `options` locally by label. The combobox closes itself\n * after a single-select.\n */\nfunction Combobox({\n contentClassName,\n emptyLabel,\n loading = false,\n multiple = false,\n onSearch,\n onSelect,\n open,\n onOpenChange,\n options,\n searchLabel,\n searchPlaceholder,\n selected,\n showSearch = true,\n testId,\n trigger,\n triggerClassName,\n triggerProps,\n}: {\n contentClassName?: string;\n emptyLabel?: string;\n loading?: boolean;\n multiple?: boolean;\n onSearch?: (query: string) => void;\n onSelect: (value: string) => void;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n options: Option[];\n searchLabel?: string;\n searchPlaceholder?: string;\n selected: string[];\n showSearch?: boolean;\n testId?: string;\n trigger: React.ReactNode;\n triggerClassName?: string;\n triggerProps?: React.ComponentProps<\"button\"> & { \"data-test\"?: string };\n}) {\n const { t } = useT(\"lattice\");\n const [query, setQuery] = useState(\"\");\n\n useEffect(() => {\n if (!onSearch || !open) {\n return;\n }\n\n const timer = window.setTimeout(() => onSearch(query), SEARCH_DEBOUNCE_MS);\n\n return () => window.clearTimeout(timer);\n }, [query, onSearch, open]);\n\n const visibleOptions = onSearch\n ? options\n : options.filter((option) => option.label.toLowerCase().includes(query.toLowerCase()));\n\n function close(): void {\n setQuery(\"\");\n onOpenChange(false);\n }\n\n function choose(value: string): void {\n onSelect(value);\n\n if (!multiple) {\n close();\n }\n }\n\n return (\n <Popover open={open} onOpenChange={(next) => (next ? onOpenChange(true) : close())}>\n <PopoverTrigger asChild>\n <button type=\"button\" className={triggerClassName} {...triggerProps}>\n {trigger}\n </button>\n </PopoverTrigger>\n\n <PopoverContent\n align=\"start\"\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] overflow-hidden p-0\",\n contentClassName,\n )}\n >\n {showSearch && (\n <div className=\"flex items-center gap-2 border-b border-lt-border px-3 py-2\">\n <input\n aria-label={searchLabel ?? t(\"form.searchOptions\", \"Search options\")}\n data-slot=\"combobox-search\"\n data-test={testId ? `${testId}-search` : undefined}\n className=\"w-full bg-transparent text-sm outline-none placeholder:text-lt-muted-fg\"\n onChange={(event) => setQuery(event.target.value)}\n placeholder={searchPlaceholder}\n value={query}\n />\n {loading && (\n <Icon\n name=\"loader-2\"\n aria-hidden=\"true\"\n className=\"size-lt-icon-md shrink-0 animate-spin text-lt-muted-fg\"\n />\n )}\n </div>\n )}\n\n <div className=\"max-h-60 overflow-y-auto p-1\" role=\"listbox\">\n {visibleOptions.length === 0 ? (\n <p className=\"px-3 py-2 text-sm text-lt-muted-fg\">{emptyLabel}</p>\n ) : (\n visibleOptions.map((option) => {\n const isSelected = selected.includes(option.value);\n\n return (\n <button\n aria-selected={isSelected}\n className={cn(\n \"flex w-full items-center justify-between gap-2 rounded-lt-sm px-3 py-1.5 text-left text-sm transition-colors hover:bg-lt-accent hover:text-lt-accent-fg\",\n isSelected && \"bg-lt-accent/60\",\n )}\n data-slot=\"combobox-option\"\n data-test={testId ? `${testId}-option-${option.value}` : undefined}\n data-value={option.value}\n key={option.value}\n onClick={() => choose(option.value)}\n role=\"option\"\n type=\"button\"\n >\n {option.label}\n {isSelected && (\n <Icon name=\"check\" aria-hidden=\"true\" className=\"size-lt-icon-md shrink-0\" />\n )}\n </button>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport { Combobox };\n"],"mappings":";;;;;;;AAQA,IAAM,qBAAqB;;;;;;;;;;AAW3B,SAAS,SAAS,EAChB,kBACA,YACA,UAAU,OACV,WAAW,OACX,UACA,UACA,MACA,cACA,SACA,aACA,mBACA,UACA,aAAa,MACb,QACA,SACA,kBACA,gBAmBC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CAErC,gBAAgB;EACd,IAAI,CAAC,YAAY,CAAC,MAChB;EAGF,MAAM,QAAQ,OAAO,iBAAiB,SAAS,KAAK,GAAG,kBAAkB;EAEzE,aAAa,OAAO,aAAa,KAAK;CACxC,GAAG;EAAC;EAAO;EAAU;CAAI,CAAC;CAE1B,MAAM,iBAAiB,WACnB,UACA,QAAQ,QAAQ,WAAW,OAAO,MAAM,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC,CAAC;CAEvF,SAAS,QAAc;EACrB,SAAS,EAAE;EACX,aAAa,KAAK;CACpB;CAEA,SAAS,OAAO,OAAqB;EACnC,SAAS,KAAK;EAEd,IAAI,CAAC,UACH,MAAM;CAEV;CAEA,OACE,qBAAC,SAAD;EAAe;EAAM,eAAe,SAAU,OAAO,aAAa,IAAI,IAAI,MAAM;YAAhF,CACE,oBAAC,gBAAD;GAAgB,SAAA;aACd,oBAAC,UAAD;IAAQ,MAAK;IAAS,WAAW;IAAkB,GAAI;cACpD;GACK,CAAA;EACM,CAAA,GAEhB,qBAAC,gBAAD;GACE,OAAM;GACN,WAAW,GACT,8DACA,gBACF;aALF,CAOG,cACC,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,SAAD;KACE,cAAY,eAAe,EAAE,sBAAsB,gBAAgB;KACnE,aAAU;KACV,aAAW,SAAS,GAAG,OAAO,WAAW,KAAA;KACzC,WAAU;KACV,WAAW,UAAU,SAAS,MAAM,OAAO,KAAK;KAChD,aAAa;KACb,OAAO;IACR,CAAA,GACA,WACC,oBAAC,MAAD;KACE,MAAK;KACL,eAAY;KACZ,WAAU;IACX,CAAA,CAEA;OAGP,oBAAC,OAAD;IAAK,WAAU;IAA+B,MAAK;cAChD,eAAe,WAAW,IACzB,oBAAC,KAAD;KAAG,WAAU;eAAsC;IAAc,CAAA,IAEjE,eAAe,KAAK,WAAW;KAC7B,MAAM,aAAa,SAAS,SAAS,OAAO,KAAK;KAEjD,OACE,qBAAC,UAAD;MACE,iBAAe;MACf,WAAW,GACT,2JACA,cAAc,iBAChB;MACA,aAAU;MACV,aAAW,SAAS,GAAG,OAAO,UAAU,OAAO,UAAU,KAAA;MACzD,cAAY,OAAO;MAEnB,eAAe,OAAO,OAAO,KAAK;MAClC,MAAK;MACL,MAAK;gBAZP,CAcG,OAAO,OACP,cACC,oBAAC,MAAD;OAAM,MAAK;OAAQ,eAAY;OAAO,WAAU;MAA4B,CAAA,CAExE;QATD,OAAO,KASN;IAEZ,CAAC;GAEA,CAAA,CACS;IACT;;AAEb"}
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../resources/js/ui/combobox.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport * as React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { Option } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { useDebouncedCallback } from \"@lattice-php/lattice/lib/use-debounced-callback\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\n\nconst SEARCH_DEBOUNCE_MS = 250;\n\n/**\n * A popover select list with an optional search box and single/multi selection.\n *\n * Selection state is controlled by the consumer (`selected` + `onSelect`); the\n * consumer also owns option fetching. Pass `onSearch` for remote search (the\n * combobox debounces the query and renders `options` as given); omit it to\n * filter the provided `options` locally by label. The combobox closes itself\n * after a single-select. Pass `renderOption` to render rich option rows; the\n * option's label stays the accessible name. `onSelect` toggles selection\n * (used by dropdown-row clicks); tag-entry commits (Enter/comma/paste) that\n * match an existing option call `onCommit` instead, falling back to\n * `onSelect` when it is not provided, so consumers can make tag entry\n * additive instead of toggling.\n */\nfunction Combobox({\n contentClassName,\n creatable = false,\n emptyLabel,\n loading = false,\n multiple = false,\n onCommit,\n onCreate,\n onSearch,\n onSelect,\n open,\n onOpenChange,\n options,\n renderOption,\n searchLabel,\n searchPlaceholder,\n selected,\n showSearch = true,\n testId,\n trigger,\n triggerClassName,\n triggerProps,\n}: {\n contentClassName?: string;\n creatable?: boolean;\n emptyLabel?: string;\n loading?: boolean;\n multiple?: boolean;\n onCommit?: (value: string) => void;\n onCreate?: (label: string) => void;\n onSearch?: (query: string) => void;\n onSelect: (value: string) => void;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n options: Option[];\n renderOption?: (option: Option) => React.ReactNode;\n searchLabel?: string;\n searchPlaceholder?: string;\n selected: string[];\n showSearch?: boolean;\n testId?: string;\n trigger: React.ReactNode;\n triggerClassName?: string;\n triggerProps?: React.ComponentProps<\"button\"> & { \"data-test\"?: string };\n}) {\n const { t } = useT(\"lattice\");\n const [query, setQuery] = useState(\"\");\n\n function commitCreate(raw: string): void {\n const tokens = raw\n .split(\",\")\n .map((token) => token.trim())\n .filter(Boolean);\n\n for (const token of tokens) {\n const match = options.find((option) => option.label.toLowerCase() === token.toLowerCase());\n\n if (match) {\n (onCommit ?? onSelect)(match.value);\n } else {\n onCreate?.(token);\n }\n }\n\n if (multiple) {\n setQuery(\"\");\n } else {\n close();\n }\n }\n\n const exactMatch = options.some(\n (option) => option.label.toLowerCase() === query.trim().toLowerCase(),\n );\n\n const runSearch = useDebouncedCallback((next: string) => onSearch?.(next), SEARCH_DEBOUNCE_MS);\n\n useEffect(() => {\n if (!onSearch || !open) {\n return;\n }\n\n runSearch(query);\n\n return () => runSearch.cancel();\n }, [query, onSearch, open, runSearch]);\n\n const visibleOptions = onSearch\n ? options\n : options.filter((option) => option.label.toLowerCase().includes(query.toLowerCase()));\n\n function close(): void {\n setQuery(\"\");\n onOpenChange(false);\n }\n\n function choose(value: string): void {\n onSelect(value);\n\n if (!multiple) {\n close();\n }\n }\n\n return (\n <Popover open={open} onOpenChange={(next) => (next ? onOpenChange(true) : close())}>\n <PopoverTrigger asChild>\n <button type=\"button\" className={triggerClassName} {...triggerProps}>\n {trigger}\n </button>\n </PopoverTrigger>\n\n <PopoverContent\n align=\"start\"\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] overflow-hidden p-0\",\n contentClassName,\n )}\n >\n {showSearch && (\n <div className=\"flex items-center gap-2 border-b border-lt-border px-3 py-2\">\n <input\n aria-label={searchLabel ?? t(\"form.search-options\", \"Search options\")}\n data-slot=\"combobox-search\"\n data-test={testId ? `${testId}-search` : undefined}\n className=\"w-full bg-transparent text-sm outline-none placeholder:text-lt-muted-fg\"\n onChange={(event) => {\n const next = event.target.value;\n\n if (creatable && next.includes(\",\")) {\n commitCreate(next);\n\n return;\n }\n\n setQuery(next);\n }}\n onKeyDown={(event) => {\n if (creatable && event.key === \"Enter\" && query.trim() !== \"\") {\n event.preventDefault();\n commitCreate(query);\n }\n }}\n placeholder={searchPlaceholder}\n value={query}\n />\n {loading && (\n <Icon\n name=\"loader-2\"\n aria-hidden=\"true\"\n className=\"size-lt-icon-md shrink-0 animate-spin text-lt-muted-fg\"\n />\n )}\n </div>\n )}\n\n <div className=\"max-h-60 overflow-y-auto p-1\" role=\"listbox\">\n {creatable && query.trim() !== \"\" && !exactMatch && (\n <button\n className=\"flex w-full items-center gap-2 rounded-lt-sm px-3 py-1.5 text-left text-sm transition-colors hover:bg-lt-accent hover:text-lt-accent-fg\"\n data-test={testId ? `${testId}-create` : undefined}\n onClick={() => commitCreate(query)}\n type=\"button\"\n >\n <Icon name=\"plus\" aria-hidden=\"true\" className=\"size-lt-icon-md shrink-0\" />\n {t(\"form.create-option\", 'Create \"{{label}}\"', { label: query.trim() })}\n </button>\n )}\n\n {visibleOptions.length === 0 && !(creatable && query.trim() !== \"\" && !exactMatch) ? (\n <p className=\"px-3 py-2 text-sm text-lt-muted-fg\">{emptyLabel}</p>\n ) : (\n visibleOptions.map((option) => {\n const isSelected = selected.includes(option.value);\n\n return (\n <button\n aria-label={renderOption ? option.label : undefined}\n aria-selected={isSelected}\n className={cn(\n \"flex w-full items-center justify-between gap-2 rounded-lt-sm px-3 py-1.5 text-left text-sm transition-colors hover:bg-lt-accent hover:text-lt-accent-fg\",\n isSelected && \"bg-lt-accent/60\",\n )}\n data-slot=\"combobox-option\"\n data-test={testId ? `${testId}-option-${option.value}` : undefined}\n data-value={option.value}\n key={option.value}\n onClick={() => choose(option.value)}\n role=\"option\"\n type=\"button\"\n >\n {renderOption ? (\n <span className=\"flex min-w-0 flex-1 items-center gap-2\">\n {renderOption(option)}\n </span>\n ) : (\n option.label\n )}\n {isSelected && (\n <Icon name=\"check\" aria-hidden=\"true\" className=\"size-lt-icon-md shrink-0\" />\n )}\n </button>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport { Combobox };\n"],"mappings":";;;;;;;;AASA,IAAM,qBAAqB;;;;;;;;;;;;;;;AAgB3B,SAAS,SAAS,EAChB,kBACA,YAAY,OACZ,YACA,UAAU,OACV,WAAW,OACX,UACA,UACA,UACA,UACA,MACA,cACA,SACA,cACA,aACA,mBACA,UACA,aAAa,MACb,QACA,SACA,kBACA,gBAuBC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAS,EAAE;CAErC,SAAS,aAAa,KAAmB;EACvC,MAAM,SAAS,IACZ,MAAM,GAAG,EACT,KAAK,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,OAAO;EAEjB,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,QAAQ,QAAQ,MAAM,WAAW,OAAO,MAAM,YAAY,MAAM,MAAM,YAAY,CAAC;GAEzF,IAAI,OACF,CAAC,YAAY,UAAU,MAAM,KAAK;QAElC,WAAW,KAAK;EAEpB;EAEA,IAAI,UACF,SAAS,EAAE;OAEX,MAAM;CAEV;CAEA,MAAM,aAAa,QAAQ,MACxB,WAAW,OAAO,MAAM,YAAY,MAAM,MAAM,KAAK,EAAE,YAAY,CACtE;CAEA,MAAM,YAAY,sBAAsB,SAAiB,WAAW,IAAI,GAAG,kBAAkB;CAE7F,gBAAgB;EACd,IAAI,CAAC,YAAY,CAAC,MAChB;EAGF,UAAU,KAAK;EAEf,aAAa,UAAU,OAAO;CAChC,GAAG;EAAC;EAAO;EAAU;EAAM;CAAS,CAAC;CAErC,MAAM,iBAAiB,WACnB,UACA,QAAQ,QAAQ,WAAW,OAAO,MAAM,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC,CAAC;CAEvF,SAAS,QAAc;EACrB,SAAS,EAAE;EACX,aAAa,KAAK;CACpB;CAEA,SAAS,OAAO,OAAqB;EACnC,SAAS,KAAK;EAEd,IAAI,CAAC,UACH,MAAM;CAEV;CAEA,OACE,qBAAC,SAAD;EAAe;EAAM,eAAe,SAAU,OAAO,aAAa,IAAI,IAAI,MAAM;YAAhF,CACE,oBAAC,gBAAD;GAAgB,SAAA;aACd,oBAAC,UAAD;IAAQ,MAAK;IAAS,WAAW;IAAkB,GAAI;cACpD;GACK,CAAA;EACM,CAAA,GAEhB,qBAAC,gBAAD;GACE,OAAM;GACN,WAAW,GACT,8DACA,gBACF;aALF,CAOG,cACC,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,SAAD;KACE,cAAY,eAAe,EAAE,uBAAuB,gBAAgB;KACpE,aAAU;KACV,aAAW,SAAS,GAAG,OAAO,WAAW,KAAA;KACzC,WAAU;KACV,WAAW,UAAU;MACnB,MAAM,OAAO,MAAM,OAAO;MAE1B,IAAI,aAAa,KAAK,SAAS,GAAG,GAAG;OACnC,aAAa,IAAI;OAEjB;MACF;MAEA,SAAS,IAAI;KACf;KACA,YAAY,UAAU;MACpB,IAAI,aAAa,MAAM,QAAQ,WAAW,MAAM,KAAK,MAAM,IAAI;OAC7D,MAAM,eAAe;OACrB,aAAa,KAAK;MACpB;KACF;KACA,aAAa;KACb,OAAO;IACR,CAAA,GACA,WACC,oBAAC,MAAD;KACE,MAAK;KACL,eAAY;KACZ,WAAU;IACX,CAAA,CAEA;OAGP,qBAAC,OAAD;IAAK,WAAU;IAA+B,MAAK;cAAnD,CACG,aAAa,MAAM,KAAK,MAAM,MAAM,CAAC,cACpC,qBAAC,UAAD;KACE,WAAU;KACV,aAAW,SAAS,GAAG,OAAO,WAAW,KAAA;KACzC,eAAe,aAAa,KAAK;KACjC,MAAK;eAJP,CAME,oBAAC,MAAD;MAAM,MAAK;MAAO,eAAY;MAAO,WAAU;KAA4B,CAAA,GAC1E,EAAE,sBAAsB,wBAAsB,EAAE,OAAO,MAAM,KAAK,EAAE,CAAC,CAChE;QAGT,eAAe,WAAW,KAAK,EAAE,aAAa,MAAM,KAAK,MAAM,MAAM,CAAC,cACrE,oBAAC,KAAD;KAAG,WAAU;eAAsC;IAAc,CAAA,IAEjE,eAAe,KAAK,WAAW;KAC7B,MAAM,aAAa,SAAS,SAAS,OAAO,KAAK;KAEjD,OACE,qBAAC,UAAD;MACE,cAAY,eAAe,OAAO,QAAQ,KAAA;MAC1C,iBAAe;MACf,WAAW,GACT,2JACA,cAAc,iBAChB;MACA,aAAU;MACV,aAAW,SAAS,GAAG,OAAO,UAAU,OAAO,UAAU,KAAA;MACzD,cAAY,OAAO;MAEnB,eAAe,OAAO,OAAO,KAAK;MAClC,MAAK;MACL,MAAK;gBAbP,CAeG,eACC,oBAAC,QAAD;OAAM,WAAU;iBACb,aAAa,MAAM;MAChB,CAAA,IAEN,OAAO,OAER,cACC,oBAAC,MAAD;OAAM,MAAK;OAAQ,eAAY;OAAO,WAAU;MAA4B,CAAA,CAExE;QAfD,OAAO,KAeN;IAEZ,CAAC,CAEA;KACS;IACT;;AAEb"}
|
|
@@ -14,7 +14,7 @@ function ConfirmDialog({ title, description, confirmLabel, cancelLabel = "Cancel
|
|
|
14
14
|
},
|
|
15
15
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
16
16
|
...description ? {} : { "aria-describedby": void 0 },
|
|
17
|
-
|
|
17
|
+
width: "md",
|
|
18
18
|
onEscapeKeyDown: blockWhileProcessing,
|
|
19
19
|
onInteractOutside: blockWhileProcessing,
|
|
20
20
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm-dialog.js","names":[],"sources":["../../resources/js/ui/confirm-dialog.tsx"],"sourcesContent":["import type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\nimport { Button } from \"./button\";\nimport { Dialog, DialogContent, DialogDescription, DialogTitle } from \"./dialog\";\nimport { Spinner } from \"./spinner\";\n\nexport function ConfirmDialog({\n title,\n description,\n confirmLabel,\n cancelLabel = \"Cancel\",\n confirmVariant = \"default\",\n processing = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n}: {\n title: string;\n description?: string;\n confirmLabel: string;\n cancelLabel?: string;\n confirmVariant?: ButtonVariant;\n processing?: boolean;\n confirmDisabled?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}) {\n const blockWhileProcessing = (event: Event): void => {\n if (processing) {\n event.preventDefault();\n }\n };\n\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) {\n onCancel();\n }\n }}\n >\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n
|
|
1
|
+
{"version":3,"file":"confirm-dialog.js","names":[],"sources":["../../resources/js/ui/confirm-dialog.tsx"],"sourcesContent":["import type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\nimport { Button } from \"./button\";\nimport { Dialog, DialogContent, DialogDescription, DialogTitle } from \"./dialog\";\nimport { Spinner } from \"./spinner\";\n\nexport function ConfirmDialog({\n title,\n description,\n confirmLabel,\n cancelLabel = \"Cancel\",\n confirmVariant = \"default\",\n processing = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n}: {\n title: string;\n description?: string;\n confirmLabel: string;\n cancelLabel?: string;\n confirmVariant?: ButtonVariant;\n processing?: boolean;\n confirmDisabled?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}) {\n const blockWhileProcessing = (event: Event): void => {\n if (processing) {\n event.preventDefault();\n }\n };\n\n return (\n <Dialog\n open\n onOpenChange={(open) => {\n if (!open) {\n onCancel();\n }\n }}\n >\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n width=\"md\"\n onEscapeKeyDown={blockWhileProcessing}\n onInteractOutside={blockWhileProcessing}\n >\n <div className=\"grid gap-2\">\n <DialogTitle>{title}</DialogTitle>\n {description && <DialogDescription>{description}</DialogDescription>}\n </div>\n <div className=\"mt-6 flex justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n data-test=\"confirm-cancel\"\n disabled={processing}\n onClick={onCancel}\n >\n {cancelLabel}\n </Button>\n <Button\n type=\"button\"\n variant={confirmVariant}\n data-test=\"confirm-accept\"\n disabled={processing || confirmDisabled}\n onClick={onConfirm}\n >\n {processing && <Spinner />}\n {confirmLabel}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;AAKA,SAAgB,cAAc,EAC5B,OACA,aACA,cACA,cAAc,UACd,iBAAiB,WACjB,aAAa,OACb,kBAAkB,OAClB,WACA,YAWC;CACD,MAAM,wBAAwB,UAAuB;EACnD,IAAI,YACF,MAAM,eAAe;CAEzB;CAEA,OACE,oBAAC,QAAD;EACE,MAAA;EACA,eAAe,SAAS;GACtB,IAAI,CAAC,MACH,SAAS;EAEb;YAEA,qBAAC,eAAD;GACE,GAAK,cAAc,CAAC,IAAI,EAAE,oBAAoB,KAAA,EAAU;GACxD,OAAM;GACN,iBAAiB;GACjB,mBAAmB;aAJrB,CAME,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,aAAD,EAAA,UAAc,MAAmB,CAAA,GAChC,eAAe,oBAAC,mBAAD,EAAA,UAAoB,YAA+B,CAAA,CAChE;OACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,aAAU;KACV,UAAU;KACV,SAAS;eAER;IACK,CAAA,GACR,qBAAC,QAAD;KACE,MAAK;KACL,SAAS;KACT,aAAU;KACV,UAAU,cAAc;KACxB,SAAS;eALX,CAOG,cAAc,oBAAC,SAAD,CAAU,CAAA,GACxB,YACK;MACL;KACQ;;CACT,CAAA;AAEZ"}
|
package/dist/ui/control.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export declare const FOCUS_RING = "focus-visible:border-lt-ring focus-visible:ri
|
|
|
6
6
|
* border, focus ring, invalid, and disabled treatment are unified.
|
|
7
7
|
*/
|
|
8
8
|
export declare const controlSurface: (props?: ({
|
|
9
|
-
density?: "
|
|
9
|
+
density?: "compact" | "comfortable" | null | undefined;
|
|
10
10
|
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
export declare function copyToClipboard(text: string): Promise<boolean>;
|
|
3
|
+
interface CopyButtonProps {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
testId?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function CopyButton({ value, label, testId, className }: CopyButtonProps): ReactNode;
|
|
3
10
|
interface CopyableTextProps {
|
|
4
11
|
value: string;
|
|
5
12
|
label: string;
|
package/dist/ui/copyable-text.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
1
2
|
import { Icon } from "../icons/sprite.js";
|
|
2
3
|
import { useT } from "../i18n/instance.js";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
@@ -12,7 +13,7 @@ async function copyToClipboard(text) {
|
|
|
12
13
|
return false;
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
|
-
function
|
|
16
|
+
function CopyButton({ value, label, testId, className }) {
|
|
16
17
|
const { t } = useT("lattice");
|
|
17
18
|
const [copied, setCopied] = useState(false);
|
|
18
19
|
useEffect(() => {
|
|
@@ -24,23 +25,30 @@ function CopyableText({ value, label, testId, children }) {
|
|
|
24
25
|
copyToClipboard(value);
|
|
25
26
|
setCopied(true);
|
|
26
27
|
}
|
|
27
|
-
const ariaLabel = copied ? t("common.
|
|
28
|
+
const ariaLabel = copied ? t("common.copied-value", "Copied {{label}}", { label }) : t("common.copy-value", "Copy {{label}}", { label });
|
|
29
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
30
|
+
type: "button",
|
|
31
|
+
"data-test": testId,
|
|
32
|
+
className: cn("inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs", className),
|
|
33
|
+
"aria-label": ariaLabel,
|
|
34
|
+
onClick: handleCopy,
|
|
35
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
36
|
+
name: copied ? "check" : "copy",
|
|
37
|
+
className: "size-lt-icon-xs"
|
|
38
|
+
}), copied ? t("common.copied", "Copied") : t("common.copy", "Copy")]
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function CopyableText({ value, label, testId, children }) {
|
|
28
42
|
return /* @__PURE__ */ jsxs("div", {
|
|
29
43
|
className: "inline-flex items-center gap-2",
|
|
30
|
-
children: [children ?? value, /* @__PURE__ */
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"aria-label": ariaLabel,
|
|
35
|
-
onClick: handleCopy,
|
|
36
|
-
children: [/* @__PURE__ */ jsx(Icon, {
|
|
37
|
-
name: copied ? "check" : "copy",
|
|
38
|
-
className: "size-lt-icon-xs"
|
|
39
|
-
}), copied ? t("common.copied", "Copied") : t("common.copy", "Copy")]
|
|
44
|
+
children: [children ?? value, /* @__PURE__ */ jsx(CopyButton, {
|
|
45
|
+
value,
|
|
46
|
+
label,
|
|
47
|
+
testId
|
|
40
48
|
})]
|
|
41
49
|
});
|
|
42
50
|
}
|
|
43
51
|
//#endregion
|
|
44
|
-
export { CopyableText, copyToClipboard };
|
|
52
|
+
export { CopyButton, CopyableText, copyToClipboard };
|
|
45
53
|
|
|
46
54
|
//# sourceMappingURL=copyable-text.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copyable-text.js","names":[],"sources":["../../resources/js/ui/copyable-text.tsx"],"sourcesContent":["import { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\ninterface
|
|
1
|
+
{"version":3,"file":"copyable-text.js","names":[],"sources":["../../resources/js/ui/copyable-text.tsx"],"sourcesContent":["import { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\ninterface CopyButtonProps {\n value: string;\n label: string;\n testId?: string;\n className?: string;\n}\n\nexport function CopyButton({ value, label, testId, className }: CopyButtonProps): ReactNode {\n const { t } = useT(\"lattice\");\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n if (!copied) {\n return;\n }\n\n const timeout = window.setTimeout(() => setCopied(false), 1500);\n\n return () => window.clearTimeout(timeout);\n }, [copied]);\n\n function handleCopy(): void {\n void copyToClipboard(value);\n setCopied(true);\n }\n\n const ariaLabel = copied\n ? t(\"common.copied-value\", \"Copied {{label}}\", { label })\n : t(\"common.copy-value\", \"Copy {{label}}\", { label });\n\n return (\n <button\n type=\"button\"\n data-test={testId}\n className={cn(\n \"inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs\",\n className,\n )}\n aria-label={ariaLabel}\n onClick={handleCopy}\n >\n <Icon name={copied ? \"check\" : \"copy\"} className=\"size-lt-icon-xs\" />\n {copied ? t(\"common.copied\", \"Copied\") : t(\"common.copy\", \"Copy\")}\n </button>\n );\n}\n\ninterface CopyableTextProps {\n value: string;\n label: string;\n testId?: string;\n children?: ReactNode;\n}\n\nexport function CopyableText({ value, label, testId, children }: CopyableTextProps): ReactNode {\n return (\n <div className=\"inline-flex items-center gap-2\">\n {children ?? value}\n <CopyButton value={value} label={label} testId={testId} />\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,eAAsB,gBAAgB,MAAgC;CACpE,IAAI,CAAC,WAAW,WACd,OAAO;CAGT,IAAI;EACF,MAAM,UAAU,UAAU,UAAU,IAAI;EAExC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AASA,SAAgB,WAAW,EAAE,OAAO,OAAO,QAAQ,aAAyC;CAC1F,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,UAAU,OAAO,iBAAiB,UAAU,KAAK,GAAG,IAAI;EAE9D,aAAa,OAAO,aAAa,OAAO;CAC1C,GAAG,CAAC,MAAM,CAAC;CAEX,SAAS,aAAmB;EAC1B,gBAAqB,KAAK;EAC1B,UAAU,IAAI;CAChB;CAEA,MAAM,YAAY,SACd,EAAE,uBAAuB,oBAAoB,EAAE,MAAM,CAAC,IACtD,EAAE,qBAAqB,kBAAkB,EAAE,MAAM,CAAC;CAEtD,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAW;EACX,WAAW,GACT,0FACA,SACF;EACA,cAAY;EACZ,SAAS;YARX,CAUE,oBAAC,MAAD;GAAM,MAAM,SAAS,UAAU;GAAQ,WAAU;EAAmB,CAAA,GACnE,SAAS,EAAE,iBAAiB,QAAQ,IAAI,EAAE,eAAe,MAAM,CAC1D;;AAEZ;AASA,SAAgB,aAAa,EAAE,OAAO,OAAO,QAAQ,YAA0C;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,YAAY,OACb,oBAAC,YAAD;GAAmB;GAAc;GAAe;EAAS,CAAA,CACtD;;AAET"}
|
package/dist/ui/dialog.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { ModalWidth, Side } from '../types/generated.js';
|
|
1
2
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
2
3
|
import * as React from "react";
|
|
3
|
-
export
|
|
4
|
+
export type DialogPlacement = "center" | Side;
|
|
4
5
|
declare function Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>): React.JSX.Element;
|
|
5
6
|
declare function DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>): React.JSX.Element;
|
|
6
7
|
declare function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>): React.JSX.Element;
|
|
7
8
|
declare function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>): React.JSX.Element;
|
|
8
|
-
declare function DialogContent({ children, className, ...props }: React.ComponentProps<typeof DialogPrimitive.Content>
|
|
9
|
+
declare function DialogContent({ children, className, placement, width, ...props }: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
10
|
+
placement?: DialogPlacement;
|
|
11
|
+
width?: ModalWidth;
|
|
12
|
+
}): React.JSX.Element;
|
|
9
13
|
/**
|
|
10
14
|
* The shared dialog header: a title with an optional description and a ghost
|
|
11
15
|
* close button. Pass `description` as `undefined` to suppress the description
|
package/dist/ui/dialog.js
CHANGED
|
@@ -3,9 +3,30 @@ import { Icon } from "../icons/sprite.js";
|
|
|
3
3
|
import { Button } from "./button.js";
|
|
4
4
|
import "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
6
7
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
7
8
|
//#region resources/js/ui/dialog.tsx
|
|
8
|
-
var
|
|
9
|
+
var dialogContentVariants = cva("fixed z-lt-modal w-full overflow-y-auto bg-lt-bg p-6 shadow-lt-lg", {
|
|
10
|
+
variants: {
|
|
11
|
+
placement: {
|
|
12
|
+
center: "left-1/2 top-1/2 max-h-[min(680px,calc(100vh-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-lt border border-lt-border data-[state=open]:animate-lt-dialog-in data-[state=closed]:animate-lt-dialog-out",
|
|
13
|
+
start: "inset-y-0 start-0 border-e border-lt-border data-[state=open]:animate-lt-sheet-in-start data-[state=closed]:animate-lt-sheet-out-start",
|
|
14
|
+
end: "inset-y-0 end-0 border-s border-lt-border data-[state=open]:animate-lt-sheet-in-end data-[state=closed]:animate-lt-sheet-out-end"
|
|
15
|
+
},
|
|
16
|
+
width: {
|
|
17
|
+
sm: "max-w-sm",
|
|
18
|
+
md: "max-w-md",
|
|
19
|
+
lg: "max-w-lg",
|
|
20
|
+
xl: "max-w-xl",
|
|
21
|
+
"2xl": "max-w-2xl",
|
|
22
|
+
"3xl": "max-w-3xl"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
placement: "center",
|
|
27
|
+
width: "lg"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
9
30
|
function Dialog(props) {
|
|
10
31
|
return /* @__PURE__ */ jsx(DialogPrimitive.Root, {
|
|
11
32
|
"data-slot": "dialog",
|
|
@@ -32,12 +53,15 @@ function DialogDescription({ className, ...props }) {
|
|
|
32
53
|
...props
|
|
33
54
|
});
|
|
34
55
|
}
|
|
35
|
-
function DialogContent({ children, className, ...props }) {
|
|
56
|
+
function DialogContent({ children, className, placement = "center", width = "lg", ...props }) {
|
|
36
57
|
return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [/* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
|
|
37
|
-
className: "fixed inset-0 z-lt-overlay bg-lt-overlay",
|
|
58
|
+
className: "fixed inset-0 z-lt-overlay bg-lt-overlay data-[state=open]:animate-lt-fade-in data-[state=closed]:animate-lt-fade-out",
|
|
38
59
|
"data-slot": "dialog-overlay"
|
|
39
60
|
}), /* @__PURE__ */ jsx(DialogPrimitive.Content, {
|
|
40
|
-
className: cn(
|
|
61
|
+
className: cn(dialogContentVariants({
|
|
62
|
+
placement,
|
|
63
|
+
width
|
|
64
|
+
}), className),
|
|
41
65
|
"data-slot": "dialog-content",
|
|
42
66
|
...props,
|
|
43
67
|
children
|
|
@@ -71,6 +95,6 @@ function DialogHeader({ closeLabel, description, title }) {
|
|
|
71
95
|
});
|
|
72
96
|
}
|
|
73
97
|
//#endregion
|
|
74
|
-
export {
|
|
98
|
+
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle };
|
|
75
99
|
|
|
76
100
|
//# sourceMappingURL=dialog.js.map
|
package/dist/ui/dialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.js","names":[],"sources":["../../resources/js/ui/dialog.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\n\nexport
|
|
1
|
+
{"version":3,"file":"dialog.js","names":[],"sources":["../../resources/js/ui/dialog.tsx"],"sourcesContent":["import { Icon } from \"@lattice-php/lattice/icons\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { ModalWidth, Side } from \"@lattice-php/lattice/types/generated\";\n\nexport type DialogPlacement = \"center\" | Side;\n\nconst dialogContentVariants = cva(\n \"fixed z-lt-modal w-full overflow-y-auto bg-lt-bg p-6 shadow-lt-lg\",\n {\n variants: {\n placement: {\n center:\n \"left-1/2 top-1/2 max-h-[min(680px,calc(100vh-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-lt border border-lt-border data-[state=open]:animate-lt-dialog-in data-[state=closed]:animate-lt-dialog-out\",\n start:\n \"inset-y-0 start-0 border-e border-lt-border data-[state=open]:animate-lt-sheet-in-start data-[state=closed]:animate-lt-sheet-out-start\",\n end: \"inset-y-0 end-0 border-s border-lt-border data-[state=open]:animate-lt-sheet-in-end data-[state=closed]:animate-lt-sheet-out-end\",\n },\n width: {\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n xl: \"max-w-xl\",\n \"2xl\": \"max-w-2xl\",\n \"3xl\": \"max-w-3xl\",\n },\n },\n defaultVariants: { placement: \"center\", width: \"lg\" },\n },\n);\n\nfunction Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n className={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n data-slot=\"dialog-title\"\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n className={cn(\"text-sm text-lt-muted-fg\", className)}\n data-slot=\"dialog-description\"\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n children,\n className,\n placement = \"center\",\n width = \"lg\",\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n placement?: DialogPlacement;\n width?: ModalWidth;\n}) {\n return (\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay\n className=\"fixed inset-0 z-lt-overlay bg-lt-overlay data-[state=open]:animate-lt-fade-in data-[state=closed]:animate-lt-fade-out\"\n data-slot=\"dialog-overlay\"\n />\n <DialogPrimitive.Content\n className={cn(dialogContentVariants({ placement, width }), className)}\n data-slot=\"dialog-content\"\n {...props}\n >\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n}\n\n/**\n * The shared dialog header: a title with an optional description and a ghost\n * close button. Pass `description` as `undefined` to suppress the description\n * and the matching `aria-describedby` wiring on the content.\n */\nfunction DialogHeader({\n closeLabel,\n description,\n title,\n}: {\n closeLabel?: string;\n description?: React.ReactNode;\n title: React.ReactNode;\n}) {\n return (\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"grid gap-2\">\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </div>\n <DialogClose asChild>\n <Button aria-label={closeLabel} data-test=\"dialog-close\" size=\"icon\" variant=\"ghost\">\n <Icon name=\"x\" aria-hidden=\"true\" className=\"size-lt-icon-md\" />\n </Button>\n </DialogClose>\n </div>\n );\n}\n\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle };\n"],"mappings":";;;;;;;;AAUA,IAAM,wBAAwB,IAC5B,qEACA;CACE,UAAU;EACR,WAAW;GACT,QACE;GACF,OACE;GACF,KAAK;EACP;EACA,OAAO;GACL,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,OAAO;GACP,OAAO;EACT;CACF;CACA,iBAAiB;EAAE,WAAW;EAAU,OAAO;CAAK;AACtD,CACF;AAEA,SAAS,OAAO,OAA0D;CACxE,OAAO,oBAAC,gBAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAEA,SAAS,YAAY,OAA2D;CAC9E,OAAO,oBAAC,gBAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAAC,gBAAgB,OAAjB;EACE,WAAW,GAAG,qDAAqD,SAAS;EAC5E,aAAU;EACV,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAAC,gBAAgB,aAAjB;EACE,WAAW,GAAG,4BAA4B,SAAS;EACnD,aAAU;EACV,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EACrB,UACA,WACA,YAAY,UACZ,QAAQ,MACR,GAAG,SAIF;CACD,OACE,qBAAC,gBAAgB,QAAjB,EAAA,UAAA,CACE,oBAAC,gBAAgB,SAAjB;EACE,WAAU;EACV,aAAU;CACX,CAAA,GACD,oBAAC,gBAAgB,SAAjB;EACE,WAAW,GAAG,sBAAsB;GAAE;GAAW;EAAM,CAAC,GAAG,SAAS;EACpE,aAAU;EACV,GAAI;EAEH;CACsB,CAAA,CACH,EAAA,CAAA;AAE5B;;;;;;AAOA,SAAS,aAAa,EACpB,YACA,aACA,SAKC;CACD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,aAAD,EAAA,UAAc,MAAmB,CAAA,GAChC,cAAc,oBAAC,mBAAD,EAAA,UAAoB,YAA+B,CAAA,IAAI,IACnE;MACL,oBAAC,aAAD;GAAa,SAAA;aACX,oBAAC,QAAD;IAAQ,cAAY;IAAY,aAAU;IAAe,MAAK;IAAO,SAAQ;cAC3E,oBAAC,MAAD;KAAM,MAAK;KAAI,eAAY;KAAO,WAAU;IAAmB,CAAA;GACzD,CAAA;EACG,CAAA,CACV;;AAET"}
|
package/dist/ui/fragment.js
CHANGED
package/dist/ui/fragment.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.js","names":[],"sources":["../../resources/js/ui/fragment.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport { apiJson } from \"@lattice-php/lattice/core/api\";\nimport { Skeleton } from \"@lattice-php/lattice/ui/skeleton\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { RendererComponent
|
|
1
|
+
{"version":3,"file":"fragment.js","names":[],"sources":["../../resources/js/ui/fragment.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport { apiJson } from \"@lattice-php/lattice/core/api\";\nimport { Skeleton } from \"@lattice-php/lattice/ui/skeleton\";\nimport { Renderer } from \"@lattice-php/lattice/core/renderer\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport type { FragmentResponse } from \"@lattice-php/lattice/types/generated\";\nimport { toNodes } from \"@lattice-php/lattice/core/nodes\";\nimport { LATTICE_EVENT, type ReloadComponentEvent } from \"@lattice-php/lattice/core/event-names\";\n\nconst fragmentSizeHeights = {\n lg: 320,\n md: 64,\n sm: 40,\n xl: 384,\n xs: 32,\n \"2xl\": 448,\n \"3xl\": 512,\n \"4xl\": 576,\n} as const;\n\nconst FragmentComponent: RendererComponent<\"fragment\"> = ({ node }) => {\n const endpoint = node.props.endpoint ?? \"\";\n const isLazy = node.props.lazy === true;\n const componentRef = node.props.ref ?? \"\";\n const placeholderHeight = fragmentSizeHeights[node.props.size];\n const [components, setComponents] = useState(() => node.schema ?? []);\n const [hasLoaded, setHasLoaded] = useState(!isLazy);\n const [processing, setProcessing] = useState(isLazy && endpoint !== \"\");\n\n const load = useCallback(async (): Promise<void> => {\n if (!endpoint) {\n return;\n }\n\n setProcessing(true);\n\n try {\n const result = await apiJson<FragmentResponse>(endpoint, { ref: componentRef });\n\n setComponents(toNodes(result.schema));\n setHasLoaded(true);\n } finally {\n setProcessing(false);\n }\n }, [endpoint, componentRef]);\n\n useEffect(() => {\n if (!isLazy || hasLoaded) {\n return;\n }\n\n void load();\n }, [hasLoaded, isLazy, load]);\n\n useEffect(() => {\n function reload(event: Event): void {\n const detail = (event as ReloadComponentEvent).detail;\n\n if (detail?.component !== node.id) {\n return;\n }\n\n void load();\n }\n\n window.addEventListener(LATTICE_EVENT.reloadComponent, reload);\n\n return () => window.removeEventListener(LATTICE_EVENT.reloadComponent, reload);\n }, [load, node.id]);\n\n useEffect(() => {\n function reloadOnLocaleChange(): void {\n if (!hasLoaded) {\n return;\n }\n\n void load();\n }\n\n window.addEventListener(LATTICE_EVENT.localeChange, reloadOnLocaleChange);\n\n return () => window.removeEventListener(LATTICE_EVENT.localeChange, reloadOnLocaleChange);\n }, [hasLoaded, load]);\n\n return (\n <div\n data-lattice-fragment={node.id}\n style={processing && components.length === 0 ? { minHeight: placeholderHeight } : undefined}\n >\n {processing && components.length === 0 ? (\n <Skeleton className=\"w-full\" style={{ height: placeholderHeight }} />\n ) : (\n <Renderer nodes={components} />\n )}\n </div>\n );\n};\n\nexport default FragmentComponent;\n"],"mappings":";;;;;;;;AASA,IAAM,sBAAsB;CAC1B,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;AACT;AAEA,IAAM,qBAAoD,EAAE,WAAW;CACrE,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,SAAS,KAAK,MAAM,SAAS;CACnC,MAAM,eAAe,KAAK,MAAM,OAAO;CACvC,MAAM,oBAAoB,oBAAoB,KAAK,MAAM;CACzD,MAAM,CAAC,YAAY,iBAAiB,eAAe,KAAK,UAAU,CAAC,CAAC;CACpE,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC,MAAM;CAClD,MAAM,CAAC,YAAY,iBAAiB,SAAS,UAAU,aAAa,EAAE;CAEtE,MAAM,OAAO,YAAY,YAA2B;EAClD,IAAI,CAAC,UACH;EAGF,cAAc,IAAI;EAElB,IAAI;GAGF,cAAc,SAAQ,MAFD,QAA0B,UAAU,EAAE,KAAK,aAAa,CAAC,GAEjD,MAAM,CAAC;GACpC,aAAa,IAAI;EACnB,UAAU;GACR,cAAc,KAAK;EACrB;CACF,GAAG,CAAC,UAAU,YAAY,CAAC;CAE3B,gBAAgB;EACd,IAAI,CAAC,UAAU,WACb;EAGF,KAAU;CACZ,GAAG;EAAC;EAAW;EAAQ;CAAI,CAAC;CAE5B,gBAAgB;EACd,SAAS,OAAO,OAAoB;GAGlC,IAFgB,MAA+B,QAEnC,cAAc,KAAK,IAC7B;GAGF,KAAU;EACZ;EAEA,OAAO,iBAAiB,cAAc,iBAAiB,MAAM;EAE7D,aAAa,OAAO,oBAAoB,cAAc,iBAAiB,MAAM;CAC/E,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC;CAElB,gBAAgB;EACd,SAAS,uBAA6B;GACpC,IAAI,CAAC,WACH;GAGF,KAAU;EACZ;EAEA,OAAO,iBAAiB,cAAc,cAAc,oBAAoB;EAExE,aAAa,OAAO,oBAAoB,cAAc,cAAc,oBAAoB;CAC1F,GAAG,CAAC,WAAW,IAAI,CAAC;CAEpB,OACE,oBAAC,OAAD;EACE,yBAAuB,KAAK;EAC5B,OAAO,cAAc,WAAW,WAAW,IAAI,EAAE,WAAW,kBAAkB,IAAI,KAAA;YAEjF,cAAc,WAAW,WAAW,IACnC,oBAAC,UAAD;GAAU,WAAU;GAAS,OAAO,EAAE,QAAQ,kBAAkB;EAAI,CAAA,IAEpE,oBAAC,UAAD,EAAU,OAAO,WAAa,CAAA;CAE7B,CAAA;AAET"}
|