@lattice-php/lattice 0.36.1 → 0.37.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 (87) hide show
  1. package/dist/form/components/base/field.d.ts +14 -4
  2. package/dist/form/components/base/field.js +33 -10
  3. package/dist/form/components/base/field.js.map +1 -1
  4. package/dist/form/components/fields/builder.js +4 -2
  5. package/dist/form/components/fields/builder.js.map +1 -1
  6. package/dist/form/components/fields/choice.js +6 -5
  7. package/dist/form/components/fields/choice.js.map +1 -1
  8. package/dist/form/components/fields/color-picker-field.js +2 -2
  9. package/dist/form/components/fields/color-picker-field.js.map +1 -1
  10. package/dist/form/components/fields/date-input.js +2 -1
  11. package/dist/form/components/fields/date-input.js.map +1 -1
  12. package/dist/form/components/fields/date-picker-field.d.ts +3 -1
  13. package/dist/form/components/fields/date-picker-field.js +2 -2
  14. package/dist/form/components/fields/date-picker-field.js.map +1 -1
  15. package/dist/form/components/fields/date-time-input.js +2 -1
  16. package/dist/form/components/fields/date-time-input.js.map +1 -1
  17. package/dist/form/components/fields/file-upload.js +4 -4
  18. package/dist/form/components/fields/file-upload.js.map +1 -1
  19. package/dist/form/components/fields/number-input.js +3 -3
  20. package/dist/form/components/fields/number-input.js.map +1 -1
  21. package/dist/form/components/fields/otp-input.js +2 -2
  22. package/dist/form/components/fields/otp-input.js.map +1 -1
  23. package/dist/form/components/fields/password-input.js +6 -6
  24. package/dist/form/components/fields/password-input.js.map +1 -1
  25. package/dist/form/components/fields/repeater.js +4 -2
  26. package/dist/form/components/fields/repeater.js.map +1 -1
  27. package/dist/form/components/fields/rich-editor-field.js +7 -5
  28. package/dist/form/components/fields/rich-editor-field.js.map +1 -1
  29. package/dist/form/components/fields/select.js +5 -5
  30. package/dist/form/components/fields/select.js.map +1 -1
  31. package/dist/form/components/fields/simple-field.d.ts +2 -1
  32. package/dist/form/components/fields/simple-field.js +2 -2
  33. package/dist/form/components/fields/simple-field.js.map +1 -1
  34. package/dist/form/components/fields/text-input.js +2 -2
  35. package/dist/form/components/fields/text-input.js.map +1 -1
  36. package/dist/form/components/fields/textarea.js +2 -2
  37. package/dist/form/components/fields/textarea.js.map +1 -1
  38. package/dist/form/components/fields/time-input.js +2 -2
  39. package/dist/form/components/fields/time-input.js.map +1 -1
  40. package/dist/form/components/fields/toggle.js +6 -6
  41. package/dist/form/components/fields/toggle.js.map +1 -1
  42. package/dist/form/index.d.ts +1 -0
  43. package/dist/form/index.js +2 -1
  44. package/dist/form/toolkit.d.ts +1 -1
  45. package/dist/table/components/column-visibility-menu.js +1 -1
  46. package/dist/table/components/filter-controls.js +1 -1
  47. package/dist/table/components/filter-value-input.js +1 -1
  48. package/dist/table/components/table-search.js +1 -1
  49. package/dist/types/generated.d.ts +10 -2
  50. package/dist/ui/code-block-view.d.ts +3 -0
  51. package/dist/ui/code-block-view.js +115 -0
  52. package/dist/ui/code-block-view.js.map +1 -0
  53. package/dist/ui/code-block.d.ts +22 -0
  54. package/dist/ui/code-block.js +43 -0
  55. package/dist/ui/code-block.js.map +1 -0
  56. package/dist/ui/copyable-text.d.ts +3 -1
  57. package/dist/ui/copyable-text.js +19 -13
  58. package/dist/ui/copyable-text.js.map +1 -1
  59. package/dist/ui/index.d.ts +3 -0
  60. package/dist/ui/index.js +3 -1
  61. package/dist/ui/plugin.js +2 -0
  62. package/dist/ui/plugin.js.map +1 -1
  63. package/dist/ui/segmented-pills.d.ts +2 -1
  64. package/dist/ui/segmented-pills.js +3 -2
  65. package/dist/ui/segmented-pills.js.map +1 -1
  66. package/dist/vite.js.map +1 -1
  67. package/dist-standalone/chunks/{chart-view-CR1X2aGE.js → chart-view-CFV7BU_D.js} +17 -17
  68. package/dist-standalone/chunks/code-block-view-D464jtHN.js +34 -0
  69. package/dist-standalone/chunks/date-picker-field-DepKtR_m.js +1 -0
  70. package/dist-standalone/chunks/dist-BtOmkEqQ.js +1 -0
  71. package/dist-standalone/chunks/jsx-runtime-0vZSBttN.js +1 -0
  72. package/dist-standalone/chunks/{jsx-runtime-CN5ucv1d.js → react-dom-DJCfT20h.js} +1 -1
  73. package/dist-standalone/chunks/rich-editor-field-BZQIPOLc.js +158 -0
  74. package/dist-standalone/chunks/{subscriptions-BV4g0s0U.js → subscriptions-4IpkpPX3.js} +1 -1
  75. package/dist-standalone/chunks/{time-picker-kbhOHEPd.js → time-picker-DUjYyeeP.js} +1 -1
  76. package/dist-standalone/chunks/use-dependent-field-DvH7mUyx.js +41 -0
  77. package/dist-standalone/chunks/use-effect-dispatcher-BMWOfaFE.js +97 -0
  78. package/dist-standalone/chunks/w3c-keyname-BOAvb0qz.js +1 -0
  79. package/dist-standalone/lattice.css +1 -1
  80. package/dist-standalone/lattice.js +4 -4
  81. package/dist-standalone/manifest.json +1 -1
  82. package/package.json +9 -1
  83. package/dist-standalone/chunks/date-picker-field-B4Xzow-A.js +0 -1
  84. package/dist-standalone/chunks/dist-ci5ng714.js +0 -1
  85. package/dist-standalone/chunks/icon-button-D3AltHNz.js +0 -41
  86. package/dist-standalone/chunks/rich-editor-field-JM3jBEV1.js +0 -158
  87. package/dist-standalone/chunks/use-effect-dispatcher-CJXFkAv1.js +0 -97
@@ -1,4 +1,5 @@
1
1
  import { FormValuesProvider } from "./hooks/values.js";
2
+ import { FormFieldFrame } from "./components/base/field.js";
2
3
  import { BuilderComponent } from "./components/fields/builder.js";
3
4
  import { CheckboxComponent } from "./components/fields/checkbox.js";
4
5
  import { ChoiceComponent } from "./components/fields/choice.js";
@@ -19,4 +20,4 @@ import { TimeInputComponent } from "./components/fields/time-input.js";
19
20
  import { ToggleComponent } from "./components/fields/toggle.js";
20
21
  import { WizardComponent, WizardStepComponent } from "./components/wizard.js";
21
22
  import { formComponents } from "./plugin.js";
22
- export { BuilderComponent, CheckboxComponent, ChoiceComponent, ColorPickerFieldComponent, DateInputComponent, DateTimeInputComponent, FileUploadComponent, FormComponent, FormValuesProvider, HiddenInputComponent, NumberInputComponent, OtpInputComponent, PasswordInputComponent, RepeaterComponent, SelectComponent, TextInputComponent, TextareaComponent, TimeInputComponent, ToggleComponent, WizardComponent, WizardStepComponent, formComponents };
23
+ export { BuilderComponent, CheckboxComponent, ChoiceComponent, ColorPickerFieldComponent, DateInputComponent, DateTimeInputComponent, FileUploadComponent, FormComponent, FormFieldFrame, FormValuesProvider, HiddenInputComponent, NumberInputComponent, OtpInputComponent, PasswordInputComponent, RepeaterComponent, SelectComponent, TextInputComponent, TextareaComponent, TimeInputComponent, ToggleComponent, WizardComponent, WizardStepComponent, formComponents };
@@ -2,7 +2,7 @@
2
2
  * Entry point for building custom form fields outside the package. Form
3
3
  * modules not re-exported here are internal and may change without notice.
4
4
  */
5
- export { FormFieldFrame } from './components/base/field.js';
5
+ export { FormFieldFrame, type FormFieldControlProps } from './components/base/field.js';
6
6
  export { useFormContext } from './hooks/context.js';
7
7
  export { FieldScopeProvider, useFieldScope } from './hooks/field-scope.js';
8
8
  export { fieldProps, walkFields } from './lib/field-props.js';
@@ -1,7 +1,7 @@
1
1
  import { useT } from "../../i18n/instance.js";
2
2
  import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover.js";
3
- import { Checkbox } from "../../ui/checkbox.js";
4
3
  import { IconButton } from "../../ui/icon-button.js";
