@lattice-php/lattice 0.3.0 → 0.5.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.js +3 -3
- package/dist/action/components/action-group.js +1 -1
- package/dist/action/components/action.js +10 -16
- package/dist/action/components/action.js.map +1 -1
- package/dist/action/run-action.d.ts +9 -0
- package/dist/action/run-action.js +22 -0
- package/dist/action/run-action.js.map +1 -0
- package/dist/chat/components/chat-box.js +31 -14
- package/dist/chat/components/chat-box.js.map +1 -1
- package/dist/chat/components/message.js +2 -2
- package/dist/chat/components/message.js.map +1 -1
- package/dist/chat/components/prompt-input.js +1 -1
- package/dist/chat/index.js +2 -0
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/transport.d.ts +2 -0
- package/dist/chat/transport.js +23 -3
- package/dist/chat/transport.js.map +1 -1
- package/dist/core/api.d.ts +14 -7
- package/dist/core/api.js +77 -1
- package/dist/core/api.js.map +1 -1
- package/dist/core/components/badge.js +4 -4
- package/dist/core/components/badge.js.map +1 -1
- package/dist/core/components/button.js +31 -19
- package/dist/core/components/button.js.map +1 -1
- package/dist/core/components/card.js +3 -2
- package/dist/core/components/card.js.map +1 -1
- package/dist/core/components/chart.js +3 -2
- package/dist/core/components/chart.js.map +1 -1
- package/dist/core/components/checkbox.js +1 -1
- package/dist/core/components/checkbox.js.map +1 -1
- package/dist/core/components/control.js +4 -4
- package/dist/core/components/control.js.map +1 -1
- package/dist/core/components/dialog.d.ts +1 -1
- package/dist/core/components/dialog.js +3 -2
- package/dist/core/components/dialog.js.map +1 -1
- package/dist/core/components/floating-panel.js +5 -4
- package/dist/core/components/floating-panel.js.map +1 -1
- package/dist/core/components/fragment.js +3 -6
- package/dist/core/components/fragment.js.map +1 -1
- package/dist/core/components/grid.js +2 -1
- package/dist/core/components/grid.js.map +1 -1
- package/dist/core/components/heading.js +1 -1
- package/dist/core/components/heading.js.map +1 -1
- package/dist/core/components/index.js +0 -2
- package/dist/core/components/index.js.map +1 -1
- package/dist/core/components/popover.d.ts +1 -1
- package/dist/core/components/popover.js +1 -1
- package/dist/core/components/popover.js.map +1 -1
- package/dist/core/components/section.js +7 -11
- package/dist/core/components/section.js.map +1 -1
- package/dist/core/components/segmented-pills.js +1 -1
- package/dist/core/components/segmented-pills.js.map +1 -1
- package/dist/core/components/stack.js +9 -2
- package/dist/core/components/stack.js.map +1 -1
- package/dist/core/components/tabs.js +2 -2
- package/dist/core/components/tabs.js.map +1 -1
- package/dist/core/nodes.d.ts +6 -0
- package/dist/core/nodes.js +13 -0
- package/dist/core/nodes.js.map +1 -0
- package/dist/core/renderer.js +1 -1
- package/dist/core/types.d.ts +3 -1
- package/dist/create-app.d.ts +21 -0
- package/dist/create-app.js +31 -0
- package/dist/create-app.js.map +1 -0
- package/dist/effects/registry.js +2 -1
- package/dist/effects/registry.js.map +1 -1
- package/dist/effects/use-effect-dispatcher.js +1 -1
- package/dist/effects/use-flash-effects.js +1 -1
- package/dist/events/event-names.d.ts +3 -2
- package/dist/events/event-names.js +3 -2
- package/dist/events/event-names.js.map +1 -1
- package/dist/form/components/base/affix-group.d.ts +17 -0
- package/dist/form/components/base/affix-group.js +49 -0
- package/dist/form/components/base/affix-group.js.map +1 -0
- package/dist/form/components/base/input-otp.d.ts +7 -0
- package/dist/form/components/base/input-otp.js +30 -0
- package/dist/form/components/base/input-otp.js.map +1 -0
- package/dist/form/components/base/label.js +1 -1
- package/dist/form/components/base/label.js.map +1 -1
- package/dist/form/components/base/submit-button.js +1 -1
- package/dist/form/components/base/submit-button.js.map +1 -1
- package/dist/form/components/base/textarea.js +1 -1
- package/dist/form/components/base/textarea.js.map +1 -1
- package/dist/form/components/conditions.js +1 -1
- package/dist/form/components/conditions.js.map +1 -1
- package/dist/form/components/fields/file-upload.js +35 -3
- package/dist/form/components/fields/file-upload.js.map +1 -1
- package/dist/form/components/fields/number-input.js +21 -15
- package/dist/form/components/fields/number-input.js.map +1 -1
- package/dist/form/components/fields/otp-input.d.ts +2 -0
- package/dist/form/components/fields/otp-input.js +25 -0
- package/dist/form/components/fields/otp-input.js.map +1 -0
- package/dist/form/components/fields/password-input.js +21 -15
- package/dist/form/components/fields/password-input.js.map +1 -1
- package/dist/form/components/fields/rich-editor.js +2 -2
- package/dist/form/components/fields/rich-editor.js.map +1 -1
- package/dist/form/components/fields/row-item.js +1 -1
- package/dist/form/components/fields/table-rows.js +1 -1
- package/dist/form/components/fields/text-input.js +19 -13
- package/dist/form/components/fields/text-input.js.map +1 -1
- package/dist/form/components/form.js +2 -2
- 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/components/prefill-targets.d.ts +0 -1
- package/dist/form/components/prefill-targets.js +1 -4
- package/dist/form/components/prefill-targets.js.map +1 -1
- package/dist/form/components/use-form-resolver.js +2 -2
- package/dist/form/components/use-form-resolver.js.map +1 -1
- package/dist/form/index.js +1 -0
- package/dist/form/index.js.map +1 -1
- package/dist/form/skeleton.js +1 -1
- package/dist/form/skeleton.js.map +1 -1
- package/dist/i18n/locale-reload.js +1 -1
- package/dist/i18n/translatable.d.ts +4 -0
- package/dist/i18n/translatable.js +24 -0
- package/dist/i18n/translatable.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +15 -13
- package/dist/lattice.css +99 -6
- package/dist/layout/breadcrumbs.js +3 -2
- package/dist/layout/breadcrumbs.js.map +1 -1
- package/dist/layout/callouts.js +2 -2
- package/dist/layout/callouts.js.map +1 -1
- package/dist/layout/components.js +4 -2
- package/dist/layout/components.js.map +1 -1
- package/dist/layout/dropdown.js +2 -1
- package/dist/layout/dropdown.js.map +1 -1
- package/dist/layout/menu-item.js +33 -12
- package/dist/layout/menu-item.js.map +1 -1
- package/dist/layout/menu.js +2 -1
- package/dist/layout/menu.js.map +1 -1
- package/dist/layout/popover.js +1 -1
- package/dist/layout/sidebar.js +69 -29
- package/dist/layout/sidebar.js.map +1 -1
- package/dist/layout/topbar.d.ts +3 -0
- package/dist/layout/topbar.js +16 -0
- package/dist/layout/topbar.js.map +1 -0
- package/dist/page.js +15 -10
- package/dist/page.js.map +1 -1
- package/dist/realtime/build-effects.d.ts +4 -0
- package/dist/realtime/build-effects.js +23 -0
- package/dist/realtime/build-effects.js.map +1 -0
- package/dist/realtime/listeners.d.ts +8 -0
- package/dist/realtime/listeners.js +31 -0
- package/dist/realtime/listeners.js.map +1 -0
- package/dist/realtime/subscriptions.d.ts +4 -0
- package/dist/realtime/subscriptions.js +45 -0
- package/dist/realtime/subscriptions.js.map +1 -0
- package/dist/registry.js +3 -2
- package/dist/registry.js.map +1 -1
- package/dist/remote/components/data-list.d.ts +10 -0
- package/dist/remote/components/data-list.js +106 -0
- package/dist/remote/components/data-list.js.map +1 -0
- package/dist/remote/index.d.ts +1 -0
- package/dist/remote/index.js +11 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/table/components/bulk-bar.js +10 -15
- package/dist/table/components/bulk-bar.js.map +1 -1
- package/dist/table/components/cells/text-cell.js +38 -3
- package/dist/table/components/cells/text-cell.js.map +1 -1
- package/dist/table/components/column-filter-control.d.ts +2 -1
- package/dist/table/components/column-filter-control.js +28 -19
- package/dist/table/components/column-filter-control.js.map +1 -1
- package/dist/table/components/column-header.js +2 -2
- package/dist/table/components/column-header.js.map +1 -1
- package/dist/table/components/filter-bar.d.ts +7 -6
- package/dist/table/components/filter-bar.js +51 -28
- package/dist/table/components/filter-bar.js.map +1 -1
- package/dist/table/components/filter-controls.js +2 -2
- package/dist/table/components/filter-controls.js.map +1 -1
- package/dist/table/components/filter-stack-bar.js +4 -3
- package/dist/table/components/filter-stack-bar.js.map +1 -1
- package/dist/table/components/filter-value-input.js +1 -1
- package/dist/table/components/filter-value-input.js.map +1 -1
- package/dist/table/components/sort-bar.js +1 -1
- package/dist/table/components/sort-bar.js.map +1 -1
- package/dist/table/components/table.js +26 -17
- package/dist/table/components/table.js.map +1 -1
- package/dist/table/filter-values.d.ts +5 -0
- package/dist/table/filter-values.js +10 -3
- package/dist/table/filter-values.js.map +1 -1
- package/dist/table/query.js +5 -4
- package/dist/table/query.js.map +1 -1
- package/dist/table/use-table.d.ts +1 -0
- package/dist/table/use-table.js +4 -0
- package/dist/table/use-table.js.map +1 -1
- package/dist/toast/toast.js +5 -2
- package/dist/toast/toast.js.map +1 -1
- package/dist/toast/toaster.js +6 -5
- package/dist/toast/toaster.js.map +1 -1
- package/dist/types/generated.d.ts +122 -14
- package/dist/vite.js +32 -1
- package/dist/vite.js.map +1 -1
- package/package.json +33 -3
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { Renderer } from "../../core/renderer.js";
|
|
2
|
+
import { useT } from "../../i18n/instance.js";
|
|
3
|
+
import { dispatchActionError } from "../../effects/dispatch.js";
|
|
1
4
|
import { Button } from "../../core/components/button.js";
|
|
2
5
|
import { Dialog, DialogContent, DialogHeader } from "../../core/components/dialog.js";
|
|
3
|
-
import { useT } from "../../i18n/instance.js";
|
|
4
6
|
import { Spinner } from "../../core/components/spinner.js";
|
|
5
|
-
import { dispatchActionError } from "../../effects/dispatch.js";
|
|
6
7
|
import { apiFetch } from "../../core/api.js";
|
|
7
8
|
import { Skeleton } from "../../core/components/skeleton.js";
|
|
8
|
-
import { Renderer } from "../../core/renderer.js";
|
|
9
9
|
import { FormProvider } from "../../form/components/context.js";
|
|
10
10
|
import { walkFields } from "../../form/components/field-props.js";
|
|
11
11
|
import "../../form/components/form-transport.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { Icon } from "../../icons/sprite.js";
|
|
2
3
|
import { nodeIdentity } from "../../core/test-id.js";
|
|
3
4
|
import { Button } from "../../core/components/button.js";
|
|
4
|
-
import { Icon } from "../../icons/sprite.js";
|
|
5
5
|
import { ActionMenuProvider } from "./action-menu-context.js";
|
|
6
6
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../../core/components/dropdown-menu.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { withHeaders } from "../../core/headers.js";
|
|
2
|
+
import { IconRenderer } from "../../icons/icon-renderer.js";
|
|
2
3
|
import { prefixedTestId } from "../../core/test-id.js";
|
|
4
|
+
import { getActionEffects } from "../../effects/dispatch.js";
|
|
5
|
+
import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
|
|
3
6
|
import { Button } from "../../core/components/button.js";
|
|
4
|
-
import { IconRenderer } from "../../icons/icon-renderer.js";
|
|
5
7
|
import { Spinner } from "../../core/components/spinner.js";
|
|
6
8
|
import { ConfirmDialog } from "../../core/components/confirm-dialog.js";
|
|
7
|
-
import {
|
|
8
|
-
import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
|
|
9
|
+
import { runAction } from "../run-action.js";
|
|
9
10
|
import { ActionForm, useLazyActionForm } from "./action-form.js";
|
|
10
11
|
import { actionMenuItemClassName, useActionMenu } from "./action-menu-context.js";
|
|
11
|
-
import { useState } from "react";
|
|
12
12
|
import { router, useHttp } from "@inertiajs/react";
|
|
13
|
+
import { useState } from "react";
|
|
13
14
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
15
|
//#region resources/js/action/components/action.tsx
|
|
15
16
|
var ActionComponent = ({ node }) => {
|
|
@@ -32,18 +33,12 @@ var ActionComponent = ({ node }) => {
|
|
|
32
33
|
const formNode = lazyForm ? lazyNode : inlineForm;
|
|
33
34
|
const submit = async () => {
|
|
34
35
|
if (!endpoint) return;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
router.visit(endpoint, { headers: withHeaders(componentRef) });
|
|
38
|
-
setIsConfirming(false);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const responseEffects = getActionEffects((await http[method](endpoint, { headers: withHeaders(componentRef) })).effects);
|
|
42
|
-
dispatch(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
|
|
36
|
+
if (method === "get") {
|
|
37
|
+
router.visit(endpoint, { headers: withHeaders(componentRef) });
|
|
43
38
|
setIsConfirming(false);
|
|
44
|
-
|
|
45
|
-
dispatchActionError(error);
|
|
39
|
+
return;
|
|
46
40
|
}
|
|
41
|
+
if (await runAction(() => http[method](endpoint, { headers: withHeaders(componentRef) }), dispatch)) setIsConfirming(false);
|
|
47
42
|
};
|
|
48
43
|
const requestSubmit = () => {
|
|
49
44
|
if (hasForm) {
|
|
@@ -94,8 +89,7 @@ var ActionComponent = ({ node }) => {
|
|
|
94
89
|
method,
|
|
95
90
|
onClose: () => setIsFilling(false),
|
|
96
91
|
onSuccess: (response) => {
|
|
97
|
-
|
|
98
|
-
dispatch(responseEffects.length > 0 ? responseEffects : getActionEffects(node.props.effects));
|
|
92
|
+
dispatch(getActionEffects(response.effects));
|
|
99
93
|
setIsFilling(false);
|
|
100
94
|
},
|
|
101
95
|
submitLabel: confirmationConfirmLabel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.js","names":[],"sources":["../../../resources/js/action/components/action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/core/components/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/core/components/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport {
|
|
1
|
+
{"version":3,"file":"action.js","names":[],"sources":["../../../resources/js/action/components/action.tsx"],"sourcesContent":["import { router, useHttp } from \"@inertiajs/react\";\nimport type { Method } from \"@inertiajs/core\";\nimport { useState } from \"react\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/core/components/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/core/components/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/core/components/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\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 \"../run-action\";\nimport { ActionForm, useLazyActionForm } from \"./action-form\";\nimport { actionMenuItemClassName, useActionMenu } from \"./action-menu-context\";\n\nconst ActionComponent: RendererComponent<\"action\"> = ({ node }) => {\n const endpoint = node.props.endpoint ?? \"\";\n const icon = node.props.icon;\n const label = node.props.label ?? \"Run action\";\n const componentRef = node.props.ref ?? \"\";\n const method: Method = node.props.method ?? \"post\";\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 isMenuItem = useActionMenu();\n const confirmation = node.props.confirmation;\n const variant = node.props.variant ?? \"default\";\n const inlineForm = node.props.form;\n const lazyForm = node.props.lazyForm === true;\n const hasForm = Boolean(inlineForm) || lazyForm;\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 const testId = node.key ?? prefixedTestId(\"action\", node.id);\n\n return (\n <>\n <Button\n className={isMenuItem ? actionMenuItemClassName : undefined}\n data-lattice-component={node.id}\n data-test={testId}\n disabled={http.processing || !endpoint}\n onClick={requestSubmit}\n type=\"button\"\n variant={isMenuItem ? \"ghost\" : variant}\n >\n {http.processing ? (\n <Spinner className={isMenuItem ? \"size-lt-icon-sm\" : undefined} />\n ) : (\n icon && (\n <IconRenderer\n className={isMenuItem ? \"size-lt-icon-sm\" : \"size-lt-icon-md\"}\n icon={icon}\n />\n )\n )}\n {label}\n </Button>\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\nexport default ActionComponent;\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,WAAW,KAAK,MAAM,YAAY;CACxC,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,eAAe,KAAK,MAAM,OAAO;CACvC,MAAM,SAAiB,KAAK,MAAM,UAAU;CAC5C,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,aAAa,cAAc;CACjC,MAAM,eAAe,KAAK,MAAM;CAChC,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,WAAW,KAAK,MAAM,aAAa;CACzC,MAAM,UAAU,QAAQ,UAAU,KAAK;CACvC,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;CAC7D,MAAM,SAAS,KAAK,OAAO,eAAe,UAAU,KAAK,EAAE;CAE3D,OACE,qBAAA,YAAA,EAAA,UAAA;EACE,qBAAC,QAAD;GACE,WAAW,aAAa,0BAA0B,KAAA;GAClD,0BAAwB,KAAK;GAC7B,aAAW;GACX,UAAU,KAAK,cAAc,CAAC;GAC9B,SAAS;GACT,MAAK;GACL,SAAS,aAAa,UAAU;aAPlC,CASG,KAAK,aACJ,oBAAC,SAAD,EAAS,WAAW,aAAa,oBAAoB,KAAA,EAAY,CAAA,IAEjE,QACE,oBAAC,cAAD;IACE,WAAW,aAAa,oBAAoB;IACtC;GACP,CAAA,GAGJ,KACK;;EAEP,gBAAgB,gBACf,oBAAC,eAAD;GACE,OAAO;GACP,aAAa,aAAa,eAAe,KAAA;GACzC,cAAc;GACd,aAAa;GACb,gBAAgB;GAChB,YAAY,KAAK;GACjB,iBAAiB,CAAC;GAClB,iBAAiB,KAAK,OAAO;GAC7B,gBAAgB,gBAAgB,KAAK;EACtC,CAAA;EAGF,aAAa,WACZ,oBAAC,YAAD;GACE,aAAa;GACC;GACd,aAAa,cAAc,eAAe,KAAA;GAChC;GACA;GACF;GACR,eAAe,aAAa,KAAK;GACjC,YAAY,aAAa;IACvB,SAAS,iBAAiB,SAAS,OAAO,CAAC;IAC3C,aAAa,KAAK;GACpB;GACA,aAAa;GACb,OAAO;EACR,CAAA;CAEH,EAAA,CAAA;AAEN"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ActionEffect, ActionResponse } from '../effects/dispatch';
|
|
2
|
+
/**
|
|
3
|
+
* Runs an action request and dispatches the effects from its response, routing
|
|
4
|
+
* any failure through dispatchActionError. Returns whether the request
|
|
5
|
+
* succeeded so callers run their own post-success cleanup (closing a dialog,
|
|
6
|
+
* reloading a table). Shared by the single action button and the bulk bar so
|
|
7
|
+
* the invocation contract stays in one place.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runAction(request: () => Promise<ActionResponse>, dispatch: (effects: ActionEffect[]) => void): Promise<boolean>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { dispatchActionError, getActionEffects } from "../effects/dispatch.js";
|
|
2
|
+
//#region resources/js/action/run-action.ts
|
|
3
|
+
/**
|
|
4
|
+
* Runs an action request and dispatches the effects from its response, routing
|
|
5
|
+
* any failure through dispatchActionError. Returns whether the request
|
|
6
|
+
* succeeded so callers run their own post-success cleanup (closing a dialog,
|
|
7
|
+
* reloading a table). Shared by the single action button and the bulk bar so
|
|
8
|
+
* the invocation contract stays in one place.
|
|
9
|
+
*/
|
|
10
|
+
async function runAction(request, dispatch) {
|
|
11
|
+
try {
|
|
12
|
+
dispatch(getActionEffects((await request()).effects));
|
|
13
|
+
return true;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
dispatchActionError(error);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { runAction };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=run-action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-action.js","names":[],"sources":["../../resources/js/action/run-action.ts"],"sourcesContent":["import {\n type ActionEffect,\n type ActionResponse,\n dispatchActionError,\n getActionEffects,\n} from \"@lattice-php/lattice/effects/dispatch\";\n\n/**\n * Runs an action request and dispatches the effects from its response, routing\n * any failure through dispatchActionError. Returns whether the request\n * succeeded so callers run their own post-success cleanup (closing a dialog,\n * reloading a table). Shared by the single action button and the bulk bar so\n * the invocation contract stays in one place.\n */\nexport async function runAction(\n request: () => Promise<ActionResponse>,\n dispatch: (effects: ActionEffect[]) => void,\n): Promise<boolean> {\n try {\n const response = await request();\n dispatch(getActionEffects(response.effects));\n\n return true;\n } catch (error) {\n dispatchActionError(error);\n\n return false;\n }\n}\n"],"mappings":";;;;;;;;;AAcA,eAAsB,UACpB,SACA,UACkB;CAClB,IAAI;EAEF,SAAS,kBAAiB,MADH,QAAQ,GACI,OAAO,CAAC;EAE3C,OAAO;CACT,SAAS,OAAO;EACd,oBAAoB,KAAK;EAEzB,OAAO;CACT;AACF"}
|
|
@@ -1,48 +1,65 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
-
import { testIdentity } from "../../core/test-id.js";
|
|
3
2
|
import { useT } from "../../i18n/instance.js";
|
|
4
|
-
import {
|
|
3
|
+
import { testIdentity } from "../../core/test-id.js";
|
|
4
|
+
import { apiFetch, remoteJson } from "../../core/api.js";
|
|
5
|
+
import { createRemoteNdjsonChatTransport, ndjsonChatTransport } from "../transport.js";
|
|
5
6
|
import { useChat } from "../use-chat.js";
|
|
6
7
|
import { MessageList } from "./message-list.js";
|
|
7
8
|
import { PromptInput } from "./prompt-input.js";
|
|
8
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
9
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
//#region resources/js/chat/components/chat-box.tsx
|
|
11
12
|
var ChatBox = ({ node }) => {
|
|
12
|
-
const
|
|
13
|
+
const props = node.props;
|
|
13
14
|
const { t } = useT("lattice");
|
|
14
|
-
const
|
|
15
|
+
const transport = useMemo(() => props.remote ? createRemoteNdjsonChatTransport(props.remote) : ndjsonChatTransport, [props.remote]);
|
|
16
|
+
const { messages, status, error, sendMessage, setMessages } = useChat({
|
|
17
|
+
endpoint: props.streamEndpoint ?? "",
|
|
18
|
+
transport
|
|
19
|
+
});
|
|
15
20
|
const seededRef = useRef(false);
|
|
16
21
|
const seedHistory = useCallback(async () => {
|
|
17
|
-
if (seededRef.current || !historyEndpoint) return;
|
|
22
|
+
if (seededRef.current || !props.historyEndpoint) return;
|
|
18
23
|
seededRef.current = true;
|
|
19
|
-
|
|
24
|
+
if (props.remote) {
|
|
25
|
+
setMessages((await remoteJson(props.historyEndpoint, { remote: props.remote })).messages);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const response = await apiFetch(props.historyEndpoint, { throwOnError: false });
|
|
20
29
|
if (!response.ok) return;
|
|
21
30
|
setMessages((await response.json()).messages);
|
|
22
|
-
}, [
|
|
31
|
+
}, [
|
|
32
|
+
props.historyEndpoint,
|
|
33
|
+
props.remote,
|
|
34
|
+
setMessages
|
|
35
|
+
]);
|
|
23
36
|
useEffect(() => {
|
|
24
|
-
seedHistory();
|
|
37
|
+
seedHistory().catch(() => {});
|
|
25
38
|
}, [seedHistory]);
|
|
26
|
-
const
|
|
39
|
+
const disabled = status === "submitted" || status === "streaming" || !props.streamEndpoint;
|
|
27
40
|
return /* @__PURE__ */ jsxs("div", {
|
|
28
|
-
className: cn("flex flex-col overflow-hidden border border-lt-border bg-lt-bg", fill ? "sticky top-0 h-
|
|
41
|
+
className: cn("flex flex-col overflow-hidden border border-lt-border bg-lt-bg", props.fill ? "sticky top-0 h-full min-h-[28rem] w-full" : "h-[28rem] w-80 rounded-lt shadow-lt-lg"),
|
|
29
42
|
"data-test": testIdentity("chat-box"),
|
|
30
43
|
children: [
|
|
31
44
|
/* @__PURE__ */ jsx("div", {
|
|
32
45
|
className: "flex items-center border-b border-lt-border px-3 py-2",
|
|
33
46
|
children: /* @__PURE__ */ jsx("span", {
|
|
34
47
|
className: "text-sm font-medium text-lt-fg",
|
|
35
|
-
children: title ?? t("chat.title", "Chat")
|
|
48
|
+
children: props.title ?? t("chat.title", "Chat")
|
|
36
49
|
})
|
|
37
50
|
}),
|
|
38
51
|
/* @__PURE__ */ jsx("div", {
|
|
39
52
|
className: "flex-1 overflow-y-auto",
|
|
40
53
|
children: /* @__PURE__ */ jsx(MessageList, { messages })
|
|
41
54
|
}),
|
|
55
|
+
error ? /* @__PURE__ */ jsx("div", {
|
|
56
|
+
className: "border-t border-lt-danger/40 px-3 py-2 text-xs text-lt-danger",
|
|
57
|
+
children: error
|
|
58
|
+
}) : null,
|
|
42
59
|
/* @__PURE__ */ jsx(PromptInput, {
|
|
43
|
-
disabled
|
|
60
|
+
disabled,
|
|
44
61
|
onSubmit: sendMessage,
|
|
45
|
-
placeholder: placeholder ?? void 0
|
|
62
|
+
placeholder: props.placeholder ?? void 0
|
|
46
63
|
})
|
|
47
64
|
]
|
|
48
65
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-box.js","names":[],"sources":["../../../resources/js/chat/components/chat-box.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport {
|
|
1
|
+
{"version":3,"file":"chat-box.js","names":[],"sources":["../../../resources/js/chat/components/chat-box.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { apiFetch, remoteJson } from \"@lattice-php/lattice/core/api\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport type { ChatBox as ChatBoxProps } from \"@lattice-php/lattice/types/generated\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { createRemoteNdjsonChatTransport, ndjsonChatTransport } from \"../transport\";\nimport { useChat } from \"../use-chat\";\nimport type { ChatMessage } from \"../types\";\nimport { MessageList } from \"./message-list\";\nimport { PromptInput } from \"./prompt-input\";\n\ntype ChatHistoryResponse = { messages: ChatMessage[] };\n\nexport const ChatBox: RendererComponent<\"chat.box\"> = ({ node }) => {\n const props: ChatBoxProps = node.props;\n const { t } = useT(\"lattice\");\n const transport = useMemo(\n () => (props.remote ? createRemoteNdjsonChatTransport(props.remote) : ndjsonChatTransport),\n [props.remote],\n );\n const { messages, status, error, sendMessage, setMessages } = useChat({\n endpoint: props.streamEndpoint ?? \"\",\n transport,\n });\n\n const seededRef = useRef(false);\n\n const seedHistory = useCallback(async (): Promise<void> => {\n if (seededRef.current || !props.historyEndpoint) {\n return;\n }\n\n seededRef.current = true;\n\n if (props.remote) {\n const payload = await remoteJson<ChatHistoryResponse>(props.historyEndpoint, {\n remote: props.remote,\n });\n setMessages(payload.messages);\n\n return;\n }\n\n const response = await apiFetch(props.historyEndpoint, { throwOnError: false });\n\n if (!response.ok) {\n return;\n }\n\n const payload = (await response.json()) as ChatHistoryResponse;\n setMessages(payload.messages);\n }, [props.historyEndpoint, props.remote, setMessages]);\n\n useEffect(() => {\n void seedHistory().catch(() => {});\n }, [seedHistory]);\n\n const busy = status === \"submitted\" || status === \"streaming\";\n const disabled = busy || !props.streamEndpoint;\n\n return (\n <div\n className={cn(\n \"flex flex-col overflow-hidden border border-lt-border bg-lt-bg\",\n props.fill\n ? \"sticky top-0 h-full min-h-[28rem] w-full\"\n : \"h-[28rem] w-80 rounded-lt shadow-lt-lg\",\n )}\n data-test={testIdentity(\"chat-box\")}\n >\n <div className=\"flex items-center border-b border-lt-border px-3 py-2\">\n <span className=\"text-sm font-medium text-lt-fg\">\n {props.title ?? t(\"chat.title\", \"Chat\")}\n </span>\n </div>\n <div className=\"flex-1 overflow-y-auto\">\n <MessageList messages={messages} />\n </div>\n {error ? (\n <div className=\"border-t border-lt-danger/40 px-3 py-2 text-xs text-lt-danger\">{error}</div>\n ) : null}\n <PromptInput\n disabled={disabled}\n onSubmit={sendMessage}\n placeholder={props.placeholder ?? undefined}\n />\n </div>\n );\n};\n\nexport default ChatBox;\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,WAA0C,EAAE,WAAW;CAClE,MAAM,QAAsB,KAAK;CACjC,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,YAAY,cACT,MAAM,SAAS,gCAAgC,MAAM,MAAM,IAAI,qBACtE,CAAC,MAAM,MAAM,CACf;CACA,MAAM,EAAE,UAAU,QAAQ,OAAO,aAAa,gBAAgB,QAAQ;EACpE,UAAU,MAAM,kBAAkB;EAClC;CACF,CAAC;CAED,MAAM,YAAY,OAAO,KAAK;CAE9B,MAAM,cAAc,YAAY,YAA2B;EACzD,IAAI,UAAU,WAAW,CAAC,MAAM,iBAC9B;EAGF,UAAU,UAAU;EAEpB,IAAI,MAAM,QAAQ;GAIhB,aAAY,MAHU,WAAgC,MAAM,iBAAiB,EAC3E,QAAQ,MAAM,OAChB,CAAC,GACmB,QAAQ;GAE5B;EACF;EAEA,MAAM,WAAW,MAAM,SAAS,MAAM,iBAAiB,EAAE,cAAc,MAAM,CAAC;EAE9E,IAAI,CAAC,SAAS,IACZ;EAIF,aAAY,MADW,SAAS,KAAK,GACjB,QAAQ;CAC9B,GAAG;EAAC,MAAM;EAAiB,MAAM;EAAQ;CAAW,CAAC;CAErD,gBAAgB;EACd,YAAiB,EAAE,YAAY,CAAC,CAAC;CACnC,GAAG,CAAC,WAAW,CAAC;CAGhB,MAAM,WADO,WAAW,eAAe,WAAW,eACzB,CAAC,MAAM;CAEhC,OACE,qBAAC,OAAD;EACE,WAAW,GACT,kEACA,MAAM,OACF,6CACA,wCACN;EACA,aAAW,aAAa,UAAU;YAPpC;GASE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KAAM,WAAU;eACb,MAAM,SAAS,EAAE,cAAc,MAAM;IAClC,CAAA;GACH,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,aAAD,EAAuB,SAAW,CAAA;GAC/B,CAAA;GACJ,QACC,oBAAC,OAAD;IAAK,WAAU;cAAiE;GAAW,CAAA,IACzF;GACJ,oBAAC,aAAD;IACY;IACV,UAAU;IACV,aAAa,MAAM,eAAe,KAAA;GACnC,CAAA;EACE;;AAET"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
-
import { testIdentity } from "../../core/test-id.js";
|
|
3
2
|
import { RenderNode } from "../../core/renderer.js";
|
|
3
|
+
import { testIdentity } from "../../core/test-id.js";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region resources/js/chat/components/message.tsx
|
|
6
6
|
function Message({ message }) {
|
|
@@ -9,7 +9,7 @@ function Message({ message }) {
|
|
|
9
9
|
className: cn("flex flex-col gap-1", isUser ? "items-end" : "items-start"),
|
|
10
10
|
"data-test": testIdentity(`chat-message-${message.role}`),
|
|
11
11
|
children: /* @__PURE__ */ jsx("div", {
|
|
12
|
-
className: cn("max-w-[80%] rounded-lt
|
|
12
|
+
className: cn("max-w-[80%] rounded-lt px-3 py-2 text-sm", isUser ? "bg-lt-primary text-lt-primary-fg" : "bg-lt-muted text-lt-fg"),
|
|
13
13
|
children: message.parts.map((part, index) => /* @__PURE__ */ jsx(RenderNode, { node: part }, part.key ?? index))
|
|
14
14
|
})
|
|
15
15
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","names":[],"sources":["../../../resources/js/chat/components/message.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { ChatMessage } from \"../types\";\n\nexport function Message({ message }: { message: ChatMessage }): ReactNode {\n const isUser = message.role === \"user\";\n\n return (\n <div\n className={cn(\"flex flex-col gap-1\", isUser ? \"items-end\" : \"items-start\")}\n data-test={testIdentity(`chat-message-${message.role}`)}\n >\n <div\n className={cn(\n \"max-w-[80%] rounded-lt
|
|
1
|
+
{"version":3,"file":"message.js","names":[],"sources":["../../../resources/js/chat/components/message.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { testIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport { RenderNode } from \"@lattice-php/lattice/core/renderer\";\nimport type { ChatMessage } from \"../types\";\n\nexport function Message({ message }: { message: ChatMessage }): ReactNode {\n const isUser = message.role === \"user\";\n\n return (\n <div\n className={cn(\"flex flex-col gap-1\", isUser ? \"items-end\" : \"items-start\")}\n data-test={testIdentity(`chat-message-${message.role}`)}\n >\n <div\n className={cn(\n \"max-w-[80%] rounded-lt px-3 py-2 text-sm\",\n isUser ? \"bg-lt-primary text-lt-primary-fg\" : \"bg-lt-muted text-lt-fg\",\n )}\n >\n {message.parts.map((part, index) => (\n <RenderNode key={part.key ?? index} node={part} />\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,QAAQ,EAAE,WAAgD;CACxE,MAAM,SAAS,QAAQ,SAAS;CAEhC,OACE,oBAAC,OAAD;EACE,WAAW,GAAG,uBAAuB,SAAS,cAAc,aAAa;EACzE,aAAW,aAAa,gBAAgB,QAAQ,MAAM;YAEtD,oBAAC,OAAD;GACE,WAAW,GACT,4CACA,SAAS,qCAAqC,wBAChD;aAEC,QAAQ,MAAM,KAAK,MAAM,UACxB,oBAAC,YAAD,EAAoC,MAAM,KAAO,GAAhC,KAAK,OAAO,KAAoB,CAClD;EACE,CAAA;CACF,CAAA;AAET"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import { useT } from "../../i18n/instance.js";
|
|
2
3
|
import { testIdentity } from "../../core/test-id.js";
|
|
3
4
|
import { Button } from "../../core/components/button.js";
|
|
4
|
-
import { useT } from "../../i18n/instance.js";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region resources/js/chat/components/prompt-input.tsx
|
package/dist/chat/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createPlugin, eagerComponent } from "../core/registry.js";
|
|
2
|
+
import { ChatBox } from "./components/chat-box.js";
|
|
2
3
|
import { TextPart } from "./parts/text.js";
|
|
3
4
|
import { ToolCallPart } from "./parts/tool-call.js";
|
|
4
5
|
//#region resources/js/chat/index.ts
|
|
5
6
|
var chatPlugin = createPlugin({
|
|
6
7
|
name: "chat",
|
|
7
8
|
components: {
|
|
9
|
+
"chat.box": eagerComponent(ChatBox),
|
|
8
10
|
"chat.part.text": eagerComponent(TextPart),
|
|
9
11
|
"chat.part.tool-call": eagerComponent(ToolCallPart)
|
|
10
12
|
}
|
package/dist/chat/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/chat/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport { TextPart } from \"./parts/text\";\nimport { ToolCallPart } from \"./parts/tool-call\";\n\nexport const chatPlugin = createPlugin({\n name: \"chat\",\n components: {\n \"chat.part.text\": eagerComponent(TextPart),\n \"chat.part.tool-call\": eagerComponent(ToolCallPart),\n },\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../resources/js/chat/index.ts"],"sourcesContent":["import { createPlugin, eagerComponent } from \"@lattice-php/lattice/core/registry\";\nimport ChatBoxComponent from \"./components/chat-box\";\nimport { TextPart } from \"./parts/text\";\nimport { ToolCallPart } from \"./parts/tool-call\";\n\nexport const chatPlugin = createPlugin({\n name: \"chat\",\n components: {\n \"chat.box\": eagerComponent(ChatBoxComponent),\n \"chat.part.text\": eagerComponent(TextPart),\n \"chat.part.tool-call\": eagerComponent(ToolCallPart),\n },\n});\n"],"mappings":";;;;;AAKA,IAAa,aAAa,aAAa;CACrC,MAAM;CACN,YAAY;EACV,YAAY,eAAe,OAAgB;EAC3C,kBAAkB,eAAe,QAAQ;EACzC,uBAAuB,eAAe,YAAY;CACpD;AACF,CAAC"}
|
package/dist/chat/transport.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import { RemoteAccess } from '../core/api';
|
|
1
2
|
import { ChatFrame, ChatTransportRequest } from './types';
|
|
2
3
|
export declare function ndjsonChatTransport({ url, body, signal, }: ChatTransportRequest): AsyncGenerator<ChatFrame>;
|
|
4
|
+
export declare function createRemoteNdjsonChatTransport(remote: RemoteAccess): ({ url, body, signal, }: ChatTransportRequest) => AsyncGenerator<ChatFrame>;
|
package/dist/chat/transport.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { apiFetch } from "../core/api.js";
|
|
1
|
+
import { apiFetch, remoteFetch } from "../core/api.js";
|
|
2
2
|
//#region resources/js/chat/transport.ts
|
|
3
3
|
function parseFrame(line) {
|
|
4
4
|
try {
|
|
@@ -16,7 +16,27 @@ async function* ndjsonChatTransport({ url, body, signal }) {
|
|
|
16
16
|
throwOnError: false
|
|
17
17
|
});
|
|
18
18
|
if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
|
|
19
|
-
|
|
19
|
+
yield* readNdjsonFrames(res.body);
|
|
20
|
+
}
|
|
21
|
+
function createRemoteNdjsonChatTransport(remote) {
|
|
22
|
+
return async function* remoteNdjsonChatTransport({ url, body, signal }) {
|
|
23
|
+
const res = await remoteFetch(url, {
|
|
24
|
+
remote,
|
|
25
|
+
method: "POST",
|
|
26
|
+
signal,
|
|
27
|
+
headers: {
|
|
28
|
+
Accept: "application/x-ndjson",
|
|
29
|
+
"Content-Type": "application/json"
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
throwOnError: false
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok || !res.body) throw new Error(`Chat stream failed (${res.status})`);
|
|
35
|
+
yield* readNdjsonFrames(res.body);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function* readNdjsonFrames(body) {
|
|
39
|
+
const reader = body.getReader();
|
|
20
40
|
const decoder = new TextDecoder();
|
|
21
41
|
let buffer = "";
|
|
22
42
|
try {
|
|
@@ -42,6 +62,6 @@ async function* ndjsonChatTransport({ url, body, signal }) {
|
|
|
42
62
|
}
|
|
43
63
|
}
|
|
44
64
|
//#endregion
|
|
45
|
-
export { ndjsonChatTransport };
|
|
65
|
+
export { createRemoteNdjsonChatTransport, ndjsonChatTransport };
|
|
46
66
|
|
|
47
67
|
//# sourceMappingURL=transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","names":[],"sources":["../../resources/js/chat/transport.ts"],"sourcesContent":["import { apiFetch } from \"../core/api\";\nimport type { ChatFrame, ChatTransportRequest } from \"./types\";\n\nfunction parseFrame(line: string): ChatFrame | null {\n try {\n return JSON.parse(line) as ChatFrame;\n } catch {\n return null;\n }\n}\n\nexport async function* ndjsonChatTransport({\n url,\n body,\n signal,\n}: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await apiFetch(url, {\n method: \"POST\",\n signal,\n headers: { Accept: \"application/x-ndjson\" },\n body: JSON.stringify(body),\n throwOnError: false,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n const
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../../resources/js/chat/transport.ts"],"sourcesContent":["import { apiFetch, remoteFetch, type RemoteAccess } from \"../core/api\";\nimport type { ChatFrame, ChatTransportRequest } from \"./types\";\n\nfunction parseFrame(line: string): ChatFrame | null {\n try {\n return JSON.parse(line) as ChatFrame;\n } catch {\n return null;\n }\n}\n\nexport async function* ndjsonChatTransport({\n url,\n body,\n signal,\n}: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await apiFetch(url, {\n method: \"POST\",\n signal,\n headers: { Accept: \"application/x-ndjson\" },\n body: JSON.stringify(body),\n throwOnError: false,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n yield* readNdjsonFrames(res.body);\n}\n\nexport function createRemoteNdjsonChatTransport(remote: RemoteAccess) {\n return async function* remoteNdjsonChatTransport({\n url,\n body,\n signal,\n }: ChatTransportRequest): AsyncGenerator<ChatFrame> {\n const res = await remoteFetch(url, {\n remote,\n method: \"POST\",\n signal,\n headers: {\n Accept: \"application/x-ndjson\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n throwOnError: false,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`Chat stream failed (${res.status})`);\n }\n\n yield* readNdjsonFrames(res.body);\n };\n}\n\nasync function* readNdjsonFrames(body: ReadableStream<Uint8Array>): AsyncGenerator<ChatFrame> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.trim() === \"\") {\n continue;\n }\n\n const frame = parseFrame(line);\n if (frame) {\n yield frame;\n }\n }\n }\n\n buffer += decoder.decode();\n if (buffer.trim() !== \"\") {\n const frame = parseFrame(buffer);\n if (frame) {\n yield frame;\n }\n }\n } finally {\n await reader.cancel().catch(() => {});\n }\n}\n"],"mappings":";;AAGA,SAAS,WAAW,MAAgC;CAClD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,gBAAuB,oBAAoB,EACzC,KACA,MACA,UACkD;CAClD,MAAM,MAAM,MAAM,SAAS,KAAK;EAC9B,QAAQ;EACR;EACA,SAAS,EAAE,QAAQ,uBAAuB;EAC1C,MAAM,KAAK,UAAU,IAAI;EACzB,cAAc;CAChB,CAAC;CAED,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAClB,MAAM,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;CAGtD,OAAO,iBAAiB,IAAI,IAAI;AAClC;AAEA,SAAgB,gCAAgC,QAAsB;CACpE,OAAO,gBAAgB,0BAA0B,EAC/C,KACA,MACA,UACkD;EAClD,MAAM,MAAM,MAAM,YAAY,KAAK;GACjC;GACA,QAAQ;GACR;GACA,SAAS;IACP,QAAQ;IACR,gBAAgB;GAClB;GACA,MAAM,KAAK,UAAU,IAAI;GACzB,cAAc;EAChB,CAAC;EAED,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAClB,MAAM,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;EAGtD,OAAO,iBAAiB,IAAI,IAAI;CAClC;AACF;AAEA,gBAAgB,iBAAiB,MAA6D;CAC5F,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CAEb,IAAI;EACF,SAAS;GACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MACF;GAGF,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;GAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;GAC/B,SAAS,MAAM,IAAI,KAAK;GAExB,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,KAAK,KAAK,MAAM,IAClB;IAGF,MAAM,QAAQ,WAAW,IAAI;IAC7B,IAAI,OACF,MAAM;GAEV;EACF;EAEA,UAAU,QAAQ,OAAO;EACzB,IAAI,OAAO,KAAK,MAAM,IAAI;GACxB,MAAM,QAAQ,WAAW,MAAM;GAC/B,IAAI,OACF,MAAM;EAEV;CACF,UAAU;EACR,MAAM,OAAO,OAAO,EAAE,YAAY,CAAC,CAAC;CACtC;AACF"}
|
package/dist/core/api.d.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* The single funnel for raw-fetch HTTP, so the cross-cutting header, credential,
|
|
3
|
-
* and error policy has one home and call sites only declare intent. Returns a
|
|
4
|
-
* Response (not parsed data) so one primitive serves JSON, the chat's streaming
|
|
5
|
-
* getReader(), and multipart alike. Not for the Inertia world (router/useHttp),
|
|
6
|
-
* which carries its own headers.
|
|
7
|
-
*/
|
|
1
|
+
import { BrowserToken as GeneratedBrowserToken, RemoteAccess as GeneratedRemoteAccess } from '../types/generated';
|
|
8
2
|
export declare class ApiError extends Error {
|
|
9
3
|
readonly response: Response;
|
|
10
4
|
constructor(response: Response);
|
|
@@ -14,5 +8,18 @@ export type ApiInit = Omit<RequestInit, "headers"> & {
|
|
|
14
8
|
headers?: Record<string, string>;
|
|
15
9
|
throwOnError?: boolean;
|
|
16
10
|
};
|
|
11
|
+
export type BrowserToken = GeneratedBrowserToken;
|
|
12
|
+
export type RemoteAccess = GeneratedRemoteAccess;
|
|
13
|
+
export type RemoteInit = Omit<RequestInit, "credentials" | "headers"> & {
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
remote: RemoteAccess;
|
|
16
|
+
retryOnUnauthorized?: boolean;
|
|
17
|
+
throwOnError?: boolean;
|
|
18
|
+
};
|
|
17
19
|
export declare function apiFetch(url: string, init?: ApiInit): Promise<Response>;
|
|
18
20
|
export declare function apiJson<T>(url: string, init?: ApiInit): Promise<T>;
|
|
21
|
+
export declare function clearRemoteTokenCache(): void;
|
|
22
|
+
export declare function invalidateRemoteToken(remote: RemoteAccess): void;
|
|
23
|
+
export declare function remoteToken(remote: RemoteAccess): Promise<BrowserToken>;
|
|
24
|
+
export declare function remoteFetch(url: string, init: RemoteInit): Promise<Response>;
|
|
25
|
+
export declare function remoteJson<T>(url: string, init: RemoteInit): Promise<T>;
|
package/dist/core/api.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { localeHeader } from "../i18n/locale.js";
|
|
1
2
|
import { withHeaders } from "./headers.js";
|
|
2
3
|
//#region resources/js/core/api.ts
|
|
3
4
|
/**
|
|
@@ -18,6 +19,9 @@ function xsrfToken() {
|
|
|
18
19
|
const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);
|
|
19
20
|
return match ? decodeURIComponent(match[1]) : "";
|
|
20
21
|
}
|
|
22
|
+
var tokenRefreshSkewMs = 1e4;
|
|
23
|
+
var remoteTokenCache = /* @__PURE__ */ new Map();
|
|
24
|
+
var pendingRemoteTokens = /* @__PURE__ */ new Map();
|
|
21
25
|
function defaultHeaders(method) {
|
|
22
26
|
if (!(method !== void 0 && method !== "GET" && method !== "HEAD")) return { Accept: "application/json" };
|
|
23
27
|
return {
|
|
@@ -45,7 +49,79 @@ async function apiFetch(url, init = {}) {
|
|
|
45
49
|
async function apiJson(url, init) {
|
|
46
50
|
return (await apiFetch(url, init)).json();
|
|
47
51
|
}
|
|
52
|
+
function remoteTokenKey(remote) {
|
|
53
|
+
return [
|
|
54
|
+
remote.source,
|
|
55
|
+
remote.audience,
|
|
56
|
+
[...remote.scopes].sort().join(" ")
|
|
57
|
+
].join("");
|
|
58
|
+
}
|
|
59
|
+
function clearRemoteTokenCache() {
|
|
60
|
+
remoteTokenCache.clear();
|
|
61
|
+
pendingRemoteTokens.clear();
|
|
62
|
+
}
|
|
63
|
+
function invalidateRemoteToken(remote) {
|
|
64
|
+
remoteTokenCache.delete(remoteTokenKey(remote));
|
|
65
|
+
}
|
|
66
|
+
async function remoteToken(remote) {
|
|
67
|
+
const key = remoteTokenKey(remote);
|
|
68
|
+
const cached = remoteTokenCache.get(key);
|
|
69
|
+
if (cached && cached.expiresAt > Date.now() + tokenRefreshSkewMs) return cached.token;
|
|
70
|
+
const pending = pendingRemoteTokens.get(key);
|
|
71
|
+
if (pending) return pending;
|
|
72
|
+
const request = apiJson(remote.tokenEndpoint, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
ref: remote.ref,
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
nodeId: remote.nodeId,
|
|
77
|
+
nodeType: remote.nodeType,
|
|
78
|
+
audience: remote.audience,
|
|
79
|
+
scopes: remote.scopes
|
|
80
|
+
})
|
|
81
|
+
}).then((token) => {
|
|
82
|
+
remoteTokenCache.set(key, {
|
|
83
|
+
token,
|
|
84
|
+
expiresAt: Date.now() + Math.max(0, token.expiresIn) * 1e3
|
|
85
|
+
});
|
|
86
|
+
return token;
|
|
87
|
+
}).finally(() => {
|
|
88
|
+
pendingRemoteTokens.delete(key);
|
|
89
|
+
});
|
|
90
|
+
pendingRemoteTokens.set(key, request);
|
|
91
|
+
return request;
|
|
92
|
+
}
|
|
93
|
+
function isUnauthorized(response) {
|
|
94
|
+
return response.status === 401 || response.status === 403;
|
|
95
|
+
}
|
|
96
|
+
async function fetchRemoteWithToken(url, init, token) {
|
|
97
|
+
const { headers, ...rest } = init;
|
|
98
|
+
return fetch(url, {
|
|
99
|
+
...rest,
|
|
100
|
+
credentials: "omit",
|
|
101
|
+
headers: {
|
|
102
|
+
Accept: "application/json",
|
|
103
|
+
...localeHeader(),
|
|
104
|
+
...headers,
|
|
105
|
+
Authorization: `${token.tokenType} ${token.accessToken}`
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async function remoteFetch(url, init) {
|
|
110
|
+
const { remote, retryOnUnauthorized = true, throwOnError = true, ...request } = init;
|
|
111
|
+
let token = await remoteToken(remote);
|
|
112
|
+
let response = await fetchRemoteWithToken(url, request, token);
|
|
113
|
+
if (retryOnUnauthorized && isUnauthorized(response)) {
|
|
114
|
+
invalidateRemoteToken(remote);
|
|
115
|
+
token = await remoteToken(remote);
|
|
116
|
+
response = await fetchRemoteWithToken(url, request, token);
|
|
117
|
+
}
|
|
118
|
+
if (throwOnError && !response.ok) throw new ApiError(response);
|
|
119
|
+
return response;
|
|
120
|
+
}
|
|
121
|
+
async function remoteJson(url, init) {
|
|
122
|
+
return (await remoteFetch(url, init)).json();
|
|
123
|
+
}
|
|
48
124
|
//#endregion
|
|
49
|
-
export { ApiError, apiFetch, apiJson };
|
|
125
|
+
export { ApiError, apiFetch, apiJson, clearRemoteTokenCache, invalidateRemoteToken, remoteFetch, remoteJson, remoteToken };
|
|
50
126
|
|
|
51
127
|
//# sourceMappingURL=api.js.map
|
package/dist/core/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../resources/js/core/api.ts"],"sourcesContent":["/**\n * The single funnel for raw-fetch HTTP, so the cross-cutting header, credential,\n * and error policy has one home and call sites only declare intent. Returns a\n * Response (not parsed data) so one primitive serves JSON, the chat's streaming\n * getReader(), and multipart alike. Not for the Inertia world (router/useHttp),\n * which carries its own headers.\n */\n\nimport { withHeaders } from \"./headers\";\n\nexport class ApiError extends Error {\n constructor(readonly response: Response) {\n super(`HTTP ${response.status}`);\n }\n}\n\nfunction xsrfToken(): string {\n const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);\n\n return match ? decodeURIComponent(match[1]) : \"\";\n}\n\nexport type ApiInit = Omit<RequestInit, \"headers\"> & {\n ref?: string;\n headers?: Record<string, string>;\n throwOnError?: boolean;\n};\n\nfunction defaultHeaders(method: string | undefined): Record<string, string> {\n const isWrite = method !== undefined && method !== \"GET\" && method !== \"HEAD\";\n\n if (!isWrite) {\n return { Accept: \"application/json\" };\n }\n\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-XSRF-TOKEN\": xsrfToken(),\n };\n}\n\nexport async function apiFetch(url: string, init: ApiInit = {}): Promise<Response> {\n const { ref, headers, throwOnError = true, method, ...rest } = init;\n // Some servers reject a lower-case method line, and fetch only normalizes the\n // standard verbs, so upper-case it here.\n const normalizedMethod = method?.toUpperCase();\n const response = await fetch(url, {\n credentials: \"same-origin\",\n ...rest,\n method: normalizedMethod,\n headers: withHeaders(ref ?? \"\", { ...defaultHeaders(normalizedMethod), ...headers }),\n });\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function apiJson<T>(url: string, init?: ApiInit): Promise<T> {\n return (await apiFetch(url, init)).json() as Promise<T>;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../resources/js/core/api.ts"],"sourcesContent":["/**\n * The single funnel for raw-fetch HTTP, so the cross-cutting header, credential,\n * and error policy has one home and call sites only declare intent. Returns a\n * Response (not parsed data) so one primitive serves JSON, the chat's streaming\n * getReader(), and multipart alike. Not for the Inertia world (router/useHttp),\n * which carries its own headers.\n */\n\nimport { withHeaders } from \"./headers\";\nimport { localeHeader } from \"../i18n/locale\";\nimport type {\n BrowserToken as GeneratedBrowserToken,\n RemoteAccess as GeneratedRemoteAccess,\n} from \"../types/generated\";\n\nexport class ApiError extends Error {\n constructor(readonly response: Response) {\n super(`HTTP ${response.status}`);\n }\n}\n\nfunction xsrfToken(): string {\n const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);\n\n return match ? decodeURIComponent(match[1]) : \"\";\n}\n\nexport type ApiInit = Omit<RequestInit, \"headers\"> & {\n ref?: string;\n headers?: Record<string, string>;\n throwOnError?: boolean;\n};\n\nexport type BrowserToken = GeneratedBrowserToken;\nexport type RemoteAccess = GeneratedRemoteAccess;\n\nexport type RemoteInit = Omit<RequestInit, \"credentials\" | \"headers\"> & {\n headers?: Record<string, string>;\n remote: RemoteAccess;\n retryOnUnauthorized?: boolean;\n throwOnError?: boolean;\n};\n\ntype CachedBrowserToken = {\n expiresAt: number;\n token: BrowserToken;\n};\n\nconst tokenRefreshSkewMs = 10_000;\nconst remoteTokenCache = new Map<string, CachedBrowserToken>();\nconst pendingRemoteTokens = new Map<string, Promise<BrowserToken>>();\n\nfunction defaultHeaders(method: string | undefined): Record<string, string> {\n const isWrite = method !== undefined && method !== \"GET\" && method !== \"HEAD\";\n\n if (!isWrite) {\n return { Accept: \"application/json\" };\n }\n\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"X-XSRF-TOKEN\": xsrfToken(),\n };\n}\n\nexport async function apiFetch(url: string, init: ApiInit = {}): Promise<Response> {\n const { ref, headers, throwOnError = true, method, ...rest } = init;\n // Some servers reject a lower-case method line, and fetch only normalizes the\n // standard verbs, so upper-case it here.\n const normalizedMethod = method?.toUpperCase();\n const response = await fetch(url, {\n credentials: \"same-origin\",\n ...rest,\n method: normalizedMethod,\n headers: withHeaders(ref ?? \"\", { ...defaultHeaders(normalizedMethod), ...headers }),\n });\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function apiJson<T>(url: string, init?: ApiInit): Promise<T> {\n return (await apiFetch(url, init)).json() as Promise<T>;\n}\n\nfunction remoteTokenKey(remote: RemoteAccess): string {\n return [remote.source, remote.audience, [...remote.scopes].sort().join(\" \")].join(\"\\u001f\");\n}\n\nexport function clearRemoteTokenCache(): void {\n remoteTokenCache.clear();\n pendingRemoteTokens.clear();\n}\n\nexport function invalidateRemoteToken(remote: RemoteAccess): void {\n remoteTokenCache.delete(remoteTokenKey(remote));\n}\n\nexport async function remoteToken(remote: RemoteAccess): Promise<BrowserToken> {\n const key = remoteTokenKey(remote);\n const cached = remoteTokenCache.get(key);\n\n if (cached && cached.expiresAt > Date.now() + tokenRefreshSkewMs) {\n return cached.token;\n }\n\n const pending = pendingRemoteTokens.get(key);\n\n if (pending) {\n return pending;\n }\n\n const request = apiJson<BrowserToken>(remote.tokenEndpoint, {\n method: \"POST\",\n ref: remote.ref,\n body: JSON.stringify({\n nodeId: remote.nodeId,\n nodeType: remote.nodeType,\n audience: remote.audience,\n scopes: remote.scopes,\n }),\n })\n .then((token) => {\n remoteTokenCache.set(key, {\n token,\n expiresAt: Date.now() + Math.max(0, token.expiresIn) * 1000,\n });\n\n return token;\n })\n .finally(() => {\n pendingRemoteTokens.delete(key);\n });\n\n pendingRemoteTokens.set(key, request);\n\n return request;\n}\n\nfunction isUnauthorized(response: Response): boolean {\n return response.status === 401 || response.status === 403;\n}\n\nasync function fetchRemoteWithToken(\n url: string,\n init: Omit<RemoteInit, \"remote\" | \"retryOnUnauthorized\" | \"throwOnError\">,\n token: BrowserToken,\n): Promise<Response> {\n const { headers, ...rest } = init;\n\n return fetch(url, {\n ...rest,\n credentials: \"omit\",\n headers: {\n Accept: \"application/json\",\n ...localeHeader(),\n ...headers,\n Authorization: `${token.tokenType} ${token.accessToken}`,\n },\n });\n}\n\nexport async function remoteFetch(url: string, init: RemoteInit): Promise<Response> {\n const { remote, retryOnUnauthorized = true, throwOnError = true, ...request } = init;\n let token = await remoteToken(remote);\n let response = await fetchRemoteWithToken(url, request, token);\n\n if (retryOnUnauthorized && isUnauthorized(response)) {\n invalidateRemoteToken(remote);\n token = await remoteToken(remote);\n response = await fetchRemoteWithToken(url, request, token);\n }\n\n if (throwOnError && !response.ok) {\n throw new ApiError(response);\n }\n\n return response;\n}\n\nexport async function remoteJson<T>(url: string, init: RemoteInit): Promise<T> {\n return (await remoteFetch(url, init)).json() as Promise<T>;\n}\n"],"mappings":";;;;;;;;;;AAeA,IAAa,WAAb,cAA8B,MAAM;CACb;CAArB,YAAY,UAA6B;EACvC,MAAM,QAAQ,SAAS,QAAQ;EADZ,KAAA,WAAA;CAErB;AACF;AAEA,SAAS,YAAoB;CAC3B,MAAM,QAAQ,SAAS,OAAO,MAAM,oBAAoB;CAExD,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI;AAChD;AAuBA,IAAM,qBAAqB;AAC3B,IAAM,mCAAmB,IAAI,IAAgC;AAC7D,IAAM,sCAAsB,IAAI,IAAmC;AAEnE,SAAS,eAAe,QAAoD;CAG1E,IAAI,EAFY,WAAW,KAAA,KAAa,WAAW,SAAS,WAAW,SAGrE,OAAO,EAAE,QAAQ,mBAAmB;CAGtC,OAAO;EACL,QAAQ;EACR,gBAAgB;EAChB,oBAAoB;EACpB,gBAAgB,UAAU;CAC5B;AACF;AAEA,eAAsB,SAAS,KAAa,OAAgB,CAAC,GAAsB;CACjF,MAAM,EAAE,KAAK,SAAS,eAAe,MAAM,QAAQ,GAAG,SAAS;CAG/D,MAAM,mBAAmB,QAAQ,YAAY;CAC7C,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,aAAa;EACb,GAAG;EACH,QAAQ;EACR,SAAS,YAAY,OAAO,IAAI;GAAE,GAAG,eAAe,gBAAgB;GAAG,GAAG;EAAQ,CAAC;CACrF,CAAC;CAED,IAAI,gBAAgB,CAAC,SAAS,IAC5B,MAAM,IAAI,SAAS,QAAQ;CAG7B,OAAO;AACT;AAEA,eAAsB,QAAW,KAAa,MAA4B;CACxE,QAAQ,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK;AAC1C;AAEA,SAAS,eAAe,QAA8B;CACpD,OAAO;EAAC,OAAO;EAAQ,OAAO;EAAU,CAAC,GAAG,OAAO,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG;CAAC,EAAE,KAAK,GAAQ;AAC5F;AAEA,SAAgB,wBAA8B;CAC5C,iBAAiB,MAAM;CACvB,oBAAoB,MAAM;AAC5B;AAEA,SAAgB,sBAAsB,QAA4B;CAChE,iBAAiB,OAAO,eAAe,MAAM,CAAC;AAChD;AAEA,eAAsB,YAAY,QAA6C;CAC7E,MAAM,MAAM,eAAe,MAAM;CACjC,MAAM,SAAS,iBAAiB,IAAI,GAAG;CAEvC,IAAI,UAAU,OAAO,YAAY,KAAK,IAAI,IAAI,oBAC5C,OAAO,OAAO;CAGhB,MAAM,UAAU,oBAAoB,IAAI,GAAG;CAE3C,IAAI,SACF,OAAO;CAGT,MAAM,UAAU,QAAsB,OAAO,eAAe;EAC1D,QAAQ;EACR,KAAK,OAAO;EACZ,MAAM,KAAK,UAAU;GACnB,QAAQ,OAAO;GACf,UAAU,OAAO;GACjB,UAAU,OAAO;GACjB,QAAQ,OAAO;EACjB,CAAC;CACH,CAAC,EACE,MAAM,UAAU;EACf,iBAAiB,IAAI,KAAK;GACxB;GACA,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,SAAS,IAAI;EACzD,CAAC;EAED,OAAO;CACT,CAAC,EACA,cAAc;EACb,oBAAoB,OAAO,GAAG;CAChC,CAAC;CAEH,oBAAoB,IAAI,KAAK,OAAO;CAEpC,OAAO;AACT;AAEA,SAAS,eAAe,UAA6B;CACnD,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW;AACxD;AAEA,eAAe,qBACb,KACA,MACA,OACmB;CACnB,MAAM,EAAE,SAAS,GAAG,SAAS;CAE7B,OAAO,MAAM,KAAK;EAChB,GAAG;EACH,aAAa;EACb,SAAS;GACP,QAAQ;GACR,GAAG,aAAa;GAChB,GAAG;GACH,eAAe,GAAG,MAAM,UAAU,GAAG,MAAM;EAC7C;CACF,CAAC;AACH;AAEA,eAAsB,YAAY,KAAa,MAAqC;CAClF,MAAM,EAAE,QAAQ,sBAAsB,MAAM,eAAe,MAAM,GAAG,YAAY;CAChF,IAAI,QAAQ,MAAM,YAAY,MAAM;CACpC,IAAI,WAAW,MAAM,qBAAqB,KAAK,SAAS,KAAK;CAE7D,IAAI,uBAAuB,eAAe,QAAQ,GAAG;EACnD,sBAAsB,MAAM;EAC5B,QAAQ,MAAM,YAAY,MAAM;EAChC,WAAW,MAAM,qBAAqB,KAAK,SAAS,KAAK;CAC3D;CAEA,IAAI,gBAAgB,CAAC,SAAS,IAC5B,MAAM,IAAI,SAAS,QAAQ;CAG7B,OAAO;AACT;AAEA,eAAsB,WAAc,KAAa,MAA8B;CAC7E,QAAQ,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK;AAC7C"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
2
|
import "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
5
|
import { cva } from "class-variance-authority";
|
|
5
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region resources/js/core/components/badge.tsx
|
|
7
7
|
var badgeVariants = cva("inline-flex items-center justify-center rounded-lt-sm border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-lt-icon-xs gap-1 [&>svg]:pointer-events-none focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px] aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40 aria-invalid:border-lt-danger transition-[color,box-shadow] overflow-hidden", {
|
|
8
8
|
variants: { variant: {
|
|
9
|
-
default: "border-transparent bg-lt-primary text-lt-primary-fg [a&]:hover:bg-lt-primary
|
|
10
|
-
secondary: "border-transparent bg-lt-secondary text-lt-secondary-fg [a&]:hover:bg-lt-secondary
|
|
11
|
-
destructive: "border-transparent bg-lt-danger text-lt-danger-fg [a&]:hover:bg-lt-danger
|
|
9
|
+
default: "border-transparent bg-lt-primary text-lt-primary-fg [a&]:hover:bg-lt-primary-hover",
|
|
10
|
+
secondary: "border-transparent bg-lt-secondary text-lt-secondary-fg [a&]:hover:bg-lt-secondary-hover",
|
|
11
|
+
destructive: "border-transparent bg-lt-danger text-lt-danger-fg [a&]:hover:bg-lt-danger-hover focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 dark:bg-lt-danger/60",
|
|
12
12
|
outline: "border-lt-border text-lt-fg [a&]:hover:bg-lt-accent [a&]:hover:text-lt-accent-fg"
|
|
13
13
|
} },
|
|
14
14
|
defaultVariants: { variant: "default" }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.js","names":[],"sources":["../../../resources/js/core/components/badge.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center justify-center rounded-lt-sm border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-lt-icon-xs gap-1 [&>svg]:pointer-events-none focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px] aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40 aria-invalid:border-lt-danger transition-[color,box-shadow] overflow-hidden\",\n {\n variants: {\n variant: {\n default
|
|
1
|
+
{"version":3,"file":"badge.js","names":[],"sources":["../../../resources/js/core/components/badge.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center justify-center rounded-lt-sm border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-lt-icon-xs gap-1 [&>svg]:pointer-events-none focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px] aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40 aria-invalid:border-lt-danger transition-[color,box-shadow] overflow-hidden\",\n {\n variants: {\n variant: {\n default:\n \"border-transparent bg-lt-primary text-lt-primary-fg [a&]:hover:bg-lt-primary-hover\",\n secondary:\n \"border-transparent bg-lt-secondary text-lt-secondary-fg [a&]:hover:bg-lt-secondary-hover\",\n destructive:\n \"border-transparent bg-lt-danger text-lt-danger-fg [a&]:hover:bg-lt-danger-hover focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 dark:bg-lt-danger/60\",\n outline: \"border-lt-border text-lt-fg [a&]:hover:bg-lt-accent [a&]:hover:text-lt-accent-fg\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nfunction Badge({\n className,\n variant,\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp data-slot=\"badge\" className={cn(badgeVariants({ variant }), className)} {...props} />\n );\n}\n\nconst BadgeComponent: RendererComponent<\"badge\"> = ({ node }) => (\n <Badge variant=\"secondary\" className=\"w-fit px-3 py-1\">\n {node.props.label}\n </Badge>\n);\n\nexport default BadgeComponent;\nexport { Badge, badgeVariants };\n"],"mappings":";;;;;;AAMA,IAAM,gBAAgB,IACpB,8ZACA;CACE,UAAU,EACR,SAAS;EACP,SACE;EACF,WACE;EACF,aACE;EACF,SAAS;CACX,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CACF;AAEA,SAAS,MAAM,EACb,WACA,SACA,UAAU,OACV,GAAG,SACyF;CAG5F,OACE,oBAHW,UAAU,OAAO,QAG5B;EAAM,aAAU;EAAQ,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,SAAS;EAAG,GAAI;CAAQ,CAAA;AAE9F;AAEA,IAAM,kBAA8C,EAAE,WACpD,oBAAC,OAAD;CAAO,SAAQ;CAAY,WAAU;WAClC,KAAK,MAAM;AACP,CAAA"}
|