@lattice-php/lattice 0.15.0 → 0.17.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.
Files changed (143) hide show
  1. package/dist/action/components/action-form.js +1 -1
  2. package/dist/action/use-action.js +1 -1
  3. package/dist/chat/types.d.ts +2 -10
  4. package/dist/core/components/button.js +34 -18
  5. package/dist/core/components/button.js.map +1 -1
  6. package/dist/core/components/chart.js +49 -2
  7. package/dist/core/components/chart.js.map +1 -1
  8. package/dist/core/components/control.d.ts +1 -3
  9. package/dist/core/components/control.js.map +1 -1
  10. package/dist/core/components/link.js +25 -29
  11. package/dist/core/components/link.js.map +1 -1
  12. package/dist/core/types.d.ts +22 -42
  13. package/dist/core/use-click-behavior.d.ts +42 -0
  14. package/dist/core/use-click-behavior.js +46 -0
  15. package/dist/core/use-click-behavior.js.map +1 -0
  16. package/dist/create-app.d.ts +8 -2
  17. package/dist/create-app.js +4 -2
  18. package/dist/create-app.js.map +1 -1
  19. package/dist/effects/registry.d.ts +9 -20
  20. package/dist/effects/registry.js +4 -6
  21. package/dist/effects/registry.js.map +1 -1
  22. package/dist/events/event-bridge.d.ts +1 -1
  23. package/dist/events/event-bridge.js +1 -1
  24. package/dist/events/event-bridge.js.map +1 -1
  25. package/dist/form/components/base/input-otp.d.ts +2 -1
  26. package/dist/form/components/base/input-otp.js.map +1 -1
  27. package/dist/form/components/conditions.d.ts +1 -1
  28. package/dist/form/components/conditions.js.map +1 -1
  29. package/dist/form/components/field-props.d.ts +2 -1
  30. package/dist/form/components/field-props.js.map +1 -1
  31. package/dist/form/components/field-scope.d.ts +2 -1
  32. package/dist/form/components/field-scope.js.map +1 -1
  33. package/dist/form/components/fields/date-picker-control.js +11 -13
  34. package/dist/form/components/fields/date-picker-control.js.map +1 -1
  35. package/dist/form/components/fields/row-action-menu.d.ts +2 -1
  36. package/dist/form/components/fields/row-action-menu.js.map +1 -1
  37. package/dist/form/components/fields/row-item.d.ts +2 -1
  38. package/dist/form/components/fields/row-item.js.map +1 -1
  39. package/dist/form/components/fields/table-rows.d.ts +2 -1
  40. package/dist/form/components/fields/table-rows.js.map +1 -1
  41. package/dist/form/components/fields/time-input.js +54 -15
  42. package/dist/form/components/fields/time-input.js.map +1 -1
  43. package/dist/form/components/fields/time-picker-columns.d.ts +24 -0
  44. package/dist/form/components/fields/time-picker-columns.js +76 -0
  45. package/dist/form/components/fields/time-picker-columns.js.map +1 -0
  46. package/dist/form/components/fields/time-picker.d.ts +18 -0
  47. package/dist/form/components/fields/time-picker.js +132 -0
  48. package/dist/form/components/fields/time-picker.js.map +1 -0
  49. package/dist/form/components/fields/use-row-collection.d.ts +2 -1
  50. package/dist/form/components/fields/use-row-collection.js.map +1 -1
  51. package/dist/form/components/form-path.d.ts +0 -1
  52. package/dist/form/components/form-path.js +1 -1
  53. package/dist/form/components/form-path.js.map +1 -1
  54. package/dist/form/components/prefill-targets.d.ts +1 -1
  55. package/dist/form/components/prefill-targets.js.map +1 -1
  56. package/dist/form/components/types.d.ts +5 -1
  57. package/dist/form/components/use-field-commit.d.ts +2 -1
  58. package/dist/form/components/use-field-commit.js.map +1 -1
  59. package/dist/form/components/use-form-resolver.d.ts +2 -1
  60. package/dist/form/components/use-form-resolver.js.map +1 -1
  61. package/dist/format/date-time.d.ts +12 -0
  62. package/dist/format/date-time.js +30 -0
  63. package/dist/format/date-time.js.map +1 -0
  64. package/dist/format/number.d.ts +2 -0
  65. package/dist/format/number.js +23 -0
  66. package/dist/format/number.js.map +1 -0
  67. package/dist/{table/components/cells → format}/numeric.js +1 -1
  68. package/dist/format/numeric.js.map +1 -0
  69. package/dist/format/value.d.ts +6 -0
  70. package/dist/format/value.js +17 -0
  71. package/dist/format/value.js.map +1 -0
  72. package/dist/i18n/config.d.ts +2 -1
  73. package/dist/i18n/config.js.map +1 -1
  74. package/dist/i18n/date-time.js +1 -1
  75. package/dist/i18n/date-time.js.map +1 -1
  76. package/dist/i18n/instance.d.ts +1 -1
  77. package/dist/i18n/instance.js.map +1 -1
  78. package/dist/i18n/locale-reload.d.ts +2 -1
  79. package/dist/i18n/locale-reload.js.map +1 -1
  80. package/dist/index.d.ts +1 -1
  81. package/dist/index.js +1 -1
  82. package/dist/layout/components.js +1 -1
  83. package/dist/layout/menu-item.js +43 -49
  84. package/dist/layout/menu-item.js.map +1 -1
  85. package/dist/notifications/api.d.ts +6 -0
  86. package/dist/notifications/api.js +21 -0
  87. package/dist/notifications/api.js.map +1 -0
  88. package/dist/notifications/components/empty-state.d.ts +1 -0
  89. package/dist/notifications/components/empty-state.js +21 -0
  90. package/dist/notifications/components/empty-state.js.map +1 -0
  91. package/dist/notifications/components/notification-item.d.ts +6 -0
  92. package/dist/notifications/components/notification-item.js +65 -0
  93. package/dist/notifications/components/notification-item.js.map +1 -0
  94. package/dist/notifications/components/notification-list.d.ts +10 -0
  95. package/dist/notifications/components/notification-list.js +38 -0
  96. package/dist/notifications/components/notification-list.js.map +1 -0
  97. package/dist/notifications/components/notifications-echo.d.ts +5 -0
  98. package/dist/notifications/components/notifications-echo.js +22 -0
  99. package/dist/notifications/components/notifications-echo.js.map +1 -0
  100. package/dist/notifications/components/notifications.d.ts +3 -0
  101. package/dist/notifications/components/notifications.js +109 -0
  102. package/dist/notifications/components/notifications.js.map +1 -0
  103. package/dist/notifications/index.d.ts +1 -0
  104. package/dist/notifications/index.js +11 -0
  105. package/dist/notifications/index.js.map +1 -0
  106. package/dist/notifications/store.d.ts +25 -0
  107. package/dist/notifications/store.js +100 -0
  108. package/dist/notifications/store.js.map +1 -0
  109. package/dist/notifications/types.d.ts +10 -0
  110. package/dist/notifications/types.js +0 -0
  111. package/dist/realtime/build-effects.d.ts +2 -1
  112. package/dist/realtime/build-effects.js.map +1 -1
  113. package/dist/realtime/subscriptions.js.map +1 -1
  114. package/dist/registry/eager.js +2 -1
  115. package/dist/registry/eager.js.map +1 -1
  116. package/dist/registry/lazy.js +2 -1
  117. package/dist/registry/lazy.js.map +1 -1
  118. package/dist/table/bulk.d.ts +2 -1
  119. package/dist/table/bulk.js.map +1 -1
  120. package/dist/table/components/bulk-bar.js +2 -2
  121. package/dist/table/components/cells/money-cell.js +11 -12
  122. package/dist/table/components/cells/money-cell.js.map +1 -1
  123. package/dist/table/components/cells/number-cell.js +11 -11
  124. package/dist/table/components/cells/number-cell.js.map +1 -1
  125. package/dist/table/components/cells/text-cell.js +1 -1
  126. package/dist/table/components/filter-controls.d.ts +0 -4
  127. package/dist/table/components/filter-controls.js.map +1 -1
  128. package/dist/table/components/table-cell.js.map +1 -1
  129. package/dist/table/format.d.ts +1 -10
  130. package/dist/table/format.js +2 -24
  131. package/dist/table/format.js.map +1 -1
  132. package/dist/table/types.d.ts +7 -17
  133. package/dist/types/generated.d.ts +137 -290
  134. package/dist/types/index.d.ts +1 -1
  135. package/dist/vite-client.d.ts +8 -0
  136. package/dist/vite.d.ts +35 -1
  137. package/dist/vite.js +60 -2
  138. package/dist/vite.js.map +1 -1
  139. package/package.json +13 -2
  140. package/resources/icons/bell.svg +16 -0
  141. package/resources/icons/clock.svg +16 -0
  142. package/dist/table/components/cells/numeric.js.map +0 -1
  143. /package/dist/{table/components/cells → format}/numeric.d.ts +0 -0
@@ -1,9 +1,9 @@
1
1
  import { Renderer } from "../../core/renderer.js";
2
2
  import { useT } from "../../i18n/instance.js";
3
- import { dispatchActionError } from "../../effects/dispatch.js";
4
3
  import { Button } from "../../core/components/button.js";
5
4
  import { Dialog, DialogContent, DialogHeader } from "../../core/components/dialog.js";
