@lattice-php/lattice 0.36.1 → 0.38.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 +12 -2
  50. package/dist/ui/code-block-view.d.ts +3 -0
  51. package/dist/ui/code-block-view.js +135 -0
  52. package/dist/ui/code-block-view.js.map +1 -0
  53. package/dist/ui/code-block.d.ts +25 -0
  54. package/dist/ui/code-block.js +54 -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-fzD5e55N.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 +5 -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,15 @@ 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
+ lineNumbers: boolean;
330
+ maxHeight: number | null;
331
+ wrap: boolean;
332
+ };
333
+ export type CodeBlockLanguage = "text" | "json" | "javascript" | "shell" | "php";
325
334
  export type Collapsible = {
326
335
  collapsed: boolean;
327
336
  rememberState: boolean;
@@ -409,6 +418,7 @@ export type ComponentPropsMap = {
409
418
  "chat.box": ChatBox;
410
419
  "chat.part.text": TextPart;
411
420
  "chat.part.tool-call": ToolCallPart;
421
+ "code-block": CodeBlock;
412
422
  collapsible: Collapsible;
413
423
  dropdown: Dropdown;
414
424
  "field.builder": Builder;
@@ -841,7 +851,7 @@ export type MoneyColumn = {
841
851
  toggleable: boolean;
842
852
  width: ColumnWidth;
843
853
  };
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";
854
+ 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
855
  export type NotificationItem = {
846
856
  readonly actions: Node[];
847
857
  readonly body: Translatable | string | null;
@@ -1390,7 +1400,7 @@ export type Translatable = {
1390
1400
  payload: Record<string, string>;
1391
1401
  replacements: Record<string, string | number | boolean>;
1392
1402
  };
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";
1403
+ 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
1404
  export type UnreadCount = {
1395
1405
  readonly unreadCount: number;
1396
1406
  };
@@ -0,0 +1,3 @@
1
+ import { CodeBlockViewProps } from './code-block.js';
2
+ declare function CodeBlockView({ children, language, lineNumbers, maxHeight, wrap }: CodeBlockViewProps): import("react").JSX.Element;
3
+ export default CodeBlockView;
@@ -0,0 +1,135 @@
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, lineNumbers } 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-gutters": {
71
+ backgroundColor: "transparent",
72
+ borderRightColor: "var(--lt-border)",
73
+ color: "var(--lt-muted-fg)"
74
+ },
75
+ ".cm-lineNumbers .cm-gutterElement": { padding: "0 0.75rem" },
76
+ ".cm-line": { padding: "0" }
77
+ });
78
+ function CodeBlockView({ children, language, lineNumbers: lineNumbers$1, maxHeight, wrap }) {
79
+ const container = useRef(null);
80
+ const content = useRef(children);
81
+ const editor = useRef(null);
82
+ content.current = children;
83
+ useEffect(() => {
84
+ if (!container.current) return;
85
+ const languageCompartment = new Compartment();
86
+ const customLanguage = typeof language === "function" ? language : null;
87
+ const initialLanguage = typeof language === "function" ? [] : languages[language];
88
+ const view = new EditorView({
89
+ doc: content.current,
90
+ parent: container.current,
91
+ extensions: [
92
+ EditorState.readOnly.of(true),
93
+ EditorView.editable.of(false),
94
+ EditorView.contentAttributes.of({ role: "code" }),
95
+ languageCompartment.of(initialLanguage),
96
+ syntaxHighlighting(highlightStyle),
97
+ codeBlockTheme,
98
+ lineNumbers$1 ? lineNumbers() : [],
99
+ maxHeight === null ? [] : EditorView.theme({ "&": { maxHeight: `${maxHeight}px` } }),
100
+ wrap ? EditorView.lineWrapping : []
101
+ ]
102
+ });
103
+ editor.current = view;
104
+ let active = true;
105
+ if (customLanguage) customLanguage().then((extension) => {
106
+ if (active) view.dispatch({ effects: languageCompartment.reconfigure(extension) });
107
+ }).catch((error) => {
108
+ if (active) console.warn("[lattice] CodeBlock language failed to load.", error);
109
+ });
110
+ return () => {
111
+ active = false;
112
+ editor.current = null;
113
+ view.destroy();
114
+ };
115
+ }, [
116
+ language,
117
+ lineNumbers$1,
118
+ maxHeight,
119
+ wrap
120
+ ]);
121
+ useEffect(() => {
122
+ const view = editor.current;
123
+ if (!view || view.state.doc.toString() === children) return;
124
+ view.dispatch({ changes: {
125
+ from: 0,
126
+ to: view.state.doc.length,
127
+ insert: children
128
+ } });
129
+ }, [children]);
130
+ return /* @__PURE__ */ jsx("div", { ref: container });
131
+ }
132
+ //#endregion
133
+ export { CodeBlockView as default };
134
+
135
+ //# 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, lineNumbers as showLineNumbers } 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-gutters\": {\n backgroundColor: \"transparent\",\n borderRightColor: \"var(--lt-border)\",\n color: \"var(--lt-muted-fg)\",\n },\n \".cm-lineNumbers .cm-gutterElement\": { padding: \"0 0.75rem\" },\n \".cm-line\": { padding: \"0\" },\n});\n\nfunction CodeBlockView({ children, language, lineNumbers, maxHeight, wrap }: CodeBlockViewProps) {\n const container = useRef<HTMLDivElement>(null);\n const content = useRef(children);\n const editor = useRef<EditorView>(null);\n content.current = children;\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: content.current,\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 lineNumbers ? showLineNumbers() : [],\n maxHeight === null\n ? []\n : EditorView.theme({\n \"&\": { maxHeight: `${maxHeight}px` },\n }),\n wrap ? EditorView.lineWrapping : [],\n ],\n });\n editor.current = view;\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 editor.current = null;\n view.destroy();\n };\n }, [language, lineNumbers, maxHeight, wrap]);\n\n useEffect(() => {\n const view = editor.current;\n\n if (!view || view.state.doc.toString() === children) {\n return;\n }\n\n view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: children } });\n }, [children]);\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,eAAe;EACb,iBAAiB;EACjB,kBAAkB;EAClB,OAAO;CACT;CACA,qCAAqC,EAAE,SAAS,YAAY;CAC5D,YAAY,EAAE,SAAS,IAAI;AAC7B,CAAC;AAED,SAAS,cAAc,EAAE,UAAU,UAAU,aAAA,eAAa,WAAW,QAA4B;CAC/F,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,SAAS,OAAmB,IAAI;CACtC,QAAQ,UAAU;CAElB,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,QAAQ;GACb,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,gBAAc,YAAgB,IAAI,CAAC;IACnC,cAAc,OACV,CAAC,IACD,WAAW,MAAM,EACf,KAAK,EAAE,WAAW,GAAG,UAAU,IAAI,EACrC,CAAC;IACL,OAAO,WAAW,eAAe,CAAC;GACpC;EACF,CAAC;EACD,OAAO,UAAU;EACjB,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,OAAO,UAAU;GACjB,KAAK,QAAQ;EACf;CACF,GAAG;EAAC;EAAU;EAAa;EAAW;CAAI,CAAC;CAE3C,gBAAgB;EACd,MAAM,OAAO,OAAO;EAEpB,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAI,SAAS,MAAM,UACzC;EAGF,KAAK,SAAS,EAAE,SAAS;GAAE,MAAM;GAAG,IAAI,KAAK,MAAM,IAAI;GAAQ,QAAQ;EAAS,EAAE,CAAC;CACrF,GAAG,CAAC,QAAQ,CAAC;CAEb,OAAO,oBAAC,OAAD,EAAK,KAAK,UAAY,CAAA;AAC/B"}
@@ -0,0 +1,25 @@
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
+ lineNumbers?: boolean;
11
+ maxHeight?: number | null;
12
+ wrap?: boolean;
13
+ }
14
+ interface CodeBlockViewProps {
15
+ children: string;
16
+ language: CodeBlockLanguage | CodeBlockLanguageLoader;
17
+ lineNumbers: boolean;
18
+ maxHeight: number | null;
19
+ wrap: boolean;
20
+ }
21
+ declare function CodeBlock({ "aria-label": ariaLabel, children, className, copyable, language, lineNumbers, maxHeight, role, wrap, ...props }: CodeBlockProps): import("react").JSX.Element;
22
+ declare const CodeBlockComponent: RendererComponent<"code-block">;
23
+ export default CodeBlockComponent;
24
+ export { CodeBlock };
25
+ export type { CodeBlockLanguage, CodeBlockLanguageLoader, CodeBlockProps, CodeBlockViewProps };
@@ -0,0 +1,54 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { CopyButton } from "./copyable-text.js";
3
+ import { Fragment, 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", lineNumbers = false, maxHeight = null, role = ariaLabel ? "region" : void 0, wrap = false, ...props }) {
8
+ const fallback = /* @__PURE__ */ jsx("pre", {
9
+ className: cn("max-w-full overflow-auto p-3 font-lt-mono text-xs", wrap && "whitespace-pre-wrap wrap-anywhere"),
10
+ style: { maxHeight: maxHeight ?? void 0 },
11
+ children: lineNumbers ? /* @__PURE__ */ jsx("code", {
12
+ className: "grid grid-cols-[auto_1fr]",
13
+ children: children.split("\n").map((line, index) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
14
+ "aria-hidden": "true",
15
+ className: "mr-3 border-r border-lt-border pr-3 text-right text-lt-muted-fg select-none",
16
+ children: index + 1
17
+ }), /* @__PURE__ */ jsx("span", { children: line || "​" })] }, index))
18
+ }) : children
19
+ });
20
+ return /* @__PURE__ */ jsxs("div", {
21
+ "data-slot": "code-block",
22
+ "aria-label": ariaLabel,
23
+ role,
24
+ ...props,
25
+ className: cn("relative max-w-full overflow-hidden rounded-lt-sm bg-lt-muted text-lt-fg", className),
26
+ children: [copyable ? /* @__PURE__ */ jsx(CopyButton, {
27
+ value: children,
28
+ label: ariaLabel ?? "code",
29
+ iconOnly: true,
30
+ className: "absolute top-3 right-6 z-10 bg-lt-bg/80 hover:bg-lt-bg"
31
+ }) : null, /* @__PURE__ */ jsx(Suspense, {
32
+ fallback,
33
+ children: /* @__PURE__ */ jsx(CodeBlockView, {
34
+ language,
35
+ lineNumbers,
36
+ maxHeight,
37
+ wrap,
38
+ children
39
+ })
40
+ })]
41
+ });
42
+ }
43
+ var CodeBlockComponent = ({ node }) => /* @__PURE__ */ jsx(CodeBlock, {
44
+ copyable: node.props.copyable,
45
+ language: node.props.language,
46
+ lineNumbers: node.props.lineNumbers,
47
+ maxHeight: node.props.maxHeight,
48
+ wrap: node.props.wrap,
49
+ children: node.props.code
50
+ });
51
+ //#endregion
52
+ export { CodeBlock, CodeBlockComponent as default };
53
+
54
+ //# 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 { Fragment, 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 lineNumbers?: boolean;\n maxHeight?: number | null;\n wrap?: boolean;\n}\n\ninterface CodeBlockViewProps {\n children: string;\n language: CodeBlockLanguage | CodeBlockLanguageLoader;\n lineNumbers: boolean;\n maxHeight: number | null;\n wrap: boolean;\n}\n\nfunction CodeBlock({\n \"aria-label\": ariaLabel,\n children,\n className,\n copyable = false,\n language = \"text\",\n lineNumbers = false,\n maxHeight = null,\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-auto p-3 font-lt-mono text-xs\",\n wrap && \"whitespace-pre-wrap wrap-anywhere\",\n )}\n style={{ maxHeight: maxHeight ?? undefined }}\n >\n {lineNumbers ? (\n <code className=\"grid grid-cols-[auto_1fr]\">\n {children.split(\"\\n\").map((line, index) => (\n <Fragment key={index}>\n <span\n aria-hidden=\"true\"\n className=\"mr-3 border-r border-lt-border pr-3 text-right text-lt-muted-fg select-none\"\n >\n {index + 1}\n </span>\n <span>{line || \"\\u200b\"}</span>\n </Fragment>\n ))}\n </code>\n ) : (\n children\n )}\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-3 right-6 z-10 bg-lt-bg/80 hover:bg-lt-bg\"\n />\n ) : null}\n <Suspense fallback={fallback}>\n <CodeBlockView\n language={language}\n lineNumbers={lineNumbers}\n maxHeight={maxHeight}\n wrap={wrap}\n >\n {children}\n </CodeBlockView>\n </Suspense>\n </div>\n );\n}\n\nconst CodeBlockComponent: RendererComponent<\"code-block\"> = ({ node }) => (\n <CodeBlock\n copyable={node.props.copyable}\n language={node.props.language}\n lineNumbers={node.props.lineNumbers}\n maxHeight={node.props.maxHeight}\n wrap={node.props.wrap}\n >\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;AAsB5D,SAAS,UAAU,EACjB,cAAc,WACd,UACA,WACA,WAAW,OACX,WAAW,QACX,cAAc,OACd,YAAY,MACZ,OAAO,YAAY,WAAW,KAAA,GAC9B,OAAO,OACP,GAAG,SACc;CACjB,MAAM,WACJ,oBAAC,OAAD;EACE,WAAW,GACT,qDACA,QAAQ,mCACV;EACA,OAAO,EAAE,WAAW,aAAa,KAAA,EAAU;EAE1C,UAAA,cACC,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,SAAS,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UAC/B,qBAAC,UAAD,EAAA,UAAA,CACE,oBAAC,QAAD;IACE,eAAY;IACZ,WAAU;IAET,UAAA,QAAQ;GACL,CAAA,GACN,oBAAC,QAAD,EAAA,UAAO,QAAQ,IAAe,CAAA,CACtB,EAAA,GARK,KAQL,CACX;EACG,CAAA,IAEN;CAEC,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;IACY;IACG;IACF;IACL;IAEL;GACY,CAAA;EACP,CAAA,CACP;;AAET;AAEA,IAAM,sBAAuD,EAAE,WAC7D,oBAAC,WAAD;CACE,UAAU,KAAK,MAAM;CACrB,UAAU,KAAK,MAAM;CACrB,aAAa,KAAK,MAAM;CACxB,WAAW,KAAK,MAAM;CACtB,MAAM,KAAK,MAAM;CAEhB,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"}