4
+ import { Checkbox } from "../../ui/checkbox.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region resources/js/table/components/column-visibility-menu.tsx
7
7
  function ColumnVisibilityMenu({ columns, hasHidden, isVisible, onReset, onToggle, processing, visibleColumnCount }) {
@@ -8,8 +8,8 @@ import { ResolvedNodesProvider } from "../../form/hooks/resolved-nodes.js";
8
8
  import { FormValuesProvider, useFormValues, useSetFormValue } from "../../form/hooks/values.js";
9
9
  import { FieldCommitOverrideProvider } from "../../form/hooks/use-field-commit.js";
10
10
  import { TableCellProvider } from "../../form/hooks/row-layout-context.js";
11
- import { Checkbox } from "../../ui/checkbox.js";
12
11
  import { IconButton } from "../../ui/icon-button.js";
12
+ import { Checkbox } from "../../ui/checkbox.js";
13
13
  import { filterValue, isActiveFilterValue } from "../lib/filter-values.js";
14
14
  import { isTruthy } from "../../lib/is-truthy.js";
15
15
  import { useCallback, useMemo, useRef } from "react";
@@ -1,8 +1,8 @@
1
1
  import { useT } from "../../i18n/instance.js";
2
2
  import { cn } from "../../lib/utils.js";
3
3
  import { Icon } from "../../icons/sprite.js";
4
- import { Input } from "../../ui/input.js";
5
4
  import { IconButton } from "../../ui/icon-button.js";
5
+ import { Input } from "../../ui/input.js";
6
6
  import { NativeSelect } from "../../ui/native-select.js";
7
7
  import { useEffect, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -2,8 +2,8 @@ import { useT } from "../../i18n/instance.js";
2
2
  import { cn } from "../../lib/utils.js";
3
3
  import { Icon } from "../../icons/sprite.js";
4
4
  import { useDebouncedCallback } from "../../lib/use-debounced-callback.js";
5
- import { Input } from "../../ui/input.js";
6
5
  import { IconButton } from "../../ui/icon-button.js";
6
+ import { Input } from "../../ui/input.js";
7
7
  import { useEffect, useRef, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region resources/js/table/components/table-search.tsx
@@ -322,6 +322,13 @@ export type Choice = {
322
322
  export type CloseModal = {
323
323
  readonly modal: string | null;
324
324
  };
325
+ export type CodeBlock = {
326
+ code: string;
327
+ copyable: boolean;
328
+ language: CodeBlockLanguage;
329
+ wrap: boolean;
330
+ };
331
+ export type CodeBlockLanguage = "text" | "json" | "javascript" | "shell" | "php";
325
332
  export type Collapsible = {
326
333
  collapsed: boolean;
327
334
  rememberState: boolean;
@@ -409,6 +416,7 @@ export type ComponentPropsMap = {
409
416
  "chat.box": ChatBox;
410
417
  "chat.part.text": TextPart;
411
418
  "chat.part.tool-call": ToolCallPart;
419
+ "code-block": CodeBlock;
412
420
  collapsible: Collapsible;
413
421
  dropdown: Dropdown;
414
422
  "field.builder": Builder;
@@ -841,7 +849,7 @@ export type MoneyColumn = {
841
849
  toggleable: boolean;
842
850
  width: ColumnWidth;
843
851
  };
844
- export type NodeType = "action" | "action.bulk" | "action.group" | "avatar" | "badge" | "breadcrumbs" | "button" | "callouts" | "card" | "chart" | "chat.box" | "chat.part.text" | "chat.part.tool-call" | "collapsible" | "dropdown" | "field.builder" | "field.checkbox" | "field.choice" | "field.color-picker" | "field.date-input" | "field.date-time-input" | "field.file-upload" | "field.hidden-input" | "field.number-input" | "field.otp" | "field.password-input" | "field.repeater" | "field.rich-editor" | "field.select" | "field.text-input" | "field.textarea" | "field.time-input" | "field.toggle" | "floating-panel" | "form" | "fragment" | "grid" | "heading" | "icon" | "image" | "link" | "menu" | "menu-item" | "modal" | "notifications" | "outlet" | "progress" | "raw-block" | "remote.data-list" | "section" | "segmented-control" | "separator" | "sidebar" | "stack" | "tab" | "table" | "tabs" | "text" | "tooltip" | "topbar" | "wizard" | "wizard-step";
852
+ export type NodeType = "action" | "action.bulk" | "action.group" | "avatar" | "badge" | "breadcrumbs" | "button" | "callouts" | "card" | "chart" | "chat.box" | "chat.part.text" | "chat.part.tool-call" | "code-block" | "collapsible" | "dropdown" | "field.builder" | "field.checkbox" | "field.choice" | "field.color-picker" | "field.date-input" | "field.date-time-input" | "field.file-upload" | "field.hidden-input" | "field.number-input" | "field.otp" | "field.password-input" | "field.repeater" | "field.rich-editor" | "field.select" | "field.text-input" | "field.textarea" | "field.time-input" | "field.toggle" | "floating-panel" | "form" | "fragment" | "grid" | "heading" | "icon" | "image" | "link" | "menu" | "menu-item" | "modal" | "notifications" | "outlet" | "progress" | "raw-block" | "remote.data-list" | "section" | "segmented-control" | "separator" | "sidebar" | "stack" | "tab" | "table" | "tabs" | "text" | "tooltip" | "topbar" | "wizard" | "wizard-step";
845
853
  export type NotificationItem = {
846
854
  readonly actions: Node[];
847
855
  readonly body: Translatable | string | null;
@@ -1390,7 +1398,7 @@ export type Translatable = {
1390
1398
  payload: Record<string, string>;
1391
1399
  replacements: Record<string, string | number | boolean>;
1392
1400
  };
1393
- export type UiNodeType = "avatar" | "badge" | "button" | "card" | "chart" | "collapsible" | "floating-panel" | "grid" | "heading" | "icon" | "image" | "link" | "modal" | "progress" | "raw-block" | "section" | "segmented-control" | "separator" | "stack" | "tab" | "tabs" | "text" | "tooltip";
1401
+ export type UiNodeType = "avatar" | "badge" | "button" | "card" | "chart" | "code-block" | "collapsible" | "floating-panel" | "grid" | "heading" | "icon" | "image" | "link" | "modal" | "progress" | "raw-block" | "section" | "segmented-control" | "separator" | "stack" | "tab" | "tabs" | "text" | "tooltip";
1394
1402
  export type UnreadCount = {
1395
1403
  readonly unreadCount: number;
1396
1404
  };
@@ -0,0 +1,3 @@
1
+ import { CodeBlockViewProps } from './code-block.js';
2
+ declare function CodeBlockView({ children, copyable, language, wrap }: CodeBlockViewProps): import("react").JSX.Element;
3
+ export default CodeBlockView;
@@ -0,0 +1,115 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { javascript } from "@codemirror/lang-javascript";
4
+ import { json } from "@codemirror/lang-json";
5
+ import { php } from "@codemirror/lang-php";
6
+ import { HighlightStyle, StreamLanguage, syntaxHighlighting } from "@codemirror/language";
7
+ import { shell } from "@codemirror/legacy-modes/mode/shell";
8
+ import { Compartment, EditorState } from "@codemirror/state";
9
+ import { EditorView } from "@codemirror/view";
10
+ import { tags } from "@lezer/highlight";
11
+ //#region resources/js/ui/code-block-view.tsx
12
+ var languages = {
13
+ text: [],
14
+ json: json(),
15
+ javascript: javascript(),
16
+ shell: StreamLanguage.define(shell),
17
+ php: php()
18
+ };
19
+ var highlightStyle = HighlightStyle.define([
20
+ {
21
+ tag: tags.comment,
22
+ color: "var(--lt-muted-fg)",
23
+ fontStyle: "italic"
24
+ },
25
+ {
26
+ tag: [
27
+ tags.keyword,
28
+ tags.operatorKeyword,
29
+ tags.controlKeyword
30
+ ],
31
+ color: "var(--lt-primary)"
32
+ },
33
+ {
34
+ tag: [tags.string, tags.special(tags.string)],
35
+ color: "var(--lt-success)"
36
+ },
37
+ {
38
+ tag: [
39
+ tags.number,
40
+ tags.bool,
41
+ tags.null
42
+ ],
43
+ color: "var(--lt-info)"
44
+ },
45
+ {
46
+ tag: [tags.function(tags.variableName), tags.labelName],
47
+ color: "var(--lt-accent-fg)"
48
+ },
49
+ {
50
+ tag: [tags.typeName, tags.className],
51
+ color: "var(--lt-danger)"
52
+ },
53
+ {
54
+ tag: tags.meta,
55
+ color: "var(--lt-muted-fg)"
56
+ }
57
+ ]);
58
+ var codeBlockTheme = EditorView.theme({
59
+ "&": {
60
+ backgroundColor: "transparent",
61
+ color: "var(--lt-fg)",
62
+ fontSize: "0.75rem"
63
+ },
64
+ ".cm-scroller": {
65
+ fontFamily: "var(--lt-font-mono)",
66
+ lineHeight: "1.5",
67
+ overflow: "auto"
68
+ },
69
+ ".cm-content": { padding: "0.75rem" },
70
+ ".cm-line": { padding: "0" }
71
+ });
72
+ var copyableTheme = EditorView.theme({ ".cm-content": { padding: "2.75rem 0.75rem 0.75rem" } });
73
+ function CodeBlockView({ children, copyable, language, wrap }) {
74
+ const container = useRef(null);
75
+ useEffect(() => {
76
+ if (!container.current) return;
77
+ const languageCompartment = new Compartment();
78
+ const customLanguage = typeof language === "function" ? language : null;
79
+ const initialLanguage = typeof language === "function" ? [] : languages[language];
80
+ const view = new EditorView({
81
+ doc: children,
82
+ parent: container.current,
83
+ extensions: [
84
+ EditorState.readOnly.of(true),
85
+ EditorView.editable.of(false),
86
+ EditorView.contentAttributes.of({ role: "code" }),
87
+ languageCompartment.of(initialLanguage),
88
+ syntaxHighlighting(highlightStyle),
89
+ codeBlockTheme,
90
+ copyable ? copyableTheme : [],
91
+ wrap ? EditorView.lineWrapping : []
92
+ ]
93
+ });
94
+ let active = true;
95
+ if (customLanguage) customLanguage().then((extension) => {
96
+ if (active) view.dispatch({ effects: languageCompartment.reconfigure(extension) });
97
+ }).catch((error) => {
98
+ if (active) console.warn("[lattice] CodeBlock language failed to load.", error);
99
+ });
100
+ return () => {
101
+ active = false;
102
+ view.destroy();
103
+ };
104
+ }, [
105
+ children,
106
+ copyable,
107
+ language,
108
+ wrap
109
+ ]);
110
+ return /* @__PURE__ */ jsx("div", { ref: container });
111
+ }
112
+ //#endregion
113
+ export { CodeBlockView as default };
114
+
115
+ //# sourceMappingURL=code-block-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block-view.js","names":[],"sources":["../../resources/js/ui/code-block-view.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { javascript } from \"@codemirror/lang-javascript\";\nimport { json } from \"@codemirror/lang-json\";\nimport { php } from \"@codemirror/lang-php\";\nimport { HighlightStyle, StreamLanguage, syntaxHighlighting } from \"@codemirror/language\";\nimport { shell } from \"@codemirror/legacy-modes/mode/shell\";\nimport { Compartment, EditorState, type Extension } from \"@codemirror/state\";\nimport { EditorView } from \"@codemirror/view\";\nimport { tags } from \"@lezer/highlight\";\nimport type { CodeBlockLanguage, CodeBlockViewProps } from \"./code-block\";\n\nconst languages: Record<CodeBlockLanguage, Extension> = {\n text: [],\n json: json(),\n javascript: javascript(),\n shell: StreamLanguage.define(shell),\n php: php(),\n};\n\nconst highlightStyle = HighlightStyle.define([\n { tag: tags.comment, color: \"var(--lt-muted-fg)\", fontStyle: \"italic\" },\n { tag: [tags.keyword, tags.operatorKeyword, tags.controlKeyword], color: \"var(--lt-primary)\" },\n { tag: [tags.string, tags.special(tags.string)], color: \"var(--lt-success)\" },\n { tag: [tags.number, tags.bool, tags.null], color: \"var(--lt-info)\" },\n { tag: [tags.function(tags.variableName), tags.labelName], color: \"var(--lt-accent-fg)\" },\n { tag: [tags.typeName, tags.className], color: \"var(--lt-danger)\" },\n { tag: tags.meta, color: \"var(--lt-muted-fg)\" },\n]);\n\nconst codeBlockTheme = EditorView.theme({\n \"&\": {\n backgroundColor: \"transparent\",\n color: \"var(--lt-fg)\",\n fontSize: \"0.75rem\",\n },\n \".cm-scroller\": {\n fontFamily: \"var(--lt-font-mono)\",\n lineHeight: \"1.5\",\n overflow: \"auto\",\n },\n \".cm-content\": { padding: \"0.75rem\" },\n \".cm-line\": { padding: \"0\" },\n});\n\nconst copyableTheme = EditorView.theme({\n \".cm-content\": { padding: \"2.75rem 0.75rem 0.75rem\" },\n});\n\nfunction CodeBlockView({ children, copyable, language, wrap }: CodeBlockViewProps) {\n const container = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!container.current) {\n return;\n }\n\n const languageCompartment = new Compartment();\n const customLanguage = typeof language === \"function\" ? language : null;\n const initialLanguage = typeof language === \"function\" ? [] : languages[language];\n const view = new EditorView({\n doc: children,\n parent: container.current,\n extensions: [\n EditorState.readOnly.of(true),\n EditorView.editable.of(false),\n EditorView.contentAttributes.of({ role: \"code\" }),\n languageCompartment.of(initialLanguage),\n syntaxHighlighting(highlightStyle),\n codeBlockTheme,\n copyable ? copyableTheme : [],\n wrap ? EditorView.lineWrapping : [],\n ],\n });\n let active = true;\n\n if (customLanguage) {\n void customLanguage()\n .then((extension) => {\n if (active) {\n view.dispatch({ effects: languageCompartment.reconfigure(extension) });\n }\n })\n .catch((error: unknown) => {\n if (active) {\n console.warn(\"[lattice] CodeBlock language failed to load.\", error);\n }\n });\n }\n\n return () => {\n active = false;\n view.destroy();\n };\n }, [children, copyable, language, wrap]);\n\n return <div ref={container} />;\n}\n\nexport default CodeBlockView;\n"],"mappings":";;;;;;;;;;;AAWA,IAAM,YAAkD;CACtD,MAAM,CAAC;CACP,MAAM,KAAK;CACX,YAAY,WAAW;CACvB,OAAO,eAAe,OAAO,KAAK;CAClC,KAAK,IAAI;AACX;AAEA,IAAM,iBAAiB,eAAe,OAAO;CAC3C;EAAE,KAAK,KAAK;EAAS,OAAO;EAAsB,WAAW;CAAS;CACtE;EAAE,KAAK;GAAC,KAAK;GAAS,KAAK;GAAiB,KAAK;EAAc;EAAG,OAAO;CAAoB;CAC7F;EAAE,KAAK,CAAC,KAAK,QAAQ,KAAK,QAAQ,KAAK,MAAM,CAAC;EAAG,OAAO;CAAoB;CAC5E;EAAE,KAAK;GAAC,KAAK;GAAQ,KAAK;GAAM,KAAK;EAAI;EAAG,OAAO;CAAiB;CACpE;EAAE,KAAK,CAAC,KAAK,SAAS,KAAK,YAAY,GAAG,KAAK,SAAS;EAAG,OAAO;CAAsB;CACxF;EAAE,KAAK,CAAC,KAAK,UAAU,KAAK,SAAS;EAAG,OAAO;CAAmB;CAClE;EAAE,KAAK,KAAK;EAAM,OAAO;CAAqB;AAChD,CAAC;AAED,IAAM,iBAAiB,WAAW,MAAM;CACtC,KAAK;EACH,iBAAiB;EACjB,OAAO;EACP,UAAU;CACZ;CACA,gBAAgB;EACd,YAAY;EACZ,YAAY;EACZ,UAAU;CACZ;CACA,eAAe,EAAE,SAAS,UAAU;CACpC,YAAY,EAAE,SAAS,IAAI;AAC7B,CAAC;AAED,IAAM,gBAAgB,WAAW,MAAM,EACrC,eAAe,EAAE,SAAS,0BAA0B,EACtD,CAAC;AAED,SAAS,cAAc,EAAE,UAAU,UAAU,UAAU,QAA4B;CACjF,MAAM,YAAY,OAAuB,IAAI;CAE7C,gBAAgB;EACd,IAAI,CAAC,UAAU,SACb;EAGF,MAAM,sBAAsB,IAAI,YAAY;EAC5C,MAAM,iBAAiB,OAAO,aAAa,aAAa,WAAW;EACnE,MAAM,kBAAkB,OAAO,aAAa,aAAa,CAAC,IAAI,UAAU;EACxE,MAAM,OAAO,IAAI,WAAW;GAC1B,KAAK;GACL,QAAQ,UAAU;GAClB,YAAY;IACV,YAAY,SAAS,GAAG,IAAI;IAC5B,WAAW,SAAS,GAAG,KAAK;IAC5B,WAAW,kBAAkB,GAAG,EAAE,MAAM,OAAO,CAAC;IAChD,oBAAoB,GAAG,eAAe;IACtC,mBAAmB,cAAc;IACjC;IACA,WAAW,gBAAgB,CAAC;IAC5B,OAAO,WAAW,eAAe,CAAC;GACpC;EACF,CAAC;EACD,IAAI,SAAS;EAEb,IAAI,gBACF,eAAoB,CAAC,CAClB,MAAM,cAAc;GACnB,IAAI,QACF,KAAK,SAAS,EAAE,SAAS,oBAAoB,YAAY,SAAS,EAAE,CAAC;EAEzE,CAAC,CAAC,CACD,OAAO,UAAmB;GACzB,IAAI,QACF,QAAQ,KAAK,gDAAgD,KAAK;EAEtE,CAAC;EAGL,aAAa;GACX,SAAS;GACT,KAAK,QAAQ;EACf;CACF,GAAG;EAAC;EAAU;EAAU;EAAU;CAAI,CAAC;CAEvC,OAAO,oBAAC,OAAD,EAAK,KAAK,UAAY,CAAA;AAC/B"}
@@ -0,0 +1,22 @@
1
+ import { ComponentProps } from 'react';
2
+ import { Extension } from '@codemirror/state';
3
+ import { RendererComponent } from '../core/types.js';
4
+ type CodeBlockLanguage = "text" | "json" | "javascript" | "shell" | "php";
5
+ type CodeBlockLanguageLoader = () => Promise<Extension>;
6
+ interface CodeBlockProps extends Omit<ComponentProps<"div">, "children"> {
7
+ children: string;
8
+ copyable?: boolean;
9
+ language?: CodeBlockLanguage | CodeBlockLanguageLoader;
10
+ wrap?: boolean;
11
+ }
12
+ interface CodeBlockViewProps {
13
+ children: string;
14
+ copyable: boolean;
15
+ language: CodeBlockLanguage | CodeBlockLanguageLoader;
16
+ wrap: boolean;
17
+ }
18
+ declare function CodeBlock({ "aria-label": ariaLabel, children, className, copyable, language, role, wrap, ...props }: CodeBlockProps): import("react").JSX.Element;
19
+ declare const CodeBlockComponent: RendererComponent<"code-block">;
20
+ export default CodeBlockComponent;
21
+ export { CodeBlock };
22
+ export type { CodeBlockLanguage, CodeBlockLanguageLoader, CodeBlockProps, CodeBlockViewProps };
@@ -0,0 +1,43 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { CopyButton } from "./copyable-text.js";
3
+ import { Suspense, lazy } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region resources/js/ui/code-block.tsx
6
+ var CodeBlockView = lazy(() => import("./code-block-view.js"));
7
+ function CodeBlock({ "aria-label": ariaLabel, children, className, copyable = false, language = "text", role = ariaLabel ? "region" : void 0, wrap = false, ...props }) {
8
+ const fallback = /* @__PURE__ */ jsx("pre", {
9
+ className: cn("max-w-full overflow-x-auto p-3 font-lt-mono text-xs", wrap && "whitespace-pre-wrap wrap-anywhere", copyable && "pt-11"),
10
+ children
11
+ });
12
+ return /* @__PURE__ */ jsxs("div", {
13
+ "data-slot": "code-block",
14
+ "aria-label": ariaLabel,
15
+ role,
16
+ ...props,
17
+ className: cn("relative max-w-full overflow-hidden rounded-lt-sm bg-lt-muted text-lt-fg", className),
18
+ children: [copyable ? /* @__PURE__ */ jsx(CopyButton, {
19
+ value: children,
20
+ label: ariaLabel ?? "code",
21
+ iconOnly: true,
22
+ className: "absolute top-2 right-2 z-10 bg-lt-bg/80 hover:bg-lt-bg"
23
+ }) : null, /* @__PURE__ */ jsx(Suspense, {
24
+ fallback,
25
+ children: /* @__PURE__ */ jsx(CodeBlockView, {
26
+ copyable,
27
+ language,
28
+ wrap,
29
+ children
30
+ })
31
+ })]
32
+ });
33
+ }
34
+ var CodeBlockComponent = ({ node }) => /* @__PURE__ */ jsx(CodeBlock, {
35
+ copyable: node.props.copyable,
36
+ language: node.props.language,
37
+ wrap: node.props.wrap,
38
+ children: node.props.code
39
+ });
40
+ //#endregion
41
+ export { CodeBlock, CodeBlockComponent as default };
42
+
43
+ //# sourceMappingURL=code-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block.js","names":[],"sources":["../../resources/js/ui/code-block.tsx"],"sourcesContent":["import { lazy, Suspense } from \"react\";\nimport type { ComponentProps } from \"react\";\nimport type { Extension } from \"@codemirror/state\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { CopyButton } from \"./copyable-text\";\n\nconst CodeBlockView = lazy(() => import(\"./code-block-view\"));\n\ntype CodeBlockLanguage = \"text\" | \"json\" | \"javascript\" | \"shell\" | \"php\";\ntype CodeBlockLanguageLoader = () => Promise<Extension>;\n\ninterface CodeBlockProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n children: string;\n copyable?: boolean;\n language?: CodeBlockLanguage | CodeBlockLanguageLoader;\n wrap?: boolean;\n}\n\ninterface CodeBlockViewProps {\n children: string;\n copyable: boolean;\n language: CodeBlockLanguage | CodeBlockLanguageLoader;\n wrap: boolean;\n}\n\nfunction CodeBlock({\n \"aria-label\": ariaLabel,\n children,\n className,\n copyable = false,\n language = \"text\",\n role = ariaLabel ? \"region\" : undefined,\n wrap = false,\n ...props\n}: CodeBlockProps) {\n const fallback = (\n <pre\n className={cn(\n \"max-w-full overflow-x-auto p-3 font-lt-mono text-xs\",\n wrap && \"whitespace-pre-wrap wrap-anywhere\",\n copyable && \"pt-11\",\n )}\n >\n {children}\n </pre>\n );\n\n return (\n <div\n data-slot=\"code-block\"\n aria-label={ariaLabel}\n role={role}\n {...props}\n className={cn(\n \"relative max-w-full overflow-hidden rounded-lt-sm bg-lt-muted text-lt-fg\",\n className,\n )}\n >\n {copyable ? (\n <CopyButton\n value={children}\n label={ariaLabel ?? \"code\"}\n iconOnly\n className=\"absolute top-2 right-2 z-10 bg-lt-bg/80 hover:bg-lt-bg\"\n />\n ) : null}\n <Suspense fallback={fallback}>\n <CodeBlockView copyable={copyable} language={language} wrap={wrap}>\n {children}\n </CodeBlockView>\n </Suspense>\n </div>\n );\n}\n\nconst CodeBlockComponent: RendererComponent<\"code-block\"> = ({ node }) => (\n <CodeBlock copyable={node.props.copyable} language={node.props.language} wrap={node.props.wrap}>\n {node.props.code}\n </CodeBlock>\n);\n\nexport default CodeBlockComponent;\nexport { CodeBlock };\nexport type { CodeBlockLanguage, CodeBlockLanguageLoader, CodeBlockProps, CodeBlockViewProps };\n"],"mappings":";;;;;AAOA,IAAM,gBAAgB,WAAW,OAAO,uBAAoB;AAmB5D,SAAS,UAAU,EACjB,cAAc,WACd,UACA,WACA,WAAW,OACX,WAAW,QACX,OAAO,YAAY,WAAW,KAAA,GAC9B,OAAO,OACP,GAAG,SACc;CACjB,MAAM,WACJ,oBAAC,OAAD;EACE,WAAW,GACT,uDACA,QAAQ,qCACR,YAAY,OACd;EAEC;CACE,CAAA;CAGP,OACE,qBAAC,OAAD;EACE,aAAU;EACV,cAAY;EACN;EACN,GAAI;EACJ,WAAW,GACT,4EACA,SACF;EARF,UAAA,CAUG,WACC,oBAAC,YAAD;GACE,OAAO;GACP,OAAO,aAAa;GACpB,UAAA;GACA,WAAU;EACX,CAAA,IACC,MACJ,oBAAC,UAAD;GAAoB;GAClB,UAAA,oBAAC,eAAD;IAAyB;IAAoB;IAAgB;IAC1D;GACY,CAAA;EACP,CAAA,CACP;;AAET;AAEA,IAAM,sBAAuD,EAAE,WAC7D,oBAAC,WAAD;CAAW,UAAU,KAAK,MAAM;CAAU,UAAU,KAAK,MAAM;CAAU,MAAM,KAAK,MAAM;CACvF,UAAA,KAAK,MAAM;AACH,CAAA"}
@@ -5,8 +5,10 @@ interface CopyButtonProps {
5
5
  label: string;
6
6
  testId?: string;
7
7
  className?: string;
8
+ iconOnly?: boolean;
9
+ children?: ReactNode;
8
10
  }
9
- export declare function CopyButton({ value, label, testId, className }: CopyButtonProps): ReactNode;
11
+ export declare function CopyButton({ value, label, testId, className, iconOnly, children, }: CopyButtonProps): ReactNode;
10
12
  interface CopyableTextProps {
11
13
  value: string;
12
14
  label: string;
@@ -1,6 +1,6 @@
1
1
  import { useT } from "../i18n/instance.js";
2
- import { cn } from "../lib/utils.js";
3
- import { Icon } from "../icons/sprite.js";
2
+ import { Button } from "./button.js";
3
+ import { IconButton } from "./icon-button.js";
4
4
  import { useEffect, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region resources/js/ui/copyable-text.tsx
@@ -13,7 +13,7 @@ async function copyToClipboard(text) {
13
13
  return false;
14
14
  }
15
15
  }
16
- function CopyButton({ value, label, testId, className }) {
16
+ function CopyButton({ value, label, testId, className, iconOnly = false, children }) {
17
17
  const { t } = useT("lattice");
18
18
  const [copied, setCopied] = useState(false);
19
19
  useEffect(() => {
@@ -21,21 +21,27 @@ function CopyButton({ value, label, testId, className }) {
21
21
  const timeout = window.setTimeout(() => setCopied(false), 1500);
22
22
  return () => window.clearTimeout(timeout);
23
23
  }, [copied]);
24
- function handleCopy() {
25
- copyToClipboard(value);
26
- setCopied(true);
24
+ async function handleCopy() {
25
+ if (await copyToClipboard(value)) setCopied(true);
27
26
  }
28
27
  const ariaLabel = copied ? t("common.copied-value", "Copied {{label}}", { label }) : t("common.copy-value", "Copy {{label}}", { label });
29
- return /* @__PURE__ */ jsxs("button", {
28
+ if (iconOnly) return /* @__PURE__ */ jsx(IconButton, {
29
+ icon: copied ? "check" : "copy",
30
+ label: ariaLabel,
31
+ "data-test": testId,
32
+ className,
33
+ onClick: () => void handleCopy()
34
+ });
35
+ return /* @__PURE__ */ jsx(Button, {
30
36
  type: "button",
37
+ size: "sm",
38
+ emphasis: "outline",
39
+ icon: copied ? "check" : "copy",
31
40
  "data-test": testId,
32
- className: cn("inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs", className),
41
+ className,
33
42
  "aria-label": ariaLabel,
34
- onClick: handleCopy,
35
- children: [/* @__PURE__ */ jsx(Icon, {
36
- name: copied ? "check" : "copy",
37
- className: "size-lt-icon-xs"
38
- }), copied ? t("common.copied", "Copied") : t("common.copy", "Copy")]
43
+ onClick: () => void handleCopy(),
44
+ children: copied ? t("common.copied", "Copied") : children ?? t("common.copy", "Copy")
39
45
  });
40
46
  }
41
47
  function CopyableText({ value, label, testId, children }) {
@@ -1 +1 @@
1
- {"version":3,"file":"copyable-text.js","names":[],"sources":["../../resources/js/ui/copyable-text.tsx"],"sourcesContent":["import { useT } from \"@lattice-php/lattice/i18n\";\nimport { Icon } from \"@lattice-php/lattice/icons\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\ninterface CopyButtonProps {\n value: string;\n label: string;\n testId?: string;\n className?: string;\n}\n\nexport function CopyButton({ value, label, testId, className }: CopyButtonProps): ReactNode {\n const { t } = useT(\"lattice\");\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n if (!copied) {\n return;\n }\n\n const timeout = window.setTimeout(() => setCopied(false), 1500);\n\n return () => window.clearTimeout(timeout);\n }, [copied]);\n\n function handleCopy(): void {\n void copyToClipboard(value);\n setCopied(true);\n }\n\n const ariaLabel = copied\n ? t(\"common.copied-value\", \"Copied {{label}}\", { label })\n : t(\"common.copy-value\", \"Copy {{label}}\", { label });\n\n return (\n <button\n type=\"button\"\n data-test={testId}\n className={cn(\n \"inline-flex items-center gap-1 rounded-lt-sm border border-lt-border px-2 py-1 text-xs\",\n className,\n )}\n aria-label={ariaLabel}\n onClick={handleCopy}\n >\n <Icon name={copied ? \"check\" : \"copy\"} className=\"size-lt-icon-xs\" />\n {copied ? t(\"common.copied\", \"Copied\") : t(\"common.copy\", \"Copy\")}\n </button>\n );\n}\n\ninterface CopyableTextProps {\n value: string;\n label: string;\n testId?: string;\n children?: ReactNode;\n}\n\nexport function CopyableText({ value, label, testId, children }: CopyableTextProps): ReactNode {\n return (\n <div className=\"inline-flex items-center gap-2\">\n {children ?? value}\n <CopyButton value={value} label={label} testId={testId} />\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,eAAsB,gBAAgB,MAAgC;CACpE,IAAI,CAAC,WAAW,WACd,OAAO;CAGT,IAAI;EACF,MAAM,UAAU,UAAU,UAAU,IAAI;EAExC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AASA,SAAgB,WAAW,EAAE,OAAO,OAAO,QAAQ,aAAyC;CAC1F,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,UAAU,OAAO,iBAAiB,UAAU,KAAK,GAAG,IAAI;EAE9D,aAAa,OAAO,aAAa,OAAO;CAC1C,GAAG,CAAC,MAAM,CAAC;CAEX,SAAS,aAAmB;EAC1B,gBAAqB,KAAK;EAC1B,UAAU,IAAI;CAChB;CAEA,MAAM,YAAY,SACd,EAAE,uBAAuB,oBAAoB,EAAE,MAAM,CAAC,IACtD,EAAE,qBAAqB,kBAAkB,EAAE,MAAM,CAAC;CAEtD,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAW;EACX,WAAW,GACT,0FACA,SACF;EACA,cAAY;EACZ,SAAS;EARX,UAAA,CAUE,oBAAC,MAAD;GAAM,MAAM,SAAS,UAAU;GAAQ,WAAU;EAAmB,CAAA,GACnE,SAAS,EAAE,iBAAiB,QAAQ,IAAI,EAAE,eAAe,MAAM,CAC1D;;AAEZ;AASA,SAAgB,aAAa,EAAE,OAAO,OAAO,QAAQ,YAA0C;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,YAAY,OACb,oBAAC,YAAD;GAAmB;GAAc;GAAe;EAAS,CAAA,CACtD;;AAET"}
1
+ {"version":3,"file":"copyable-text.js","names":[],"sources":["../../resources/js/ui/copyable-text.tsx"],"sourcesContent":["import { useT } from \"@lattice-php/lattice/i18n\";\nimport { type ReactNode, useEffect, useState } from \"react\";\nimport { Button } from \"./button\";\nimport { IconButton } from \"./icon-button\";\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n if (!navigator?.clipboard) {\n return false;\n }\n\n try {\n await navigator.clipboard.writeText(text);\n\n return true;\n } catch {\n return false;\n }\n}\n\ninterface CopyButtonProps {\n value: string;\n label: string;\n testId?: string;\n className?: string;\n iconOnly?: boolean;\n children?: ReactNode;\n}\n\nexport function CopyButton({\n value,\n label,\n testId,\n className,\n iconOnly = false,\n children,\n}: CopyButtonProps): ReactNode {\n const { t } = useT(\"lattice\");\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n if (!copied) {\n return;\n }\n\n const timeout = window.setTimeout(() => setCopied(false), 1500);\n\n return () => window.clearTimeout(timeout);\n }, [copied]);\n\n async function handleCopy(): Promise<void> {\n if (await copyToClipboard(value)) {\n setCopied(true);\n }\n }\n\n const ariaLabel = copied\n ? t(\"common.copied-value\", \"Copied {{label}}\", { label })\n : t(\"common.copy-value\", \"Copy {{label}}\", { label });\n\n if (iconOnly) {\n return (\n <IconButton\n icon={copied ? \"check\" : \"copy\"}\n label={ariaLabel}\n data-test={testId}\n className={className}\n onClick={() => void handleCopy()}\n />\n );\n }\n\n return (\n <Button\n type=\"button\"\n size=\"sm\"\n emphasis=\"outline\"\n icon={copied ? \"check\" : \"copy\"}\n data-test={testId}\n className={className}\n aria-label={ariaLabel}\n onClick={() => void handleCopy()}\n >\n {copied ? t(\"common.copied\", \"Copied\") : (children ?? t(\"common.copy\", \"Copy\"))}\n </Button>\n );\n}\n\ninterface CopyableTextProps {\n value: string;\n label: string;\n testId?: string;\n children?: ReactNode;\n}\n\nexport function CopyableText({ value, label, testId, children }: CopyableTextProps): ReactNode {\n return (\n <div className=\"inline-flex items-center gap-2\">\n {children ?? value}\n <CopyButton value={value} label={label} testId={testId} />\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,eAAsB,gBAAgB,MAAgC;CACpE,IAAI,CAAC,WAAW,WACd,OAAO;CAGT,IAAI;EACF,MAAM,UAAU,UAAU,UAAU,IAAI;EAExC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAWA,SAAgB,WAAW,EACzB,OACA,OACA,QACA,WACA,WAAW,OACX,YAC6B;CAC7B,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,gBAAgB;EACd,IAAI,CAAC,QACH;EAGF,MAAM,UAAU,OAAO,iBAAiB,UAAU,KAAK,GAAG,IAAI;EAE9D,aAAa,OAAO,aAAa,OAAO;CAC1C,GAAG,CAAC,MAAM,CAAC;CAEX,eAAe,aAA4B;EACzC,IAAI,MAAM,gBAAgB,KAAK,GAC7B,UAAU,IAAI;CAElB;CAEA,MAAM,YAAY,SACd,EAAE,uBAAuB,oBAAoB,EAAE,MAAM,CAAC,IACtD,EAAE,qBAAqB,kBAAkB,EAAE,MAAM,CAAC;CAEtD,IAAI,UACF,OACE,oBAAC,YAAD;EACE,MAAM,SAAS,UAAU;EACzB,OAAO;EACP,aAAW;EACA;EACX,eAAe,KAAK,WAAW;CAChC,CAAA;CAIL,OACE,oBAAC,QAAD;EACE,MAAK;EACL,MAAK;EACL,UAAS;EACT,MAAM,SAAS,UAAU;EACzB,aAAW;EACA;EACX,cAAY;EACZ,eAAe,KAAK,WAAW;EAE9B,UAAA,SAAS,EAAE,iBAAiB,QAAQ,IAAK,YAAY,EAAE,eAAe,MAAM;CACvE,CAAA;AAEZ;AASA,SAAgB,aAAa,EAAE,OAAO,OAAO,QAAQ,YAA0C;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,YAAY,OACb,oBAAC,YAAD;GAAmB;GAAc;GAAe;EAAS,CAAA,CACtD;;AAET"}
@@ -5,6 +5,8 @@ export { Button, buttonVariants } from './button.js';
5
5
  export type { Emphasis, Variant } from './button.js';
6
6
  export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './card.js';
7
7
  export { Checkbox } from './checkbox.js';
8
+ export { CodeBlock } from './code-block.js';
9
+ export type { CodeBlockLanguage, CodeBlockLanguageLoader, CodeBlockProps } from './code-block.js';
8
10
  export { Combobox } from './combobox.js';
9
11
  export { ConfirmDialog } from './confirm-dialog.js';
10
12
  export { ActionTrigger, ActionTriggerProvider, useActionTrigger, useClickBehavior, } from './click-behavior.js';
@@ -18,6 +20,7 @@ export { Input } from './input.js';
18
20
  export { default as InputError } from './input-error.js';
19
21
  export { InputOTP } from './input-otp.js';
20
22
  export { Label } from './label.js';
23
+ export { NativeSelect } from './native-select.js';
21
24
  export { TextLink } from './link.js';
22
25
  export { default as PasswordInput } from './password-input.js';
23
26
  export { Popover, PopoverClose, PopoverContent, PopoverTrigger } from './popover.js';
package/dist/ui/index.js CHANGED
@@ -11,6 +11,7 @@ import { Badge } from "./badge.js";
11
11
  import { InfoTooltip } from "./info-tooltip.js";
12
12
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./card.js";
13
13
  import { CopyButton, CopyableText, copyToClipboard } from "./copyable-text.js";
14
+ import { CodeBlock } from "./code-block.js";
14
15
  import { PreviewableImage } from "./image-preview.js";
15
16
  import { TextLink } from "./link.js";
16
17
  import { SegmentedPills } from "./segmented-pills.js";
@@ -24,4 +25,5 @@ import { InputOTP } from "./input-otp.js";
24
25
  import PasswordInput from "./password-input.js";
25
26
  import { Combobox } from "./combobox.js";
26
27
  import { Textarea } from "./textarea.js";
27
- export { ActionMenuProvider, ActionTrigger, ActionTriggerProvider, AffixGroup, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Combobox, ConfirmDialog, CopyButton, CopyableText, Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, InfoTooltip, Input, InputError, InputOTP, Label, PasswordInput, Popover, PopoverClose, PopoverContent, PopoverTrigger, PreviewableImage, SegmentedPills, Skeleton, Spinner, TextLink, Textarea, actionMenuItemClassName, buttonVariants, copyToClipboard, uiComponents, useActionMenu, useActionTrigger, useClickBehavior };
28
+ import { NativeSelect } from "./native-select.js";
29
+ export { ActionMenuProvider, ActionTrigger, ActionTriggerProvider, AffixGroup, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CodeBlock, Combobox, ConfirmDialog, CopyButton, CopyableText, Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, InfoTooltip, Input, InputError, InputOTP, Label, NativeSelect, PasswordInput, Popover, PopoverClose, PopoverContent, PopoverTrigger, PreviewableImage, SegmentedPills, Skeleton, Spinner, TextLink, Textarea, actionMenuItemClassName, buttonVariants, copyToClipboard, uiComponents, useActionMenu, useActionTrigger, useClickBehavior };
package/dist/ui/plugin.js CHANGED
@@ -4,6 +4,7 @@ import AvatarComponent from "./avatar.js";
4
4
  import BadgeComponent from "./badge.js";
5
5
  import CardComponent from "./card.js";
6
6
  import ChartComponent from "./chart.js";
7
+ import CodeBlockComponent from "./code-block.js";
7
8
  import CollapsibleComponent from "./collapsible.js";
8
9
  import FloatingPanelComponent from "./floating-panel.js";
9
10
  import FragmentComponent from "./fragment.js";
@@ -30,6 +31,7 @@ var uiComponents = createPlugin({
30
31
  button: eagerComponent(ButtonComponent),
31
32
  card: eagerComponent(CardComponent),
32
33
  chart: eagerComponent(ChartComponent),
34
+ "code-block": eagerComponent(CodeBlockComponent),
33
35
  collapsible: eagerComponent(CollapsibleComponent),
34
36
  "floating-panel": eagerComponent(FloatingPanelComponent),
35
37
  fragment: eagerComponent(FragmentComponent),
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/ui/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { FragmentNodeType, UiNodeType } from \"@lattice-php/lattice/types/generated\";\nimport AvatarComponent from \"./avatar\";\nimport BadgeComponent from \"./badge\";\nimport ButtonComponent from \"./button\";\nimport CardComponent from \"./card\";\nimport ChartComponent from \"./chart\";\nimport CollapsibleComponent from \"./collapsible\";\nimport FloatingPanelComponent from \"./floating-panel\";\nimport FragmentComponent from \"./fragment\";\nimport GridComponent from \"./grid\";\nimport HeadingComponent from \"./heading\";\nimport IconComponent from \"./icon\";\nimport ImageComponent from \"./image\";\nimport LinkComponent from \"./link\";\nimport ModalComponent from \"./modal\";\nimport ProgressComponent from \"./progress\";\nimport RawBlockComponent from \"./raw-block\";\nimport SectionComponent from \"./section\";\nimport SegmentedControlComponent from \"./segmented-control\";\nimport SeparatorComponent from \"./separator\";\nimport StackComponent from \"./stack\";\nimport TabComponent, { TabsComponent } from \"./tabs\";\nimport TextComponent from \"./text\";\nimport TooltipComponent from \"./tooltip\";\n\ntype UiComponentType = UiNodeType | FragmentNodeType;\n\nexport const uiComponents = createPlugin({\n components: {\n avatar: eagerComponent(AvatarComponent),\n badge: eagerComponent(BadgeComponent),\n button: eagerComponent(ButtonComponent),\n card: eagerComponent(CardComponent),\n chart: eagerComponent(ChartComponent),\n collapsible: eagerComponent(CollapsibleComponent),\n \"floating-panel\": eagerComponent(FloatingPanelComponent),\n fragment: eagerComponent(FragmentComponent),\n grid: eagerComponent(GridComponent),\n heading: eagerComponent(HeadingComponent),\n icon: eagerComponent(IconComponent),\n image: eagerComponent(ImageComponent),\n link: eagerComponent(LinkComponent),\n modal: eagerComponent(ModalComponent),\n progress: eagerComponent(ProgressComponent),\n \"raw-block\": eagerComponent(RawBlockComponent),\n section: eagerComponent(SectionComponent),\n \"segmented-control\": eagerComponent(SegmentedControlComponent),\n separator: eagerComponent(SeparatorComponent),\n stack: eagerComponent(StackComponent),\n tab: eagerComponent(TabComponent),\n tabs: eagerComponent(TabsComponent),\n text: eagerComponent(TextComponent),\n tooltip: eagerComponent(TooltipComponent),\n } satisfies ComponentRegistryFor<UiComponentType>,\n name: \"lattice/ui\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAa,eAAe,aAAa;CACvC,YAAY;EACV,QAAQ,eAAe,eAAe;EACtC,OAAO,eAAe,cAAc;EACpC,QAAQ,eAAe,eAAe;EACtC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,aAAa,eAAe,oBAAoB;EAChD,kBAAkB,eAAe,sBAAsB;EACvD,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,SAAS,eAAe,gBAAgB;EACxC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,UAAU,eAAe,iBAAiB;EAC1C,aAAa,eAAe,iBAAiB;EAC7C,SAAS,eAAe,gBAAgB;EACxC,qBAAqB,eAAe,yBAAyB;EAC7D,WAAW,eAAe,kBAAkB;EAC5C,OAAO,eAAe,cAAc;EACpC,KAAK,eAAe,YAAY;EAChC,MAAM,eAAe,aAAa;EAClC,MAAM,eAAe,aAAa;EAClC,SAAS,eAAe,gBAAgB;CAC1C;CACA,MAAM;AACR,CAAC"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../../resources/js/ui/plugin.ts"],"sourcesContent":["import {\n createPlugin,\n eagerComponent,\n type ComponentRegistryFor,\n} from \"@lattice-php/lattice/core/registry\";\nimport type { FragmentNodeType, UiNodeType } from \"@lattice-php/lattice/types/generated\";\nimport AvatarComponent from \"./avatar\";\nimport BadgeComponent from \"./badge\";\nimport ButtonComponent from \"./button\";\nimport CardComponent from \"./card\";\nimport ChartComponent from \"./chart\";\nimport CodeBlockComponent from \"./code-block\";\nimport CollapsibleComponent from \"./collapsible\";\nimport FloatingPanelComponent from \"./floating-panel\";\nimport FragmentComponent from \"./fragment\";\nimport GridComponent from \"./grid\";\nimport HeadingComponent from \"./heading\";\nimport IconComponent from \"./icon\";\nimport ImageComponent from \"./image\";\nimport LinkComponent from \"./link\";\nimport ModalComponent from \"./modal\";\nimport ProgressComponent from \"./progress\";\nimport RawBlockComponent from \"./raw-block\";\nimport SectionComponent from \"./section\";\nimport SegmentedControlComponent from \"./segmented-control\";\nimport SeparatorComponent from \"./separator\";\nimport StackComponent from \"./stack\";\nimport TabComponent, { TabsComponent } from \"./tabs\";\nimport TextComponent from \"./text\";\nimport TooltipComponent from \"./tooltip\";\n\ntype UiComponentType = UiNodeType | FragmentNodeType;\n\nexport const uiComponents = createPlugin({\n components: {\n avatar: eagerComponent(AvatarComponent),\n badge: eagerComponent(BadgeComponent),\n button: eagerComponent(ButtonComponent),\n card: eagerComponent(CardComponent),\n chart: eagerComponent(ChartComponent),\n \"code-block\": eagerComponent(CodeBlockComponent),\n collapsible: eagerComponent(CollapsibleComponent),\n \"floating-panel\": eagerComponent(FloatingPanelComponent),\n fragment: eagerComponent(FragmentComponent),\n grid: eagerComponent(GridComponent),\n heading: eagerComponent(HeadingComponent),\n icon: eagerComponent(IconComponent),\n image: eagerComponent(ImageComponent),\n link: eagerComponent(LinkComponent),\n modal: eagerComponent(ModalComponent),\n progress: eagerComponent(ProgressComponent),\n \"raw-block\": eagerComponent(RawBlockComponent),\n section: eagerComponent(SectionComponent),\n \"segmented-control\": eagerComponent(SegmentedControlComponent),\n separator: eagerComponent(SeparatorComponent),\n stack: eagerComponent(StackComponent),\n tab: eagerComponent(TabComponent),\n tabs: eagerComponent(TabsComponent),\n text: eagerComponent(TextComponent),\n tooltip: eagerComponent(TooltipComponent),\n } satisfies ComponentRegistryFor<UiComponentType>,\n name: \"lattice/ui\",\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,IAAa,eAAe,aAAa;CACvC,YAAY;EACV,QAAQ,eAAe,eAAe;EACtC,OAAO,eAAe,cAAc;EACpC,QAAQ,eAAe,eAAe;EACtC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,cAAc,eAAe,kBAAkB;EAC/C,aAAa,eAAe,oBAAoB;EAChD,kBAAkB,eAAe,sBAAsB;EACvD,UAAU,eAAe,iBAAiB;EAC1C,MAAM,eAAe,aAAa;EAClC,SAAS,eAAe,gBAAgB;EACxC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,MAAM,eAAe,aAAa;EAClC,OAAO,eAAe,cAAc;EACpC,UAAU,eAAe,iBAAiB;EAC1C,aAAa,eAAe,iBAAiB;EAC7C,SAAS,eAAe,gBAAgB;EACxC,qBAAqB,eAAe,yBAAyB;EAC7D,WAAW,eAAe,kBAAkB;EAC5C,OAAO,eAAe,cAAc;EACpC,KAAK,eAAe,YAAY;EAChC,MAAM,eAAe,aAAa;EAClC,MAAM,eAAe,aAAa;EAClC,SAAS,eAAe,gBAAgB;CAC1C;CACA,MAAM;AACR,CAAC"}
@@ -1,9 +1,10 @@
1
+ import { ComponentProps } from 'react';
1
2
  import { Option } from '../core/types.js';
2
3
  /**
3
4
  * Presentational segmented pill group. Used by the form choice field (bound to a
4
5
  * form value) and the core segmented control (standalone, emits an event).
5
6
  */
6
- export declare function SegmentedPills({ ariaLabel, autoFocus, disabled, name, onSelect, options, tabIndex, value, }: {
7
+ export declare function SegmentedPills({ ariaLabel, autoFocus, className, disabled, name, onSelect, options, tabIndex, value, ...props }: Omit<ComponentProps<"div">, "children" | "onSelect" | "ref"> & {
7
8
  ariaLabel?: string;
8
9
  autoFocus?: boolean;
9
10
  disabled?: boolean;
@@ -7,7 +7,7 @@ import { jsx } from "react/jsx-runtime";
7
7
  * Presentational segmented pill group. Used by the form choice field (bound to a
8
8
  * form value) and the core segmented control (standalone, emits an event).
9
9
  */
10
- function SegmentedPills({ ariaLabel, autoFocus = false, disabled = false, name, onSelect, options, tabIndex, value }) {
10
+ function SegmentedPills({ ariaLabel, autoFocus = false, className, disabled = false, name, onSelect, options, tabIndex, value, ...props }) {
11
11
  const groupRef = useRef(null);
12
12
  useEffect(() => {
13
13
  if (!autoFocus) return;
@@ -15,8 +15,9 @@ function SegmentedPills({ ariaLabel, autoFocus = false, disabled = false, name,
15
15
  (group?.querySelector("button[aria-checked=\"true\"]") ?? group?.querySelector("button"))?.focus();
16
16
  }, [autoFocus]);
17
17
  return /* @__PURE__ */ jsx("div", {
18
+ ...props,
18
19
  "aria-label": ariaLabel,
19
- className: "inline-flex w-fit max-w-full gap-1 overflow-x-auto rounded-lt bg-lt-muted p-1",
20
+ className: cn("inline-flex w-fit max-w-full gap-1 overflow-x-auto rounded-lt bg-lt-muted p-1", className),
20
21
  ref: groupRef,
21
22
  role: "radiogroup",
22
23
  children: options.map((option) => {
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-pills.js","names":[],"sources":["../../resources/js/ui/segmented-pills.tsx"],"sourcesContent":["import { useEffect, useRef } from \"react\";\nimport type { Option } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { pillClassName } from \"./pill\";\n\n/**\n * Presentational segmented pill group. Used by the form choice field (bound to a\n * form value) and the core segmented control (standalone, emits an event).\n */\nexport function SegmentedPills({\n ariaLabel,\n autoFocus = false,\n disabled = false,\n name,\n onSelect,\n options,\n tabIndex,\n value,\n}: {\n ariaLabel?: string;\n autoFocus?: boolean;\n disabled?: boolean;\n name: string;\n onSelect: (value: string) => void;\n options: Option[];\n tabIndex?: number;\n value: string;\n}) {\n const groupRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!autoFocus) {\n return;\n }\n\n const group = groupRef.current;\n const target =\n group?.querySelector<HTMLButtonElement>('button[aria-checked=\"true\"]') ??\n group?.querySelector<HTMLButtonElement>(\"button\");\n\n target?.focus();\n }, [autoFocus]);\n\n return (\n <div\n aria-label={ariaLabel}\n className=\"inline-flex w-fit max-w-full gap-1 overflow-x-auto rounded-lt bg-lt-muted p-1\"\n ref={groupRef}\n role=\"radiogroup\"\n >\n {options.map((option) => {\n const isSelected = value === option.value;\n\n return (\n <button\n aria-checked={isSelected}\n data-test={`${name}-${option.value}`}\n className={cn(pillClassName(isSelected), disabled && \"cursor-not-allowed opacity-60\")}\n disabled={disabled}\n key={option.value}\n onClick={() => onSelect(option.value)}\n role=\"radio\"\n tabIndex={tabIndex}\n type=\"button\"\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,eAAe,EAC7B,WACA,YAAY,OACZ,WAAW,OACX,MACA,UACA,SACA,UACA,SAUC;CACD,MAAM,WAAW,OAAuB,IAAI;CAE5C,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,MAAM,QAAQ,SAAS;EAKvB,CAHE,OAAO,cAAiC,+BAA6B,KACrE,OAAO,cAAiC,QAAQ,EAAA,EAE1C,MAAM;CAChB,GAAG,CAAC,SAAS,CAAC;CAEd,OACE,oBAAC,OAAD;EACE,cAAY;EACZ,WAAU;EACV,KAAK;EACL,MAAK;EAEJ,UAAA,QAAQ,KAAK,WAAW;GACvB,MAAM,aAAa,UAAU,OAAO;GAEpC,OACE,oBAAC,UAAD;IACE,gBAAc;IACd,aAAW,GAAG,KAAK,GAAG,OAAO;IAC7B,WAAW,GAAG,cAAc,UAAU,GAAG,YAAY,+BAA+B;IAC1E;IAEV,eAAe,SAAS,OAAO,KAAK;IACpC,MAAK;IACK;IACV,MAAK;IAEJ,UAAA,OAAO;GACF,GAPD,OAAO,KAON;EAEZ,CAAC;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"segmented-pills.js","names":[],"sources":["../../resources/js/ui/segmented-pills.tsx"],"sourcesContent":["import { type ComponentProps, useEffect, useRef } from \"react\";\nimport type { Option } from \"@lattice-php/lattice/core/types\";\nimport { cn } from \"@lattice-php/lattice/lib/utils\";\nimport { pillClassName } from \"./pill\";\n\n/**\n * Presentational segmented pill group. Used by the form choice field (bound to a\n * form value) and the core segmented control (standalone, emits an event).\n */\nexport function SegmentedPills({\n ariaLabel,\n autoFocus = false,\n className,\n disabled = false,\n name,\n onSelect,\n options,\n tabIndex,\n value,\n ...props\n}: Omit<ComponentProps<\"div\">, \"children\" | \"onSelect\" | \"ref\"> & {\n ariaLabel?: string;\n autoFocus?: boolean;\n disabled?: boolean;\n name: string;\n onSelect: (value: string) => void;\n options: Option[];\n tabIndex?: number;\n value: string;\n}) {\n const groupRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!autoFocus) {\n return;\n }\n\n const group = groupRef.current;\n const target =\n group?.querySelector<HTMLButtonElement>('button[aria-checked=\"true\"]') ??\n group?.querySelector<HTMLButtonElement>(\"button\");\n\n target?.focus();\n }, [autoFocus]);\n\n return (\n <div\n {...props}\n aria-label={ariaLabel}\n className={cn(\n \"inline-flex w-fit max-w-full gap-1 overflow-x-auto rounded-lt bg-lt-muted p-1\",\n className,\n )}\n ref={groupRef}\n role=\"radiogroup\"\n >\n {options.map((option) => {\n const isSelected = value === option.value;\n\n return (\n <button\n aria-checked={isSelected}\n data-test={`${name}-${option.value}`}\n className={cn(pillClassName(isSelected), disabled && \"cursor-not-allowed opacity-60\")}\n disabled={disabled}\n key={option.value}\n onClick={() => onSelect(option.value)}\n role=\"radio\"\n tabIndex={tabIndex}\n type=\"button\"\n >\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,eAAe,EAC7B,WACA,YAAY,OACZ,WACA,WAAW,OACX,MACA,UACA,SACA,UACA,OACA,GAAG,SAUF;CACD,MAAM,WAAW,OAAuB,IAAI;CAE5C,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,MAAM,QAAQ,SAAS;EAKvB,CAHE,OAAO,cAAiC,+BAA6B,KACrE,OAAO,cAAiC,QAAQ,EAAA,EAE1C,MAAM;CAChB,GAAG,CAAC,SAAS,CAAC;CAEd,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,cAAY;EACZ,WAAW,GACT,iFACA,SACF;EACA,KAAK;EACL,MAAK;EAEJ,UAAA,QAAQ,KAAK,WAAW;GACvB,MAAM,aAAa,UAAU,OAAO;GAEpC,OACE,oBAAC,UAAD;IACE,gBAAc;IACd,aAAW,GAAG,KAAK,GAAG,OAAO;IAC7B,WAAW,GAAG,cAAc,UAAU,GAAG,YAAY,+BAA+B;IAC1E;IAEV,eAAe,SAAS,OAAO,KAAK;IACpC,MAAK;IACK;IACV,MAAK;IAEJ,UAAA,OAAO;GACF,GAPD,OAAO,KAON;EAEZ,CAAC;CACE,CAAA;AAET"}
package/dist/vite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","names":[],"sources":["../resources/js/vite.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { svgSprite } from \"@lattice-php/vite-svg-sprite\";\nimport type { IconTypesOptions, SvgSpriteOptions } from \"@lattice-php/vite-svg-sprite\";\nimport { searchForWorkspaceRoot } from \"vite\";\nimport type { Plugin, PluginOption, UserConfig } from \"vite\";\nimport { refreshTypeScriptTypes } from \"./vite-typescript-refresh\";\n\ntype InlineDependency = string | RegExp;\n\ntype ConfigWithTest = UserConfig & {\n test?: {\n server?: {\n deps?: {\n inline?: InlineDependency[];\n };\n };\n };\n};\n\nexport type LatticeViteIconsOptions = Omit<SvgSpriteOptions, \"dts\" | \"iconDirs\"> & {\n dirs?: string[];\n dts?: Partial<IconTypesOptions> | false;\n};\n\nexport type LatticeViteOptions = {\n appRoot?: string;\n icons?: boolean | LatticeViteIconsOptions;\n root?: string;\n source?: boolean;\n /** Refresh generated TypeScript types via the dev server. Defaults to `true`. */\n typescript?: boolean;\n};\n\ntype Roots = {\n appRoot: string;\n root: string;\n};\n\nexport function lattice(options: LatticeViteOptions = {}): PluginOption[] {\n const { appRoot } = resolveRoots(options);\n const plugins: PluginOption[] = [\n corePlugin(options),\n optionalPeersPlugin(),\n componentPackagesPlugin(discoverComponentPackages(appRoot)),\n typescriptPlugin(options),\n ];\n const iconOptions = resolveIconOptions(options);\n\n if (iconOptions) {\n plugins.push(svgSprite(iconOptions));\n }\n\n return plugins;\n}\n\n/** A Composer package that contributes a Lattice component plugin. */\nexport type LatticeComponentPackage = {\n name: string;\n /** Absolute path to the package's installed directory. */\n dir: string;\n /** Absolute path to the package's JS plugin entry (its `createPlugin(...)`). */\n plugin: string;\n};\n\ntype InstalledPackage = {\n name: string;\n \"install-path\"?: string;\n extra?: { lattice?: { plugin?: string } };\n};\n\ntype RootPackageJson = {\n name?: string;\n extra?: { lattice?: { plugin?: string } };\n};\n\n/**\n * Resolve every Composer package that declares `extra.lattice.plugin` into an\n * absolute plugin-entry path. `installPathsRelativeTo` is `vendor/composer` (the\n * dir `installed.json` records its `install-path`s against).\n */\nexport function collectComponentPackages(\n installed: { packages?: InstalledPackage[] } | InstalledPackage[],\n installPathsRelativeTo: string,\n): LatticeComponentPackage[] {\n const packages = Array.isArray(installed) ? installed : (installed.packages ?? []);\n\n return packages.flatMap((pkg) => {\n const entry = pkg.extra?.lattice?.plugin;\n\n if (typeof entry !== \"string\") {\n return [];\n }\n\n const dir = path.resolve(installPathsRelativeTo, pkg[\"install-path\"] ?? `../${pkg.name}`);\n\n return [{ name: pkg.name, dir, plugin: path.resolve(dir, entry) }];\n });\n}\n\n/**\n * Resolve the composer ROOT project's own `extra.lattice.plugin` — Composer\n * never lists the root package in `installed.json`, so a component package\n * declaring the plugin entry in its own composer.json would otherwise be\n * invisible to its own dev server (e.g. inside a testbench workbench, where\n * the package itself is the app root).\n */\nexport function collectRootComponentPackage(\n composerJson: RootPackageJson,\n appRoot: string,\n): LatticeComponentPackage[] {\n const entry = composerJson.extra?.lattice?.plugin;\n\n if (typeof entry !== \"string\" || typeof composerJson.name !== \"string\") {\n return [];\n }\n\n return [{ name: composerJson.name, dir: appRoot, plugin: path.resolve(appRoot, entry) }];\n}\n\n/**\n * Read `<appRoot>/vendor/composer/installed.json` and `<appRoot>/composer.json`\n * and collect every component package they contribute.\n */\nexport function discoverComponentPackages(appRoot: string): LatticeComponentPackage[] {\n const composerDir = path.resolve(appRoot, \"vendor/composer\");\n\n let installed: LatticeComponentPackage[] = [];\n\n try {\n const raw = readFileSync(path.join(composerDir, \"installed.json\"), \"utf8\");\n installed = collectComponentPackages(JSON.parse(raw), composerDir);\n } catch {\n installed = [];\n }\n\n let root: LatticeComponentPackage[] = [];\n\n try {\n const raw = readFileSync(path.join(appRoot, \"composer.json\"), \"utf8\");\n root = collectRootComponentPackage(JSON.parse(raw), appRoot);\n } catch {\n root = [];\n }\n\n return [...installed, ...root];\n}\n\nconst VIRTUAL_PLUGINS_ID = \"virtual:lattice/plugins\";\nconst RESOLVED_VIRTUAL_PLUGINS_ID = `\\0${VIRTUAL_PLUGINS_ID}`;\n\n/**\n * Exposes the discovered component packages as `virtual:lattice/plugins` — a\n * module whose default export is the array of their `createPlugin(...)` results,\n * ready for `extendRegistry(registry, ...plugins)`. Also grants Vite filesystem\n * access to each package dir so its source compiles from `vendor/` (or a symlink).\n */\nexport function componentPackagesPlugin(packages: LatticeComponentPackage[]): Plugin {\n return {\n name: \"lattice:component-packages\",\n config(config) {\n if (packages.length === 0) {\n return {};\n }\n\n const workspaceRoot = searchForWorkspaceRoot(config.root ?? process.cwd());\n\n return { server: { fs: { allow: [workspaceRoot, ...packages.map((pkg) => pkg.dir)] } } };\n },\n resolveId(id) {\n return id === VIRTUAL_PLUGINS_ID ? RESOLVED_VIRTUAL_PLUGINS_ID : null;\n },\n load(id) {\n if (id !== RESOLVED_VIRTUAL_PLUGINS_ID) {\n return null;\n }\n\n const imports = packages\n .map((pkg, index) => `import p${index} from ${JSON.stringify(pkg.plugin)};`)\n .join(\"\\n\");\n const list = packages.map((_, index) => `p${index}`).join(\", \");\n\n return `${imports}\\nexport default [${list}];\\n`;\n },\n };\n}\n\nexport function latticeConfig(options: LatticeViteOptions = {}): ConfigWithTest {\n const { appRoot, root } = resolveRoots(options);\n\n return {\n resolve: {\n // A react alias would break SSR: Vite only externalizes bare specifiers,\n // so an absolute path inlines react's CJS into the SSR module runner.\n // `dedupe` alone keeps the app on a single React copy, symlinks included.\n ...(options.source\n ? {\n alias: {\n \"@lattice-php/lattice/css\": path.resolve(root, \"resources/css/lattice.css\"),\n \"@lattice-php/lattice\": path.resolve(root, \"resources/js\"),\n },\n }\n : {}),\n dedupe: [\"@inertiajs/react\", \"react\", \"react-dom\"],\n },\n server: options.source\n ? {\n fs: {\n allow: [searchForWorkspaceRoot(appRoot), root],\n },\n }\n : undefined,\n test: {\n server: {\n deps: {\n inline: [\n \"@lattice-php/lattice\",\n /[/\\\\]lattice[/\\\\]dist[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]@radix-ui[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]@tiptap[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]react-i18next[/\\\\]/,\n ],\n },\n },\n },\n };\n}\n\nfunction corePlugin(options: LatticeViteOptions): Plugin {\n return {\n name: \"lattice\",\n config() {\n return latticeConfig(options);\n },\n };\n}\n\nconst OPTIONAL_PEER_STUB_PREFIX = \"\\0lattice-optional-peer/\";\n\n/**\n * Real-time listeners statically import their optional Echo peers. A consumer\n * that never uses real-time should still build, so stub a missing peer with\n * hooks that throw — the `RealtimeListeners` error boundary then degrades\n * gracefully and warns to install the peer, exactly as when it is absent.\n */\nconst OPTIONAL_PEER_STUBS: Record<string, string> = {\n \"@laravel/echo-react\": [\n \"const missing = () => {\",\n \" throw new Error(\",\n ' \"[lattice] Real-time listeners require @laravel/echo-react. Install it and call configureEcho().\",',\n \" );\",\n \"};\",\n \"export const useEcho = missing;\",\n \"export const useEchoPublic = missing;\",\n \"export const useEchoPresence = missing;\",\n \"export const useEchoNotification = missing;\",\n ].join(\"\\n\"),\n};\n\nfunction optionalPeersPlugin(): Plugin {\n return {\n name: \"lattice:optional-peers\",\n enforce: \"pre\",\n async resolveId(id) {\n if (!Object.prototype.hasOwnProperty.call(OPTIONAL_PEER_STUBS, id)) {\n return null;\n }\n\n const installed = await this.resolve(id, undefined, { skipSelf: true });\n\n return installed ? null : `${OPTIONAL_PEER_STUB_PREFIX}${id}`;\n },\n load(id) {\n if (!id.startsWith(OPTIONAL_PEER_STUB_PREFIX)) {\n return null;\n }\n\n return OPTIONAL_PEER_STUBS[id.slice(OPTIONAL_PEER_STUB_PREFIX.length)] ?? null;\n },\n };\n}\n\n/**\n * Refreshes `node.props` typings from the app's own `php artisan\n * lattice:typescript` whenever the dev server starts — installing or updating\n * a component package would otherwise leave its generated types stale until\n * someone remembers to run the command by hand. Dev-server only: a production\n * build machine may not have PHP installed, and the generated file is a dev\n * ergonomics artifact, not a build input.\n *\n * Module-private like its siblings `optionalPeersPlugin`/`corePlugin` — the\n * `refreshTypeScriptTypes` DI seam it defers to lives in\n * `./vite-typescript-refresh`, which isn't part of the published `vite`\n * subpath either (see that module for why).\n */\nfunction typescriptPlugin(options: LatticeViteOptions): Plugin {\n return {\n name: \"lattice:typescript\",\n apply: \"serve\",\n configureServer(server) {\n const typescript = options.typescript ?? true;\n\n if (typescript === false) {\n return;\n }\n\n const { appRoot } = resolveRoots(options);\n\n refreshTypeScriptTypes(appRoot, server.config.logger);\n },\n };\n}\n\nexport function resolveIconOptions(options: LatticeViteOptions): SvgSpriteOptions | null {\n const icons = options.icons ?? true;\n\n if (icons === false) {\n return null;\n }\n\n const { root } = resolveRoots(options);\n const iconOptions = icons === true ? {} : icons;\n const { dirs = [], dts, ...spriteOptions } = iconOptions;\n const defaultTypes = {\n file: \"resources/js/types/sprite-icons.ts\",\n augmentModule: \"@lattice-php/lattice\",\n augmentInterface: \"KnownIcons\",\n };\n\n return {\n ...spriteOptions,\n iconDirs: [path.resolve(root, \"resources/icons\"), ...dirs],\n ...(dts === false ? {} : { dts: { ...defaultTypes, ...dts } }),\n };\n}\n\nfunction resolveRoots(options: LatticeViteOptions): Roots {\n const appRoot = options.appRoot ?? process.cwd();\n const root = options.root ?? path.resolve(appRoot, \"vendor/lattice-php/lattice\");\n\n return { appRoot, root };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../resources/js/vite.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { svgSprite } from \"@lattice-php/vite-svg-sprite\";\nimport type { IconTypesOptions, SvgSpriteOptions } from \"@lattice-php/vite-svg-sprite\";\nimport { searchForWorkspaceRoot } from \"vite\";\nimport type { Plugin, PluginOption, UserConfig } from \"vite\";\nimport { refreshTypeScriptTypes } from \"./vite-typescript-refresh.ts\";\n\ntype InlineDependency = string | RegExp;\n\ntype ConfigWithTest = UserConfig & {\n test?: {\n server?: {\n deps?: {\n inline?: InlineDependency[];\n };\n };\n };\n};\n\nexport type LatticeViteIconsOptions = Omit<SvgSpriteOptions, \"dts\" | \"iconDirs\"> & {\n dirs?: string[];\n dts?: Partial<IconTypesOptions> | false;\n};\n\nexport type LatticeViteOptions = {\n appRoot?: string;\n icons?: boolean | LatticeViteIconsOptions;\n root?: string;\n source?: boolean;\n /** Refresh generated TypeScript types via the dev server. Defaults to `true`. */\n typescript?: boolean;\n};\n\ntype Roots = {\n appRoot: string;\n root: string;\n};\n\nexport function lattice(options: LatticeViteOptions = {}): PluginOption[] {\n const { appRoot } = resolveRoots(options);\n const plugins: PluginOption[] = [\n corePlugin(options),\n optionalPeersPlugin(),\n componentPackagesPlugin(discoverComponentPackages(appRoot)),\n typescriptPlugin(options),\n ];\n const iconOptions = resolveIconOptions(options);\n\n if (iconOptions) {\n plugins.push(svgSprite(iconOptions));\n }\n\n return plugins;\n}\n\n/** A Composer package that contributes a Lattice component plugin. */\nexport type LatticeComponentPackage = {\n name: string;\n /** Absolute path to the package's installed directory. */\n dir: string;\n /** Absolute path to the package's JS plugin entry (its `createPlugin(...)`). */\n plugin: string;\n};\n\ntype InstalledPackage = {\n name: string;\n \"install-path\"?: string;\n extra?: { lattice?: { plugin?: string } };\n};\n\ntype RootPackageJson = {\n name?: string;\n extra?: { lattice?: { plugin?: string } };\n};\n\n/**\n * Resolve every Composer package that declares `extra.lattice.plugin` into an\n * absolute plugin-entry path. `installPathsRelativeTo` is `vendor/composer` (the\n * dir `installed.json` records its `install-path`s against).\n */\nexport function collectComponentPackages(\n installed: { packages?: InstalledPackage[] } | InstalledPackage[],\n installPathsRelativeTo: string,\n): LatticeComponentPackage[] {\n const packages = Array.isArray(installed) ? installed : (installed.packages ?? []);\n\n return packages.flatMap((pkg) => {\n const entry = pkg.extra?.lattice?.plugin;\n\n if (typeof entry !== \"string\") {\n return [];\n }\n\n const dir = path.resolve(installPathsRelativeTo, pkg[\"install-path\"] ?? `../${pkg.name}`);\n\n return [{ name: pkg.name, dir, plugin: path.resolve(dir, entry) }];\n });\n}\n\n/**\n * Resolve the composer ROOT project's own `extra.lattice.plugin` — Composer\n * never lists the root package in `installed.json`, so a component package\n * declaring the plugin entry in its own composer.json would otherwise be\n * invisible to its own dev server (e.g. inside a testbench workbench, where\n * the package itself is the app root).\n */\nexport function collectRootComponentPackage(\n composerJson: RootPackageJson,\n appRoot: string,\n): LatticeComponentPackage[] {\n const entry = composerJson.extra?.lattice?.plugin;\n\n if (typeof entry !== \"string\" || typeof composerJson.name !== \"string\") {\n return [];\n }\n\n return [{ name: composerJson.name, dir: appRoot, plugin: path.resolve(appRoot, entry) }];\n}\n\n/**\n * Read `<appRoot>/vendor/composer/installed.json` and `<appRoot>/composer.json`\n * and collect every component package they contribute.\n */\nexport function discoverComponentPackages(appRoot: string): LatticeComponentPackage[] {\n const composerDir = path.resolve(appRoot, \"vendor/composer\");\n\n let installed: LatticeComponentPackage[] = [];\n\n try {\n const raw = readFileSync(path.join(composerDir, \"installed.json\"), \"utf8\");\n installed = collectComponentPackages(JSON.parse(raw), composerDir);\n } catch {\n installed = [];\n }\n\n let root: LatticeComponentPackage[] = [];\n\n try {\n const raw = readFileSync(path.join(appRoot, \"composer.json\"), \"utf8\");\n root = collectRootComponentPackage(JSON.parse(raw), appRoot);\n } catch {\n root = [];\n }\n\n return [...installed, ...root];\n}\n\nconst VIRTUAL_PLUGINS_ID = \"virtual:lattice/plugins\";\nconst RESOLVED_VIRTUAL_PLUGINS_ID = `\\0${VIRTUAL_PLUGINS_ID}`;\n\n/**\n * Exposes the discovered component packages as `virtual:lattice/plugins` — a\n * module whose default export is the array of their `createPlugin(...)` results,\n * ready for `extendRegistry(registry, ...plugins)`. Also grants Vite filesystem\n * access to each package dir so its source compiles from `vendor/` (or a symlink).\n */\nexport function componentPackagesPlugin(packages: LatticeComponentPackage[]): Plugin {\n return {\n name: \"lattice:component-packages\",\n config(config) {\n if (packages.length === 0) {\n return {};\n }\n\n const workspaceRoot = searchForWorkspaceRoot(config.root ?? process.cwd());\n\n return { server: { fs: { allow: [workspaceRoot, ...packages.map((pkg) => pkg.dir)] } } };\n },\n resolveId(id) {\n return id === VIRTUAL_PLUGINS_ID ? RESOLVED_VIRTUAL_PLUGINS_ID : null;\n },\n load(id) {\n if (id !== RESOLVED_VIRTUAL_PLUGINS_ID) {\n return null;\n }\n\n const imports = packages\n .map((pkg, index) => `import p${index} from ${JSON.stringify(pkg.plugin)};`)\n .join(\"\\n\");\n const list = packages.map((_, index) => `p${index}`).join(\", \");\n\n return `${imports}\\nexport default [${list}];\\n`;\n },\n };\n}\n\nexport function latticeConfig(options: LatticeViteOptions = {}): ConfigWithTest {\n const { appRoot, root } = resolveRoots(options);\n\n return {\n resolve: {\n // A react alias would break SSR: Vite only externalizes bare specifiers,\n // so an absolute path inlines react's CJS into the SSR module runner.\n // `dedupe` alone keeps the app on a single React copy, symlinks included.\n ...(options.source\n ? {\n alias: {\n \"@lattice-php/lattice/css\": path.resolve(root, \"resources/css/lattice.css\"),\n \"@lattice-php/lattice\": path.resolve(root, \"resources/js\"),\n },\n }\n : {}),\n dedupe: [\"@inertiajs/react\", \"react\", \"react-dom\"],\n },\n server: options.source\n ? {\n fs: {\n allow: [searchForWorkspaceRoot(appRoot), root],\n },\n }\n : undefined,\n test: {\n server: {\n deps: {\n inline: [\n \"@lattice-php/lattice\",\n /[/\\\\]lattice[/\\\\]dist[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]@radix-ui[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]@tiptap[/\\\\]/,\n /[/\\\\]lattice[/\\\\]node_modules[/\\\\]react-i18next[/\\\\]/,\n ],\n },\n },\n },\n };\n}\n\nfunction corePlugin(options: LatticeViteOptions): Plugin {\n return {\n name: \"lattice\",\n config() {\n return latticeConfig(options);\n },\n };\n}\n\nconst OPTIONAL_PEER_STUB_PREFIX = \"\\0lattice-optional-peer/\";\n\n/**\n * Real-time listeners statically import their optional Echo peers. A consumer\n * that never uses real-time should still build, so stub a missing peer with\n * hooks that throw — the `RealtimeListeners` error boundary then degrades\n * gracefully and warns to install the peer, exactly as when it is absent.\n */\nconst OPTIONAL_PEER_STUBS: Record<string, string> = {\n \"@laravel/echo-react\": [\n \"const missing = () => {\",\n \" throw new Error(\",\n ' \"[lattice] Real-time listeners require @laravel/echo-react. Install it and call configureEcho().\",',\n \" );\",\n \"};\",\n \"export const useEcho = missing;\",\n \"export const useEchoPublic = missing;\",\n \"export const useEchoPresence = missing;\",\n \"export const useEchoNotification = missing;\",\n ].join(\"\\n\"),\n};\n\nfunction optionalPeersPlugin(): Plugin {\n return {\n name: \"lattice:optional-peers\",\n enforce: \"pre\",\n async resolveId(id) {\n if (!Object.prototype.hasOwnProperty.call(OPTIONAL_PEER_STUBS, id)) {\n return null;\n }\n\n const installed = await this.resolve(id, undefined, { skipSelf: true });\n\n return installed ? null : `${OPTIONAL_PEER_STUB_PREFIX}${id}`;\n },\n load(id) {\n if (!id.startsWith(OPTIONAL_PEER_STUB_PREFIX)) {\n return null;\n }\n\n return OPTIONAL_PEER_STUBS[id.slice(OPTIONAL_PEER_STUB_PREFIX.length)] ?? null;\n },\n };\n}\n\n/**\n * Refreshes `node.props` typings from the app's own `php artisan\n * lattice:typescript` whenever the dev server starts — installing or updating\n * a component package would otherwise leave its generated types stale until\n * someone remembers to run the command by hand. Dev-server only: a production\n * build machine may not have PHP installed, and the generated file is a dev\n * ergonomics artifact, not a build input.\n *\n * Module-private like its siblings `optionalPeersPlugin`/`corePlugin` — the\n * `refreshTypeScriptTypes` DI seam it defers to lives in\n * `./vite-typescript-refresh`, which isn't part of the published `vite`\n * subpath either (see that module for why).\n */\nfunction typescriptPlugin(options: LatticeViteOptions): Plugin {\n return {\n name: \"lattice:typescript\",\n apply: \"serve\",\n configureServer(server) {\n const typescript = options.typescript ?? true;\n\n if (typescript === false) {\n return;\n }\n\n const { appRoot } = resolveRoots(options);\n\n refreshTypeScriptTypes(appRoot, server.config.logger);\n },\n };\n}\n\nexport function resolveIconOptions(options: LatticeViteOptions): SvgSpriteOptions | null {\n const icons = options.icons ?? true;\n\n if (icons === false) {\n return null;\n }\n\n const { root } = resolveRoots(options);\n const iconOptions = icons === true ? {} : icons;\n const { dirs = [], dts, ...spriteOptions } = iconOptions;\n const defaultTypes = {\n file: \"resources/js/types/sprite-icons.ts\",\n augmentModule: \"@lattice-php/lattice\",\n augmentInterface: \"KnownIcons\",\n };\n\n return {\n ...spriteOptions,\n iconDirs: [path.resolve(root, \"resources/icons\"), ...dirs],\n ...(dts === false ? {} : { dts: { ...defaultTypes, ...dts } }),\n };\n}\n\nfunction resolveRoots(options: LatticeViteOptions): Roots {\n const appRoot = options.appRoot ?? process.cwd();\n const root = options.root ?? path.resolve(appRoot, \"vendor/lattice-php/lattice\");\n\n return { appRoot, root };\n}\n"],"mappings":"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"}