6
5
  import { Spinner } from "../../core/components/spinner.js";
6
+ import { dispatchActionError } from "../../effects/dispatch.js";
7
7
  import { apiFetch } from "../../core/api.js";
8
8
  import { Skeleton } from "../../core/components/skeleton.js";
9
9
  import { FormProvider } from "../../form/components/context.js";
@@ -1,7 +1,7 @@
1
1
  import { withHeaders } from "../core/headers.js";
2
+ import { ConfirmDialog } from "../core/components/confirm-dialog.js";
2
3
  import { getActionEffects } from "../effects/dispatch.js";
3
4
  import { useEffectDispatcher } from "../effects/use-effect-dispatcher.js";
4
- import { ConfirmDialog } from "../core/components/confirm-dialog.js";
5
5
  import { runAction } from "./run-action.js";
6
6
  import { ActionForm, useLazyActionForm } from "./components/action-form.js";
7
7
  import { router, useHttp } from "@inertiajs/react";
@@ -1,14 +1,6 @@
1
1
  import { Node } from '../core/types';
2
- import { ChatMessage as GeneratedChatMessage, ChatRole } from '../types/generated';
3
- export type { ChatRole };
4
- /**
5
- * The generated message shape, but `parts` is widened from the generated
6
- * `ChatNode` union to open `Node`s — a part is just a component node rendered by
7
- * `type`, so a message can also carry a consumer's custom part.
8
- */
9
- export type ChatMessage = Omit<GeneratedChatMessage, "parts"> & {
10
- parts: Node[];
11
- };
2
+ import { ChatMessage, ChatRole } from '../types/generated';
3
+ export type { ChatMessage, ChatRole };
12
4
  export type ChatStatus = "idle" | "submitted" | "streaming" | "error";
13
5
  export type ChatFrame = {
14
6
  type: "text";
@@ -1,8 +1,7 @@
1
1
  import { cn } from "../../lib/utils.js";
2
2
  import { IconRenderer } from "../../icons/icon-renderer.js";
3
3
  import { nodeIdentity } from "../test-id.js";
4
- import { getActionEffects } from "../../effects/dispatch.js";
5
- import { useEffectDispatcher } from "../../effects/use-effect-dispatcher.js";
4
+ import { ActionTrigger, useClickBehavior } from "../use-click-behavior.js";
6
5
  import { Link } from "@inertiajs/react";
7
6
  import "react";
8
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -45,34 +44,51 @@ function Button({ className, variant, size, asChild = false, ...props }) {
45
44
  });
46
45
  }
47
46
  var ButtonComponent = ({ node }) => {
48
- const { href, label, icon } = node.props;
49
- const effects = node.props.effects ?? [];
47
+ const { label, icon } = node.props;
50
48
  const variant = node.props.variant ?? "default";
51
49
  const testId = nodeIdentity(node);
52
- const dispatch = useEffectDispatcher();
53
- if (href) return /* @__PURE__ */ jsx(Button, {
50
+ const behavior = useClickBehavior(node.props);
51
+ const size = icon ? "icon" : "default";
52
+ const content = icon ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IconRenderer, {
53
+ className: "size-lt-icon-md",
54
+ icon
55
+ }), label ? /* @__PURE__ */ jsx("span", {
56
+ className: "sr-only",
57
+ children: label
58
+ }) : null] }) : label;
59
+ const triggerButton = ({ onClick, processing }) => /* @__PURE__ */ jsx(Button, {
60
+ "data-test": testId,
61
+ disabled: processing,
62
+ onClick,
63
+ size,
64
+ variant,
65
+ children: content
66
+ });
67
+ if (behavior.kind === "navigate") return /* @__PURE__ */ jsx(Button, {
54
68
  asChild: true,
55
69
  "data-test": testId,
56
70
  variant,
57
- size: "default",
71
+ size,
58
72
  children: /* @__PURE__ */ jsx(Link, {
59
- href,
60
- children: label
73
+ href: behavior.href,
74
+ method: behavior.method,
75
+ children: content
61
76
  })
62
77
  });
78
+ if (behavior.kind === "action") return /* @__PURE__ */ jsx(ActionTrigger, {
79
+ action: behavior.action,
80
+ children: triggerButton
81
+ });
82
+ if (behavior.kind === "effects") return triggerButton({
83
+ onClick: behavior.onClick,
84
+ processing: false
85
+ });
63
86
  return /* @__PURE__ */ jsx(Button, {
64
87
  "data-test": testId,
65
- onClick: effects.length > 0 ? () => dispatch(getActionEffects(effects)) : void 0,
66
- size: icon ? "icon" : "default",
88
+ size,
67
89
  type: node.props.buttonType,
68
90
  variant,
69
- children: icon ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IconRenderer, {
70
- className: "size-lt-icon-md",
71
- icon
72
- }), label ? /* @__PURE__ */ jsx("span", {
73
- className: "sr-only",
74
- children: label
75
- }) : null] }) : label
91
+ children: content
76
92
  });
77
93
  };
78
94
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../../../resources/js/core/components/button.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport { 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 { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\n\nexport type { ButtonVariant };\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lt-sm text-base font-medium transition-[color,box-shadow] disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-lt-icon-md [&_svg]:shrink-0 outline-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\",\n {\n variants: {\n variant: {\n default:\n \"bg-lt-primary text-lt-primary-fg shadow-lt-xs hover:bg-lt-primary-hover active:bg-lt-primary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n destructive:\n \"bg-lt-danger text-lt-danger-fg shadow-lt-xs hover:bg-lt-danger-hover active:bg-lt-danger-active focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n success:\n \"bg-lt-success text-lt-success-fg shadow-lt-xs hover:bg-lt-success-hover active:bg-lt-success-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n info: \"bg-lt-info text-lt-info-fg shadow-lt-xs hover:bg-lt-info-hover active:bg-lt-info-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n outline:\n \"border border-lt-input bg-lt-bg shadow-lt-xs hover:bg-lt-accent hover:text-lt-accent-fg disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:border-transparent disabled:shadow-none\",\n secondary:\n \"bg-lt-secondary text-lt-secondary-fg shadow-lt-xs hover:bg-lt-secondary-hover active:bg-lt-secondary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n ghost: \"hover:bg-lt-accent hover:text-lt-accent-fg disabled:text-lt-disabled-fg\",\n link: \"text-lt-primary underline-offset-4 hover:underline disabled:text-lt-disabled-fg disabled:no-underline\",\n },\n size: {\n default: \"h-lt-control-md px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-lt-control-sm rounded-lt-sm px-3 has-[>svg]:px-2.5\",\n lg: \"h-lt-control-lg rounded-lt-sm px-6 has-[>svg]:px-4\",\n icon: \"size-lt-control-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst ButtonComponent: RendererComponent<\"button\"> = ({ node }) => {\n const { href, label, icon } = node.props;\n const effects = node.props.effects ?? [];\n const variant = node.props.variant ?? \"default\";\n const testId = nodeIdentity(node);\n const dispatch = useEffectDispatcher();\n\n if (href) {\n return (\n <Button asChild data-test={testId} variant={variant} size=\"default\">\n <Link href={href}>{label}</Link>\n </Button>\n );\n }\n\n const hasEffects = effects.length > 0;\n\n return (\n <Button\n data-test={testId}\n onClick={hasEffects ? () => dispatch(getActionEffects(effects)) : undefined}\n size={icon ? \"icon\" : \"default\"}\n type={node.props.buttonType}\n variant={variant}\n >\n {icon ? (\n <>\n <IconRenderer className=\"size-lt-icon-md\" icon={icon} />\n {label ? <span className=\"sr-only\">{label}</span> : null}\n </>\n ) : (\n label\n )}\n </Button>\n );\n};\n\nexport default ButtonComponent;\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;;;;;AAcA,IAAM,iBAAiB,IACrB,+bACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,aACE;GACF,SACE;GACF,MAAM;GACN,SACE;GACF,WACE;GACF,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,MAAM;EACR;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAEA,SAAS,OAAO,EACd,WACA,SACA,MACA,UAAU,OACV,GAAG,SAIA;CAGH,OACE,oBAHW,UAAU,OAAO,UAG5B;EACE,aAAU;EACV,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,EAAE,MAAM,OAAO,SAAS,KAAK;CACnC,MAAM,UAAU,KAAK,MAAM,WAAW,CAAC;CACvC,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,WAAW,oBAAoB;CAErC,IAAI,MACF,OACE,oBAAC,QAAD;EAAQ,SAAA;EAAQ,aAAW;EAAiB;EAAS,MAAK;YACxD,oBAAC,MAAD;GAAY;aAAO;EAAY,CAAA;CACzB,CAAA;CAMZ,OACE,oBAAC,QAAD;EACE,aAAW;EACX,SALe,QAAQ,SAAS,UAKJ,SAAS,iBAAiB,OAAO,CAAC,IAAI,KAAA;EAClE,MAAM,OAAO,SAAS;EACtB,MAAM,KAAK,MAAM;EACR;YAER,OACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;GAAc,WAAU;GAAwB;EAAO,CAAA,GACtD,QAAQ,oBAAC,QAAD;GAAM,WAAU;aAAW;EAAY,CAAA,IAAI,IACpD,EAAA,CAAA,IAEF;CAEI,CAAA;AAEZ"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../../resources/js/core/components/button.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport { 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 { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport {\n ActionTrigger,\n type TriggerState,\n useClickBehavior,\n} from \"@lattice-php/lattice/core/use-click-behavior\";\nimport type { ButtonVariant } from \"@lattice-php/lattice/types/generated\";\n\nexport type { ButtonVariant };\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lt-sm text-base font-medium transition-[color,box-shadow] disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-lt-icon-md [&_svg]:shrink-0 outline-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\",\n {\n variants: {\n variant: {\n default:\n \"bg-lt-primary text-lt-primary-fg shadow-lt-xs hover:bg-lt-primary-hover active:bg-lt-primary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n destructive:\n \"bg-lt-danger text-lt-danger-fg shadow-lt-xs hover:bg-lt-danger-hover active:bg-lt-danger-active focus-visible:ring-lt-danger/20 dark:focus-visible:ring-lt-danger/40 disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n success:\n \"bg-lt-success text-lt-success-fg shadow-lt-xs hover:bg-lt-success-hover active:bg-lt-success-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n info: \"bg-lt-info text-lt-info-fg shadow-lt-xs hover:bg-lt-info-hover active:bg-lt-info-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n outline:\n \"border border-lt-input bg-lt-bg shadow-lt-xs hover:bg-lt-accent hover:text-lt-accent-fg disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:border-transparent disabled:shadow-none\",\n secondary:\n \"bg-lt-secondary text-lt-secondary-fg shadow-lt-xs hover:bg-lt-secondary-hover active:bg-lt-secondary-active disabled:bg-lt-disabled disabled:text-lt-disabled-fg disabled:shadow-none\",\n ghost: \"hover:bg-lt-accent hover:text-lt-accent-fg disabled:text-lt-disabled-fg\",\n link: \"text-lt-primary underline-offset-4 hover:underline disabled:text-lt-disabled-fg disabled:no-underline\",\n },\n size: {\n default: \"h-lt-control-md px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-lt-control-sm rounded-lt-sm px-3 has-[>svg]:px-2.5\",\n lg: \"h-lt-control-lg rounded-lt-sm px-6 has-[>svg]:px-4\",\n icon: \"size-lt-control-md\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst ButtonComponent: RendererComponent<\"button\"> = ({ node }) => {\n const { label, icon } = node.props;\n const variant = node.props.variant ?? \"default\";\n const testId = nodeIdentity(node);\n const behavior = useClickBehavior(node.props);\n const size = icon ? \"icon\" : \"default\";\n const content = icon ? (\n <>\n <IconRenderer className=\"size-lt-icon-md\" icon={icon} />\n {label ? <span className=\"sr-only\">{label}</span> : null}\n </>\n ) : (\n label\n );\n\n const triggerButton = ({ onClick, processing }: TriggerState) => (\n <Button\n data-test={testId}\n disabled={processing}\n onClick={onClick}\n size={size}\n variant={variant}\n >\n {content}\n </Button>\n );\n\n if (behavior.kind === \"navigate\") {\n return (\n <Button asChild data-test={testId} variant={variant} size={size}>\n <Link href={behavior.href} method={behavior.method}>\n {content}\n </Link>\n </Button>\n );\n }\n\n if (behavior.kind === \"action\") {\n return <ActionTrigger action={behavior.action}>{triggerButton}</ActionTrigger>;\n }\n\n if (behavior.kind === \"effects\") {\n return triggerButton({ onClick: behavior.onClick, processing: false });\n }\n\n return (\n <Button data-test={testId} size={size} type={node.props.buttonType} variant={variant}>\n {content}\n </Button>\n );\n};\n\nexport default ButtonComponent;\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;;;;AAiBA,IAAM,iBAAiB,IACrB,+bACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,aACE;GACF,SACE;GACF,MAAM;GACN,SACE;GACF,WACE;GACF,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,MAAM;EACR;CACF;CACA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CACF;AAEA,SAAS,OAAO,EACd,WACA,SACA,MACA,UAAU,OACV,GAAG,SAIA;CAGH,OACE,oBAHW,UAAU,OAAO,UAG5B;EACE,aAAU;EACV,WAAW,GAAG,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAAC;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,IAAM,mBAAgD,EAAE,WAAW;CACjE,MAAM,EAAE,OAAO,SAAS,KAAK;CAC7B,MAAM,UAAU,KAAK,MAAM,WAAW;CACtC,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,WAAW,iBAAiB,KAAK,KAAK;CAC5C,MAAM,OAAO,OAAO,SAAS;CAC7B,MAAM,UAAU,OACd,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EAAc,WAAU;EAAwB;CAAO,CAAA,GACtD,QAAQ,oBAAC,QAAD;EAAM,WAAU;YAAW;CAAY,CAAA,IAAI,IACpD,EAAA,CAAA,IAEF;CAGF,MAAM,iBAAiB,EAAE,SAAS,iBAChC,oBAAC,QAAD;EACE,aAAW;EACX,UAAU;EACD;EACH;EACG;YAER;CACK,CAAA;CAGV,IAAI,SAAS,SAAS,YACpB,OACE,oBAAC,QAAD;EAAQ,SAAA;EAAQ,aAAW;EAAiB;EAAe;YACzD,oBAAC,MAAD;GAAM,MAAM,SAAS;GAAM,QAAQ,SAAS;aACzC;EACG,CAAA;CACA,CAAA;CAIZ,IAAI,SAAS,SAAS,UACpB,OAAO,oBAAC,eAAD;EAAe,QAAQ,SAAS;YAAS;CAA6B,CAAA;CAG/E,IAAI,SAAS,SAAS,WACpB,OAAO,cAAc;EAAE,SAAS,SAAS;EAAS,YAAY;CAAM,CAAC;CAGvE,OACE,oBAAC,QAAD;EAAQ,aAAW;EAAc;EAAM,MAAM,KAAK,MAAM;EAAqB;YAC1E;CACK,CAAA;AAEZ"}
@@ -1,4 +1,7 @@
1
+ import { useLocale } from "../../i18n/locale.js";
2
+ import { useTimezone } from "../../i18n/timezone.js";
1
3
  import { nodeIdentity } from "../test-id.js";
4
+ import { formatValue } from "../../format/value.js";
2
5
  import { jsx, jsxs } from "react/jsx-runtime";
3
6
  import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, ComposedChart, Legend, Line, LineChart, Pie, PieChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
4
7
  //#region resources/js/core/components/chart.tsx
@@ -20,6 +23,18 @@ var compactLegendProps = {
20
23
  }
21
24
  };
22
25
  var axisTick = { fontSize: 10 };
26
+ var tooltipProps = {
27
+ contentStyle: {
28
+ background: "var(--lt-surface)",
29
+ border: "1px solid var(--lt-border)",
30
+ borderRadius: "var(--lt-radius-sm)",
31
+ boxShadow: "var(--lt-shadow-sm)",
32
+ color: "var(--lt-surface-fg)",
33
+ fontSize: 12
34
+ },
35
+ itemStyle: { color: "var(--lt-surface-fg)" },
36
+ labelStyle: { color: "var(--lt-muted-fg)" }
37
+ };
23
38
  var palette = [
24
39
  "var(--lt-primary)",
25
40
  "var(--lt-success)",
@@ -70,6 +85,21 @@ function ChartFrame({ children, description, id, title }) {
70
85
  function CartesianChart({ props }) {
71
86
  const series = props.series.filter(isCartesianSeries);
72
87
  const RechartsChart = cartesianChartFor(series);
88
+ const { locale } = useLocale();
89
+ const { timezone } = useTimezone();
90
+ const ctx = {
91
+ locale,
92
+ timezone
93
+ };
94
+ const formatCategory = (value) => formatValue(value, props.categoryFormat, ctx);
95
+ const formatValueTick = (value) => formatValue(value, props.valueFormat, ctx);
96
+ const tooltipCursor = series.some((item) => item.type === "bar") ? {
97
+ fill: "var(--lt-muted-fg)",
98
+ fillOpacity: .15
99
+ } : {
100
+ stroke: "var(--lt-muted-fg)",
101
+ strokeOpacity: .4
102
+ };
73
103
  return /* @__PURE__ */ jsx(ResponsiveContainer, {
74
104
  width: "100%",
75
105
  height: props.height,
@@ -86,15 +116,22 @@ function CartesianChart({ props }) {
86
116
  dataKey: props.categoryKey,
87
117
  stroke: "var(--lt-muted-fg)",
88
118
  tick: axisTick,
119
+ tickFormatter: formatCategory,
89
120
  tickLine: false
90
121
  }),
91
122
  props.yAxis && /* @__PURE__ */ jsx(YAxis, {
92
123
  stroke: "var(--lt-muted-fg)",
93
124
  tick: axisTick,
125
+ tickFormatter: formatValueTick,
94
126
  tickLine: false,
95
127
  width: 42
96
128
  }),
97
- props.tooltip && /* @__PURE__ */ jsx(Tooltip, {}),
129
+ props.tooltip && /* @__PURE__ */ jsx(Tooltip, {
130
+ ...tooltipProps,
131
+ cursor: tooltipCursor,
132
+ formatter: formatValueTick,
133
+ labelFormatter: formatCategory
134
+ }),
98
135
  props.legend && /* @__PURE__ */ jsx(Legend, { ...compactLegendProps }),
99
136
  series.map((item, index) => {
100
137
  const color = item.color ?? colorAt(index);
@@ -134,6 +171,12 @@ function CartesianChart({ props }) {
134
171
  });
135
172
  }
136
173
  function PieChartView({ props, series }) {
174
+ const { locale } = useLocale();
175
+ const { timezone } = useTimezone();
176
+ const ctx = {
177
+ locale,
178
+ timezone
179
+ };
137
180
  return /* @__PURE__ */ jsx(ResponsiveContainer, {
138
181
  width: "100%",
139
182
  height: props.height,
@@ -141,7 +184,11 @@ function PieChartView({ props, series }) {
141
184
  children: /* @__PURE__ */ jsxs(PieChart, {
142
185
  margin: chartMargin,
143
186
  children: [
144
- props.tooltip && /* @__PURE__ */ jsx(Tooltip, {}),
187
+ props.tooltip && /* @__PURE__ */ jsx(Tooltip, {
188
+ ...tooltipProps,
189
+ formatter: (value) => formatValue(value, props.valueFormat, ctx),
190
+ labelFormatter: (value) => formatValue(value, props.categoryFormat, ctx)
191
+ }),
145
192
  props.legend && /* @__PURE__ */ jsx(Legend, { ...compactLegendProps }),
146
193
  /* @__PURE__ */ jsx(Pie, {
147
194
  data: props.data,
@@ -1 +1 @@
1
- {"version":3,"file":"chart.js","names":[],"sources":["../../../resources/js/core/components/chart.tsx"],"sourcesContent":["import {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n ComposedChart,\n Legend,\n Line,\n LineChart,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { PropsOf, RendererComponent } from \"@lattice-php/lattice/core/types\";\n\ntype ChartProps = PropsOf<\"chart\">;\ntype ChartSeries = ChartProps[\"series\"][number];\ntype ChartDatum = ChartProps[\"data\"][number];\ntype CartesianSeries = ChartSeries & { type: \"area\" | \"bar\" | \"line\" };\ntype ChartMargin = { bottom: number; left: number; right: number; top: number };\ntype CartesianChartComponent = ComponentType<{\n children: ReactNode;\n data: ChartProps[\"data\"];\n margin?: ChartMargin;\n}>;\n\nconst chartMargin: ChartMargin = { bottom: 0, left: 0, right: 16, top: 8 };\nconst compactLegendProps = {\n align: \"center\" as const,\n height: 24,\n iconSize: 7,\n verticalAlign: \"top\" as const,\n wrapperStyle: { fontSize: 11, lineHeight: \"14px\", paddingBottom: 6 },\n};\nconst axisTick = { fontSize: 10 };\n\nconst palette = [\n \"var(--lt-primary)\",\n \"var(--lt-success)\",\n \"var(--lt-info)\",\n \"var(--lt-warning)\",\n \"var(--lt-danger)\",\n \"var(--lt-muted-fg)\",\n];\n\nfunction colorAt(index: number): string {\n return palette[index % palette.length] ?? \"var(--lt-primary)\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction datumColor(datum: ChartDatum, series: ChartSeries, index: number): string {\n if (isRecord(datum) && typeof datum.color === \"string\") {\n return datum.color;\n }\n\n return series.color ?? colorAt(index);\n}\n\nfunction isCartesianSeries(series: ChartSeries): series is CartesianSeries {\n return series.type === \"area\" || series.type === \"bar\" || series.type === \"line\";\n}\n\nfunction cartesianChartFor(series: CartesianSeries[]): CartesianChartComponent {\n const types = new Set(series.map((item) => item.type));\n const firstSeries = series[0];\n\n if (firstSeries === undefined || types.size !== 1) {\n return ComposedChart;\n }\n\n switch (firstSeries.type) {\n case \"area\":\n return AreaChart;\n case \"bar\":\n return BarChart;\n case \"line\":\n return LineChart;\n }\n}\n\nfunction ChartFrame({\n children,\n description,\n id,\n title,\n}: {\n children: ReactNode;\n description: string | null;\n id?: string;\n title: string | null;\n}) {\n const hasHeader = title !== null || description !== null;\n\n return (\n <div\n className=\"flex flex-col gap-3 rounded-lt border border-lt-border bg-lt-surface p-4 text-lt-surface-fg shadow-lt-sm\"\n data-lattice-component={id}\n >\n {hasHeader && (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n {title !== null && <div className=\"text-sm font-semibold leading-tight\">{title}</div>}\n {description !== null && (\n <div className=\"text-xs leading-5 text-lt-muted-fg\">{description}</div>\n )}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nfunction CartesianChart({ props }: { props: ChartProps }) {\n const series = props.series.filter(isCartesianSeries);\n const RechartsChart = cartesianChartFor(series);\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <RechartsChart data={props.data} margin={chartMargin}>\n {props.grid && <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--lt-border)\" />}\n {props.xAxis && props.categoryKey !== null && (\n <XAxis\n dataKey={props.categoryKey}\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickLine={false}\n />\n )}\n {props.yAxis && (\n <YAxis stroke=\"var(--lt-muted-fg)\" tick={axisTick} tickLine={false} width={42} />\n )}\n {props.tooltip && <Tooltip />}\n {props.legend && <Legend {...compactLegendProps} />}\n {series.map((item, index) => {\n const color = item.color ?? colorAt(index);\n const key = `${item.type}:${item.dataKey}`;\n\n if (item.type === \"area\") {\n return (\n <Area\n key={key}\n dataKey={item.dataKey}\n fill={color}\n fillOpacity={0.16}\n name={item.name ?? undefined}\n stackId={item.stackId ?? undefined}\n stroke={color}\n type=\"monotone\"\n />\n );\n }\n\n if (item.type === \"bar\") {\n return (\n <Bar\n key={key}\n dataKey={item.dataKey}\n fill={color}\n name={item.name ?? undefined}\n radius={[4, 4, 0, 0]}\n stackId={item.stackId ?? undefined}\n />\n );\n }\n\n return (\n <Line\n key={key}\n dataKey={item.dataKey}\n dot={false}\n name={item.name ?? undefined}\n stroke={color}\n strokeWidth={2}\n type=\"monotone\"\n />\n );\n })}\n </RechartsChart>\n </ResponsiveContainer>\n );\n}\n\nfunction PieChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <PieChart margin={chartMargin}>\n {props.tooltip && <Tooltip />}\n {props.legend && <Legend {...compactLegendProps} />}\n <Pie\n data={props.data}\n dataKey={series.dataKey}\n name={series.name ?? undefined}\n nameKey={series.nameKey ?? undefined}\n outerRadius=\"68%\"\n >\n {props.data.map((datum, index) => (\n <Cell key={index} fill={datumColor(datum, series, index)} />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n );\n}\n\nconst ChartComponent: RendererComponent<\"chart\"> = ({ node }) => {\n const props = node.props;\n const pieSeries = props.series.find((series) => series.type === \"pie\");\n const hasCartesianSeries = props.series.some(isCartesianSeries);\n\n return (\n <ChartFrame description={props.description} id={nodeIdentity(node)} title={props.title}>\n <div className=\"min-h-0 w-full\">\n {pieSeries && !hasCartesianSeries ? (\n <PieChartView props={props} series={pieSeries} />\n ) : (\n <CartesianChart props={props} />\n )}\n </div>\n </ChartFrame>\n );\n};\n\nexport default ChartComponent;\n"],"mappings":"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"}
1
+ {"version":3,"file":"chart.js","names":[],"sources":["../../../resources/js/core/components/chart.tsx"],"sourcesContent":["import {\n Area,\n AreaChart,\n Bar,\n BarChart,\n CartesianGrid,\n Cell,\n ComposedChart,\n Legend,\n Line,\n LineChart,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { PropsOf, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { useLocale, useTimezone } from \"@lattice-php/lattice/i18n\";\nimport { formatValue } from \"../../format/value\";\n\ntype ChartProps = PropsOf<\"chart\">;\ntype ChartSeries = ChartProps[\"series\"][number];\ntype ChartDatum = ChartProps[\"data\"][number];\ntype CartesianSeries = ChartSeries & { type: \"area\" | \"bar\" | \"line\" };\ntype ChartMargin = { bottom: number; left: number; right: number; top: number };\ntype CartesianChartComponent = ComponentType<{\n children: ReactNode;\n data: ChartProps[\"data\"];\n margin?: ChartMargin;\n}>;\n\nconst chartMargin: ChartMargin = { bottom: 0, left: 0, right: 16, top: 8 };\nconst compactLegendProps = {\n align: \"center\" as const,\n height: 24,\n iconSize: 7,\n verticalAlign: \"top\" as const,\n wrapperStyle: { fontSize: 11, lineHeight: \"14px\", paddingBottom: 6 },\n};\nconst axisTick = { fontSize: 10 };\nconst tooltipProps = {\n contentStyle: {\n background: \"var(--lt-surface)\",\n border: \"1px solid var(--lt-border)\",\n borderRadius: \"var(--lt-radius-sm)\",\n boxShadow: \"var(--lt-shadow-sm)\",\n color: \"var(--lt-surface-fg)\",\n fontSize: 12,\n },\n itemStyle: { color: \"var(--lt-surface-fg)\" },\n labelStyle: { color: \"var(--lt-muted-fg)\" },\n} as const;\n\nconst palette = [\n \"var(--lt-primary)\",\n \"var(--lt-success)\",\n \"var(--lt-info)\",\n \"var(--lt-warning)\",\n \"var(--lt-danger)\",\n \"var(--lt-muted-fg)\",\n];\n\nfunction colorAt(index: number): string {\n return palette[index % palette.length] ?? \"var(--lt-primary)\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction datumColor(datum: ChartDatum, series: ChartSeries, index: number): string {\n if (isRecord(datum) && typeof datum.color === \"string\") {\n return datum.color;\n }\n\n return series.color ?? colorAt(index);\n}\n\nfunction isCartesianSeries(series: ChartSeries): series is CartesianSeries {\n return series.type === \"area\" || series.type === \"bar\" || series.type === \"line\";\n}\n\nfunction cartesianChartFor(series: CartesianSeries[]): CartesianChartComponent {\n const types = new Set(series.map((item) => item.type));\n const firstSeries = series[0];\n\n if (firstSeries === undefined || types.size !== 1) {\n return ComposedChart;\n }\n\n switch (firstSeries.type) {\n case \"area\":\n return AreaChart;\n case \"bar\":\n return BarChart;\n case \"line\":\n return LineChart;\n }\n}\n\nfunction ChartFrame({\n children,\n description,\n id,\n title,\n}: {\n children: ReactNode;\n description: string | null;\n id?: string;\n title: string | null;\n}) {\n const hasHeader = title !== null || description !== null;\n\n return (\n <div\n className=\"flex flex-col gap-3 rounded-lt border border-lt-border bg-lt-surface p-4 text-lt-surface-fg shadow-lt-sm\"\n data-lattice-component={id}\n >\n {hasHeader && (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n {title !== null && <div className=\"text-sm font-semibold leading-tight\">{title}</div>}\n {description !== null && (\n <div className=\"text-xs leading-5 text-lt-muted-fg\">{description}</div>\n )}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nfunction CartesianChart({ props }: { props: ChartProps }) {\n const series = props.series.filter(isCartesianSeries);\n const RechartsChart = cartesianChartFor(series);\n const { locale } = useLocale();\n const { timezone } = useTimezone();\n const ctx = { locale, timezone };\n const formatCategory = (value: unknown) => formatValue(value, props.categoryFormat, ctx);\n const formatValueTick = (value: unknown) => formatValue(value, props.valueFormat, ctx);\n const hasBarSeries = series.some((item) => item.type === \"bar\");\n const tooltipCursor = hasBarSeries\n ? { fill: \"var(--lt-muted-fg)\", fillOpacity: 0.15 }\n : { stroke: \"var(--lt-muted-fg)\", strokeOpacity: 0.4 };\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <RechartsChart data={props.data} margin={chartMargin}>\n {props.grid && <CartesianGrid strokeDasharray=\"3 3\" stroke=\"var(--lt-border)\" />}\n {props.xAxis && props.categoryKey !== null && (\n <XAxis\n dataKey={props.categoryKey}\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatCategory}\n tickLine={false}\n />\n )}\n {props.yAxis && (\n <YAxis\n stroke=\"var(--lt-muted-fg)\"\n tick={axisTick}\n tickFormatter={formatValueTick}\n tickLine={false}\n width={42}\n />\n )}\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n cursor={tooltipCursor}\n formatter={formatValueTick}\n labelFormatter={formatCategory}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n {series.map((item, index) => {\n const color = item.color ?? colorAt(index);\n const key = `${item.type}:${item.dataKey}`;\n\n if (item.type === \"area\") {\n return (\n <Area\n key={key}\n dataKey={item.dataKey}\n fill={color}\n fillOpacity={0.16}\n name={item.name ?? undefined}\n stackId={item.stackId ?? undefined}\n stroke={color}\n type=\"monotone\"\n />\n );\n }\n\n if (item.type === \"bar\") {\n return (\n <Bar\n key={key}\n dataKey={item.dataKey}\n fill={color}\n name={item.name ?? undefined}\n radius={[4, 4, 0, 0]}\n stackId={item.stackId ?? undefined}\n />\n );\n }\n\n return (\n <Line\n key={key}\n dataKey={item.dataKey}\n dot={false}\n name={item.name ?? undefined}\n stroke={color}\n strokeWidth={2}\n type=\"monotone\"\n />\n );\n })}\n </RechartsChart>\n </ResponsiveContainer>\n );\n}\n\nfunction PieChartView({ props, series }: { props: ChartProps; series: ChartSeries }) {\n const { locale } = useLocale();\n const { timezone } = useTimezone();\n const ctx = { locale, timezone };\n\n return (\n <ResponsiveContainer width=\"100%\" height={props.height} debounce={100}>\n <PieChart margin={chartMargin}>\n {props.tooltip && (\n <Tooltip\n {...tooltipProps}\n formatter={(value) => formatValue(value, props.valueFormat, ctx)}\n labelFormatter={(value) => formatValue(value, props.categoryFormat, ctx)}\n />\n )}\n {props.legend && <Legend {...compactLegendProps} />}\n <Pie\n data={props.data}\n dataKey={series.dataKey}\n name={series.name ?? undefined}\n nameKey={series.nameKey ?? undefined}\n outerRadius=\"68%\"\n >\n {props.data.map((datum, index) => (\n <Cell key={index} fill={datumColor(datum, series, index)} />\n ))}\n </Pie>\n </PieChart>\n </ResponsiveContainer>\n );\n}\n\nconst ChartComponent: RendererComponent<\"chart\"> = ({ node }) => {\n const props = node.props;\n const pieSeries = props.series.find((series) => series.type === \"pie\");\n const hasCartesianSeries = props.series.some(isCartesianSeries);\n\n return (\n <ChartFrame description={props.description} id={nodeIdentity(node)} title={props.title}>\n <div className=\"min-h-0 w-full\">\n {pieSeries && !hasCartesianSeries ? (\n <PieChartView props={props} series={pieSeries} />\n ) : (\n <CartesianChart props={props} />\n )}\n </div>\n </ChartFrame>\n );\n};\n\nexport default ChartComponent;\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { VariantProps } from 'class-variance-authority';
2
1
  export declare const FOCUS_RING = "focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px]";
3
2
  /**
4
3
  * The shared chrome for single-line form/table controls (text inputs, native
@@ -7,6 +6,5 @@ export declare const FOCUS_RING = "focus-visible:border-lt-ring focus-visible:ri
7
6
  * border, focus ring, invalid, and disabled treatment are unified.
8
7
  */
9
8
  export declare const controlSurface: (props?: ({
10
- density?: "comfortable" | "compact" | null | undefined;
9
+ density?: "compact" | "comfortable" | null | undefined;
11
10
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
12
- export type ControlSurfaceVariants = VariantProps<typeof controlSurface>;
@@ -1 +1 @@
1
- {"version":3,"file":"control.js","names":[],"sources":["../../../resources/js/core/components/control.ts"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\n\nexport const FOCUS_RING =\n \"focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px]\";\n\n/**\n * The shared chrome for single-line form/table controls (text inputs, native\n * selects, and the Select/filter trigger buttons). `density` is the only axis\n * that differs between forms (comfortable) and table filters (compact); the\n * border, focus ring, invalid, and disabled treatment are unified.\n */\nexport const controlSurface = cva(\n [\n \"w-full min-w-0 rounded-lt-sm border border-lt-input shadow-lt-xs outline-none transition-[color,box-shadow]\",\n \"placeholder:text-lt-muted-fg\",\n FOCUS_RING,\n \"aria-invalid:border-lt-danger aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40\",\n \"disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-lt-disabled disabled:text-lt-disabled-fg\",\n ],\n {\n variants: {\n density: {\n comfortable: \"h-lt-control-md bg-transparent px-3 py-1 text-base\",\n compact: \"h-lt-control-md bg-lt-bg px-2 text-sm font-normal\",\n },\n },\n defaultVariants: { density: \"comfortable\" },\n },\n);\n\nexport type ControlSurfaceVariants = VariantProps<typeof controlSurface>;\n"],"mappings":";;AAEA,IAAa,aACX;;;;;;;AAQF,IAAa,iBAAiB,IAC5B;CACE;CACA;CACA;CACA;CACA;AACF,GACA;CACE,UAAU,EACR,SAAS;EACP,aAAa;EACb,SAAS;CACX,EACF;CACA,iBAAiB,EAAE,SAAS,cAAc;AAC5C,CACF"}
1
+ {"version":3,"file":"control.js","names":[],"sources":["../../../resources/js/core/components/control.ts"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\nexport const FOCUS_RING =\n \"focus-visible:border-lt-ring focus-visible:ring-lt-ring/50 focus-visible:ring-[3px]\";\n\n/**\n * The shared chrome for single-line form/table controls (text inputs, native\n * selects, and the Select/filter trigger buttons). `density` is the only axis\n * that differs between forms (comfortable) and table filters (compact); the\n * border, focus ring, invalid, and disabled treatment are unified.\n */\nexport const controlSurface = cva(\n [\n \"w-full min-w-0 rounded-lt-sm border border-lt-input shadow-lt-xs outline-none transition-[color,box-shadow]\",\n \"placeholder:text-lt-muted-fg\",\n FOCUS_RING,\n \"aria-invalid:border-lt-danger aria-invalid:ring-lt-danger/20 dark:aria-invalid:ring-lt-danger/40\",\n \"disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-lt-disabled disabled:text-lt-disabled-fg\",\n ],\n {\n variants: {\n density: {\n comfortable: \"h-lt-control-md bg-transparent px-3 py-1 text-base\",\n compact: \"h-lt-control-md bg-lt-bg px-2 text-sm font-normal\",\n },\n },\n defaultVariants: { density: \"comfortable\" },\n },\n);\n"],"mappings":";;AAEA,IAAa,aACX;;;;;;;AAQF,IAAa,iBAAiB,IAC5B;CACE;CACA;CACA;CACA;CACA;AACF,GACA;CACE,UAAU,EACR,SAAS;EACP,aAAa;EACb,SAAS;CACX,EACF;CACA,iBAAiB,EAAE,SAAS,cAAc;AAC5C,CACF"}
@@ -1,7 +1,7 @@
1
1
  import { cn } from "../../lib/utils.js";
2
2
  import { IconRenderer } from "../../icons/icon-renderer.js";
3
3
  import { nodeIdentity } from "../test-id.js";
4
- import { useAction } from "../../action/use-action.js";
4
+ import { ActionTrigger, useClickBehavior } from "../use-click-behavior.js";
5
5
  import { actionMenuItemClassName, useActionMenu } from "../../action/components/action-menu-context.js";
6
6
  import { Link } from "@inertiajs/react";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -14,18 +14,6 @@ function TextLink({ className = "", children, ...props }) {
14
14
  children
15
15
  });
16
16
  }
17
- function ActionLink({ action, ariaLabel, className, children, testId }) {
18
- const { processing, requestSubmit, overlays } = useAction(action);
19
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
20
- "aria-label": ariaLabel,
21
- className: cn(textLinkClassName, className),
22
- "data-test": testId,
23
- disabled: processing,
24
- onClick: requestSubmit,
25
- type: "button",
26
- children
27
- }), overlays] });
28
- }
29
17
  function LinkAffix({ affix, className }) {
30
18
  if (affix.icon) return /* @__PURE__ */ jsx(IconRenderer, {
31
19
  className: cn("size-lt-icon-md shrink-0", className),
@@ -69,12 +57,10 @@ function labelWithTextAffixes(label, prefix, suffix) {
69
57
  }
70
58
  var LinkComponent = ({ node }) => {
71
59
  const isMenuItem = useActionMenu();
72
- const action = node.props.action;
73
- const icon = node.props.icon;
74
- const label = node.props.label;
75
- const prefix = node.props.prefix;
76
- const suffix = node.props.suffix;
77
- const iconOnly = Boolean(icon);
60
+ const { icon, label, prefix, suffix } = node.props;
61
+ const behavior = useClickBehavior(node.props);
62
+ const className = isMenuItem ? actionMenuItemClassName : void 0;
63
+ const testId = nodeIdentity(node);
78
64
  const content = /* @__PURE__ */ jsx(LinkContent, {
79
65
  icon,
80
66
  isMenuItem,
@@ -82,20 +68,30 @@ var LinkComponent = ({ node }) => {
82
68
  prefix,
83
69
  suffix
84
70
  });
85
- const ariaLabel = iconOnly ? label : labelWithTextAffixes(label, prefix, suffix);
86
- if (action) return /* @__PURE__ */ jsx(ActionLink, {
87
- action,
88
- ariaLabel,
89
- className: isMenuItem ? actionMenuItemClassName : void 0,
90
- testId: nodeIdentity(node),
71
+ const ariaLabel = icon ? label : labelWithTextAffixes(label, prefix, suffix);
72
+ const triggerButton = ({ onClick, processing }) => /* @__PURE__ */ jsx("button", {
73
+ "aria-label": ariaLabel,
74
+ className: cn(textLinkClassName, className),
75
+ "data-test": testId,
76
+ disabled: processing,
77
+ onClick,
78
+ type: "button",
91
79
  children: content
92
80
  });
81
+ if (behavior.kind === "action") return /* @__PURE__ */ jsx(ActionTrigger, {
82
+ action: behavior.action,
83
+ children: triggerButton
84
+ });
85
+ if (behavior.kind === "effects") return triggerButton({
86
+ onClick: behavior.onClick,
87
+ processing: false
88
+ });
93
89
  return /* @__PURE__ */ jsx(TextLink, {
94
90
  "aria-label": ariaLabel,
95
- className: isMenuItem ? actionMenuItemClassName : void 0,
96
- "data-test": nodeIdentity(node),
97
- href: node.props.href ?? "#",
98
- method: node.props.method ?? "get",
91
+ className,
92
+ "data-test": testId,
93
+ href: behavior.kind === "navigate" ? behavior.href : "#",
94
+ method: behavior.kind === "navigate" ? behavior.method : "get",
99
95
  tabIndex: node.props.tabIndex ?? void 0,
100
96
  children: content
101
97
  });
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","names":[],"sources":["../../../resources/js/core/components/link.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { useAction } from \"@lattice-php/lattice/action/use-action\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { Node, RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport type { Affix } from \"@lattice-php/lattice/types/generated\";\nimport {\n actionMenuItemClassName,\n useActionMenu,\n} from \"@lattice-php/lattice/action/components/action-menu-context\";\n\nconst textLinkClassName =\n \"text-lt-fg underline decoration-lt-border underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-lt-border\";\n\nfunction TextLink({ className = \"\", children, ...props }: ComponentProps<typeof Link>) {\n return (\n <Link className={cn(textLinkClassName, className)} {...props}>\n {children}\n </Link>\n );\n}\n\nfunction ActionLink({\n action,\n ariaLabel,\n className,\n children,\n testId,\n}: {\n action: Node<\"action\">;\n ariaLabel?: string;\n className?: string;\n children: ReactNode;\n testId?: string;\n}) {\n const { processing, requestSubmit, overlays } = useAction(action);\n\n return (\n <>\n <button\n aria-label={ariaLabel}\n className={cn(textLinkClassName, className)}\n data-test={testId}\n disabled={processing}\n onClick={requestSubmit}\n type=\"button\"\n >\n {children}\n </button>\n {overlays}\n </>\n );\n}\n\nfunction LinkAffix({ affix, className }: { affix: Affix; className?: string }) {\n if (affix.icon) {\n return <IconRenderer className={cn(\"size-lt-icon-md shrink-0\", className)} icon={affix.icon} />;\n }\n\n return <span className={cn(\"shrink-0 text-sm text-lt-muted-fg\", className)}>{affix.text}</span>;\n}\n\nfunction LinkContent({\n icon,\n isMenuItem,\n label,\n prefix,\n suffix,\n}: {\n icon?: string | null;\n isMenuItem: boolean;\n label: string;\n prefix?: Affix | null;\n suffix?: Affix | null;\n}) {\n if (icon) {\n return <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} />;\n }\n\n if (isMenuItem) {\n return (\n <>\n {prefix ? <LinkAffix affix={prefix} /> : null}\n <span>{label}</span>\n {suffix ? <LinkAffix affix={suffix} className=\"ml-auto\" /> : null}\n </>\n );\n }\n\n if (prefix || suffix) {\n return (\n <span className=\"inline-flex items-center gap-1.5 align-baseline\">\n {prefix ? <LinkAffix affix={prefix} /> : null}\n <span>{label}</span>\n {suffix ? <LinkAffix affix={suffix} /> : null}\n </span>\n );\n }\n\n return label;\n}\n\nfunction labelWithTextAffixes(label: string, prefix?: Affix | null, suffix?: Affix | null) {\n if (!prefix?.text && !suffix?.text) {\n return undefined;\n }\n\n return [prefix?.text, label, suffix?.text]\n .filter((part): part is string => Boolean(part))\n .join(\" \");\n}\n\nconst LinkComponent: RendererComponent<\"link\"> = ({ node }) => {\n const isMenuItem = useActionMenu();\n const action = node.props.action;\n const icon = node.props.icon;\n const label = node.props.label;\n const prefix = node.props.prefix;\n const suffix = node.props.suffix;\n const iconOnly = Boolean(icon);\n const content = (\n <LinkContent\n icon={icon}\n isMenuItem={isMenuItem}\n label={label}\n prefix={prefix}\n suffix={suffix}\n />\n );\n const ariaLabel = iconOnly ? label : labelWithTextAffixes(label, prefix, suffix);\n\n if (action) {\n return (\n <ActionLink\n action={action as Node<\"action\">}\n ariaLabel={ariaLabel}\n className={isMenuItem ? actionMenuItemClassName : undefined}\n testId={nodeIdentity(node)}\n >\n {content}\n </ActionLink>\n );\n }\n\n return (\n <TextLink\n aria-label={ariaLabel}\n className={isMenuItem ? actionMenuItemClassName : undefined}\n data-test={nodeIdentity(node)}\n href={node.props.href ?? \"#\"}\n method={node.props.method ?? \"get\"}\n tabIndex={node.props.tabIndex ?? undefined}\n >\n {content}\n </TextLink>\n );\n};\n\nexport default LinkComponent;\nexport { TextLink };\n"],"mappings":";;;;;;;;AAaA,IAAM,oBACJ;AAEF,SAAS,SAAS,EAAE,YAAY,IAAI,UAAU,GAAG,SAAsC;CACrF,OACE,oBAAC,MAAD;EAAM,WAAW,GAAG,mBAAmB,SAAS;EAAG,GAAI;EACpD;CACG,CAAA;AAEV;AAEA,SAAS,WAAW,EAClB,QACA,WACA,WACA,UACA,UAOC;CACD,MAAM,EAAE,YAAY,eAAe,aAAa,UAAU,MAAM;CAEhE,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,UAAD;EACE,cAAY;EACZ,WAAW,GAAG,mBAAmB,SAAS;EAC1C,aAAW;EACX,UAAU;EACV,SAAS;EACT,MAAK;EAEJ;CACK,CAAA,GACP,QACD,EAAA,CAAA;AAEN;AAEA,SAAS,UAAU,EAAE,OAAO,aAAmD;CAC7E,IAAI,MAAM,MACR,OAAO,oBAAC,cAAD;EAAc,WAAW,GAAG,4BAA4B,SAAS;EAAG,MAAM,MAAM;CAAO,CAAA;CAGhG,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,qCAAqC,SAAS;YAAI,MAAM;CAAW,CAAA;AAChG;AAEA,SAAS,YAAY,EACnB,MACA,YACA,OACA,QACA,UAOC;CACD,IAAI,MACF,OAAO,oBAAC,cAAD;EAAc,WAAU;EAAiC;CAAO,CAAA;CAGzE,IAAI,YACF,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;EACzC,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EAClB,SAAS,oBAAC,WAAD;GAAW,OAAO;GAAQ,WAAU;EAAW,CAAA,IAAI;CAC7D,EAAA,CAAA;CAIN,IAAI,UAAU,QACZ,OACE,qBAAC,QAAD;EAAM,WAAU;YAAhB;GACG,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;GACzC,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;GAClB,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;EACrC;;CAIV,OAAO;AACT;AAEA,SAAS,qBAAqB,OAAe,QAAuB,QAAuB;CACzF,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,MAC5B;CAGF,OAAO;EAAC,QAAQ;EAAM;EAAO,QAAQ;CAAI,EACtC,QAAQ,SAAyB,QAAQ,IAAI,CAAC,EAC9C,KAAK,GAAG;AACb;AAEA,IAAM,iBAA4C,EAAE,WAAW;CAC7D,MAAM,aAAa,cAAc;CACjC,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,OAAO,KAAK,MAAM;CACxB,MAAM,QAAQ,KAAK,MAAM;CACzB,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,SAAS,KAAK,MAAM;CAC1B,MAAM,WAAW,QAAQ,IAAI;CAC7B,MAAM,UACJ,oBAAC,aAAD;EACQ;EACM;EACL;EACC;EACA;CACT,CAAA;CAEH,MAAM,YAAY,WAAW,QAAQ,qBAAqB,OAAO,QAAQ,MAAM;CAE/E,IAAI,QACF,OACE,oBAAC,YAAD;EACU;EACG;EACX,WAAW,aAAa,0BAA0B,KAAA;EAClD,QAAQ,aAAa,IAAI;YAExB;CACS,CAAA;CAIhB,OACE,oBAAC,UAAD;EACE,cAAY;EACZ,WAAW,aAAa,0BAA0B,KAAA;EAClD,aAAW,aAAa,IAAI;EAC5B,MAAM,KAAK,MAAM,QAAQ;EACzB,QAAQ,KAAK,MAAM,UAAU;EAC7B,UAAU,KAAK,MAAM,YAAY,KAAA;YAEhC;CACO,CAAA;AAEd"}
1
+ {"version":3,"file":"link.js","names":[],"sources":["../../../resources/js/core/components/link.tsx"],"sourcesContent":["import { Link } from \"@inertiajs/react\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { nodeIdentity } from \"@lattice-php/lattice/core/test-id\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport {\n ActionTrigger,\n type TriggerState,\n useClickBehavior,\n} from \"@lattice-php/lattice/core/use-click-behavior\";\nimport { IconRenderer } from \"@lattice-php/lattice/icons\";\nimport type { Affix } from \"@lattice-php/lattice/types/generated\";\nimport {\n actionMenuItemClassName,\n useActionMenu,\n} from \"@lattice-php/lattice/action/components/action-menu-context\";\n\nconst textLinkClassName =\n \"text-lt-fg underline decoration-lt-border underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-lt-border\";\n\nfunction TextLink({ className = \"\", children, ...props }: ComponentProps<typeof Link>) {\n return (\n <Link className={cn(textLinkClassName, className)} {...props}>\n {children}\n </Link>\n );\n}\n\nfunction LinkAffix({ affix, className }: { affix: Affix; className?: string }) {\n if (affix.icon) {\n return <IconRenderer className={cn(\"size-lt-icon-md shrink-0\", className)} icon={affix.icon} />;\n }\n\n return <span className={cn(\"shrink-0 text-sm text-lt-muted-fg\", className)}>{affix.text}</span>;\n}\n\nfunction LinkContent({\n icon,\n isMenuItem,\n label,\n prefix,\n suffix,\n}: {\n icon?: string | null;\n isMenuItem: boolean;\n label: string;\n prefix?: Affix | null;\n suffix?: Affix | null;\n}) {\n if (icon) {\n return <IconRenderer className=\"size-lt-icon-md shrink-0\" icon={icon} />;\n }\n\n if (isMenuItem) {\n return (\n <>\n {prefix ? <LinkAffix affix={prefix} /> : null}\n <span>{label}</span>\n {suffix ? <LinkAffix affix={suffix} className=\"ml-auto\" /> : null}\n </>\n );\n }\n\n if (prefix || suffix) {\n return (\n <span className=\"inline-flex items-center gap-1.5 align-baseline\">\n {prefix ? <LinkAffix affix={prefix} /> : null}\n <span>{label}</span>\n {suffix ? <LinkAffix affix={suffix} /> : null}\n </span>\n );\n }\n\n return label;\n}\n\nfunction labelWithTextAffixes(label: string, prefix?: Affix | null, suffix?: Affix | null) {\n if (!prefix?.text && !suffix?.text) {\n return undefined;\n }\n\n return [prefix?.text, label, suffix?.text]\n .filter((part): part is string => Boolean(part))\n .join(\" \");\n}\n\nconst LinkComponent: RendererComponent<\"link\"> = ({ node }) => {\n const isMenuItem = useActionMenu();\n const { icon, label, prefix, suffix } = node.props;\n const behavior = useClickBehavior(node.props);\n const className = isMenuItem ? actionMenuItemClassName : undefined;\n const testId = nodeIdentity(node);\n const content = (\n <LinkContent\n icon={icon}\n isMenuItem={isMenuItem}\n label={label}\n prefix={prefix}\n suffix={suffix}\n />\n );\n const ariaLabel = icon ? label : labelWithTextAffixes(label, prefix, suffix);\n\n const triggerButton = ({ onClick, processing }: TriggerState) => (\n <button\n aria-label={ariaLabel}\n className={cn(textLinkClassName, className)}\n data-test={testId}\n disabled={processing}\n onClick={onClick}\n type=\"button\"\n >\n {content}\n </button>\n );\n\n if (behavior.kind === \"action\") {\n return <ActionTrigger action={behavior.action}>{triggerButton}</ActionTrigger>;\n }\n\n if (behavior.kind === \"effects\") {\n return triggerButton({ onClick: behavior.onClick, processing: false });\n }\n\n return (\n <TextLink\n aria-label={ariaLabel}\n className={className}\n data-test={testId}\n href={behavior.kind === \"navigate\" ? behavior.href : \"#\"}\n method={behavior.kind === \"navigate\" ? behavior.method : \"get\"}\n tabIndex={node.props.tabIndex ?? undefined}\n >\n {content}\n </TextLink>\n );\n};\n\nexport default LinkComponent;\nexport { TextLink };\n"],"mappings":";;;;;;;;AAiBA,IAAM,oBACJ;AAEF,SAAS,SAAS,EAAE,YAAY,IAAI,UAAU,GAAG,SAAsC;CACrF,OACE,oBAAC,MAAD;EAAM,WAAW,GAAG,mBAAmB,SAAS;EAAG,GAAI;EACpD;CACG,CAAA;AAEV;AAEA,SAAS,UAAU,EAAE,OAAO,aAAmD;CAC7E,IAAI,MAAM,MACR,OAAO,oBAAC,cAAD;EAAc,WAAW,GAAG,4BAA4B,SAAS;EAAG,MAAM,MAAM;CAAO,CAAA;CAGhG,OAAO,oBAAC,QAAD;EAAM,WAAW,GAAG,qCAAqC,SAAS;YAAI,MAAM;CAAW,CAAA;AAChG;AAEA,SAAS,YAAY,EACnB,MACA,YACA,OACA,QACA,UAOC;CACD,IAAI,MACF,OAAO,oBAAC,cAAD;EAAc,WAAU;EAAiC;CAAO,CAAA;CAGzE,IAAI,YACF,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;EACzC,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EAClB,SAAS,oBAAC,WAAD;GAAW,OAAO;GAAQ,WAAU;EAAW,CAAA,IAAI;CAC7D,EAAA,CAAA;CAIN,IAAI,UAAU,QACZ,OACE,qBAAC,QAAD;EAAM,WAAU;YAAhB;GACG,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;GACzC,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;GAClB,SAAS,oBAAC,WAAD,EAAW,OAAO,OAAS,CAAA,IAAI;EACrC;;CAIV,OAAO;AACT;AAEA,SAAS,qBAAqB,OAAe,QAAuB,QAAuB;CACzF,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,MAC5B;CAGF,OAAO;EAAC,QAAQ;EAAM;EAAO,QAAQ;CAAI,EACtC,QAAQ,SAAyB,QAAQ,IAAI,CAAC,EAC9C,KAAK,GAAG;AACb;AAEA,IAAM,iBAA4C,EAAE,WAAW;CAC7D,MAAM,aAAa,cAAc;CACjC,MAAM,EAAE,MAAM,OAAO,QAAQ,WAAW,KAAK;CAC7C,MAAM,WAAW,iBAAiB,KAAK,KAAK;CAC5C,MAAM,YAAY,aAAa,0BAA0B,KAAA;CACzD,MAAM,SAAS,aAAa,IAAI;CAChC,MAAM,UACJ,oBAAC,aAAD;EACQ;EACM;EACL;EACC;EACA;CACT,CAAA;CAEH,MAAM,YAAY,OAAO,QAAQ,qBAAqB,OAAO,QAAQ,MAAM;CAE3E,MAAM,iBAAiB,EAAE,SAAS,iBAChC,oBAAC,UAAD;EACE,cAAY;EACZ,WAAW,GAAG,mBAAmB,SAAS;EAC1C,aAAW;EACX,UAAU;EACD;EACT,MAAK;YAEJ;CACK,CAAA;CAGV,IAAI,SAAS,SAAS,UACpB,OAAO,oBAAC,eAAD;EAAe,QAAQ,SAAS;YAAS;CAA6B,CAAA;CAG/E,IAAI,SAAS,SAAS,WACpB,OAAO,cAAc;EAAE,SAAS,SAAS;EAAS,YAAY;CAAM,CAAC;CAGvE,OACE,oBAAC,UAAD;EACE,cAAY;EACD;EACX,aAAW;EACX,MAAM,SAAS,SAAS,aAAa,SAAS,OAAO;EACrD,QAAQ,SAAS,SAAS,aAAa,SAAS,SAAS;EACzD,UAAU,KAAK,MAAM,YAAY,KAAA;YAEhC;CACO,CAAA;AAEd"}
@@ -1,58 +1,33 @@
1
1
  import { ComponentType as ReactComponentType, ReactNode } from 'react';
2
- import { Node as WireNode, NodeType, Option, PageContainer as KnownPageContainer, ListenerPayload } from '../types/generated';
3
- export type { KnownPageContainer, NodeType, WireNode };
4
- /** Loose props bag for nodes whose `type` is not a generated built-in. */
2
+ import { ComponentPropsMap, NodeType, Option, PageContainer as KnownPageContainer, WireNode, ListenerPayload } from '../types/generated';
3
+ export type { KnownPageContainer, NodeType, Option, WireNode };
5
4
  export type NodeProps = Record<string, unknown>;
6
5
  export type CommonNodeProps = {
7
6
  dataBindings?: Record<string, string> | null;
8
7
  hideWhenCollapsed?: boolean | null;
9
8
  };
10
- /** A `{ label, value }` pair used by the choice, select and segmented controls. */
11
- export type { Option };
12
9
  /**
13
- * A node whose `type` is not one of the generated built-ins. This is the escape
14
- * hatch that keeps the renderer open to components registered by consumers.
15
- */
16
- export type LooseNode<TType extends string = string> = {
17
- id?: string;
18
- key?: string;
19
- props?: NodeProps;
20
- schema?: Schema;
21
- type: TType;
22
- };
23
- /**
24
- * Augmentable map of wire `type` string → props. Consumer apps extend it via
25
- * `declare module "@lattice-php/lattice"` so their custom components gain strong
26
- * prop types; the entries are generated by `php artisan lattice:typescript`.
27
- * Built-in components resolve through the generated `WireNode` union below, so
28
- * this interface starts empty. Types listed in neither fall back to a loose bag.
10
+ * Augmentable map of wire `type` string props for consumer components. Apps
11
+ * extend it via `declare module "@lattice-php/lattice"` so their custom components
12
+ * gain strong prop types; the entries are generated by `php artisan lattice:typescript`.
13
+ * Built-in components resolve through the generated `ComponentPropsMap` below, the
14
+ * same way `ColumnProps` augments `ColumnPropsMap`. Types in neither fall back to a
15
+ * loose bag.
29
16
  */
30
17
  export interface ComponentProps {
31
18
  }
32
19
  /**
33
- * Resolves a registry `type` string to its payload: consumer augmentations
34
- * (`TAugment`) first, then generated built-ins (`TBuiltins`), then a loose
35
- * fallback. Shared by the component, column, chat-part and effect type maps so
36
- * every extensible kind resolves the same way.
20
+ * Resolves a `type` string to its payload: consumer augmentations (`TAugment`)
21
+ * win over generated built-ins (`TBuiltins`), then a loose fallback. The one
22
+ * resolver behind the component, column and effect maps.
37
23
  */
38
24
  export type ResolveProps<TAugment, TBuiltins, TType extends string, TFallback> = TType extends keyof TAugment ? TAugment[TType] : TType extends keyof TBuiltins ? TBuiltins[TType] : TFallback;
39
- type WireNodeProps = {
40
- [TNode in WireNode as TNode["type"]]: TNode extends {
41
- props: infer TProps;
42
- } ? TProps : never;
43
- };
44
- /**
45
- * Resolves a wire `type` to its props: consumer augmentations
46
- * (`ComponentProps`) first, then generated built-ins, then a loose bag.
47
- */
48
- export type PropsOf<TType extends string> = ResolveProps<ComponentProps, WireNodeProps, TType, NodeProps> & CommonNodeProps;
25
+ export type PropsOf<TType extends string> = ResolveProps<ComponentProps, ComponentPropsMap, TType, NodeProps> & CommonNodeProps;
49
26
  /**
50
- * Resolves a wire `type` string to its node shape: built-ins narrow to their
51
- * generated props, unknown types fall back to a loose props bag so custom
52
- * components still type-check. Built-in `props` is always present — the wire
53
- * serializes the full prop object, so reads need no optional chaining.
27
+ * Built-in `props` is required, not optional the wire serializes the full prop
28
+ * object, so reads need no optional chaining. Unknown types fall back to `WireNode`.
54
29
  */
55
- export type NodeOfType<TType extends string = string> = string extends TType ? LooseNode : {
30
+ export type NodeOfType<TType extends string = string> = string extends TType ? WireNode : {
56
31
  id?: string;
57
32
  key?: string;
58
33
  props: PropsOf<TType>;
@@ -60,9 +35,14 @@ export type NodeOfType<TType extends string = string> = string extends TType ? L
60
35
  type: TType;
61
36
  };
62
37
  export type Node<TType extends string = string> = NodeOfType<TType>;
63
- /** An ordered list of component nodes — the content of a page, form, or container. */
38
+ /**
39
+ * Distributes so `NodeUnionOf<"a" | "b">` is `NodeOfType<"a"> | NodeOfType<"b">`
40
+ * — a discriminated union where `node.type` narrows `node.props`. Domains build
41
+ * their node union from a generated `…NodeType` string union with this.
42
+ */
43
+ export type NodeUnionOf<TTypes extends string> = TTypes extends string ? NodeOfType<TTypes> : never;
64
44
  export type Schema = Node[];
65
- /** A server-composed layout shell: its key plus a schema containing one Outlet. */
45
+ /** Its `schema` holds exactly one Outlet node. */
66
46
  export type LayoutPayload = {
67
47
  key: string;
68
48
  schema: Schema;
@@ -0,0 +1,42 @@
1
+ import { Method } from '@inertiajs/core';
2
+ import { ReactNode } from 'react';
3
+ import { Node } from './types';
4
+ import { Effect } from '../types/generated';
5
+ export type ClickBehavior = {
6
+ kind: "navigate";
7
+ href: string;
8
+ method: Method;
9
+ } | {
10
+ kind: "action";
11
+ action: Node<"action">;
12
+ } | {
13
+ kind: "effects";
14
+ onClick: () => void;
15
+ } | {
16
+ kind: "none";
17
+ };
18
+ /**
19
+ * The shared click model for Link/Button/MenuItem: a clickable carries exactly
20
+ * one behavior — navigate to an href, run a server action, or dispatch client
21
+ * effects. This resolves it without touching the action machinery, so plain
22
+ * links/labels stay cheap; the `action` behavior renders through {@link ActionTrigger}.
23
+ */
24
+ export declare function useClickBehavior(props: {
25
+ href?: string | null;
26
+ method?: Method | null;
27
+ action?: Node | null;
28
+ effects?: Effect[] | null;
29
+ }): ClickBehavior;
30
+ export type TriggerState = {
31
+ onClick: () => void;
32
+ processing: boolean;
33
+ };
34
+ /**
35
+ * Runs a server action's gate (confirm/form) and renders its overlays, handing
36
+ * the host a click handler + processing state to render its own element with.
37
+ * Only mounted for the `action` behavior, so a plain link never runs `useAction`.
38
+ */
39
+ export declare function ActionTrigger({ action, children, }: {
40
+ action: Node<"action">;
41
+ children: (trigger: TriggerState) => ReactNode;
42
+ }): import("react").JSX.Element;