@inspirer-dev/crm-dashboard 1.0.11 → 1.0.13

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.
@@ -0,0 +1,270 @@
1
+ import React, { forwardRef, useEffect, useMemo, useState } from 'react';
2
+ import {
3
+ Badge,
4
+ Box,
5
+ Button,
6
+ Field,
7
+ Flex,
8
+ IconButton,
9
+ TextInput,
10
+ Typography,
11
+ Tooltip,
12
+ } from '@strapi/design-system';
13
+ import { Plus, Trash, ArrowUp, ArrowDown } from '@strapi/icons';
14
+ import { generateId } from '../RulesBuilder/utils';
15
+
16
+ type TelegramButton = {
17
+ id: string;
18
+ text: string;
19
+ url: string;
20
+ row?: number;
21
+ };
22
+
23
+ interface ButtonsBuilderProps {
24
+ name: string;
25
+ value?: string | TelegramButton[] | null;
26
+ onChange: (event: { target: { name: string; value: string } }) => void;
27
+ intlLabel: {
28
+ id: string;
29
+ defaultMessage: string;
30
+ };
31
+ attribute?: unknown;
32
+ disabled?: boolean;
33
+ error?: string;
34
+ required?: boolean;
35
+ hint?: string;
36
+ }
37
+
38
+ const parseButtons = (value: string | TelegramButton[] | null | undefined): TelegramButton[] => {
39
+ if (!value) return [];
40
+ if (Array.isArray(value)) {
41
+ return value.map((b) => ({
42
+ id: typeof b?.id === 'string' ? b.id : generateId(),
43
+ text: typeof b?.text === 'string' ? b.text : '',
44
+ url: typeof b?.url === 'string' ? b.url : '',
45
+ row: typeof b?.row === 'number' ? b.row : 0,
46
+ }));
47
+ }
48
+ if (typeof value === 'string') {
49
+ try {
50
+ const parsed = JSON.parse(value);
51
+ if (!Array.isArray(parsed)) return [];
52
+ return parsed.map((b) => ({
53
+ id: typeof b?.id === 'string' ? b.id : generateId(),
54
+ text: typeof b?.text === 'string' ? b.text : '',
55
+ url: typeof b?.url === 'string' ? b.url : '',
56
+ row: typeof b?.row === 'number' ? b.row : 0,
57
+ }));
58
+ } catch {
59
+ return [];
60
+ }
61
+ }
62
+ return [];
63
+ };
64
+
65
+ const serializeButtons = (buttons: TelegramButton[]): string => JSON.stringify(buttons);
66
+
67
+ const isValidUrl = (url: string): boolean => {
68
+ try {
69
+ const u = new URL(url);
70
+ return u.protocol === 'http:' || u.protocol === 'https:';
71
+ } catch {
72
+ return false;
73
+ }
74
+ };
75
+
76
+ const ButtonsBuilder = forwardRef<HTMLDivElement, ButtonsBuilderProps>(
77
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
78
+ const [buttons, setButtons] = useState<TelegramButton[]>(() => parseButtons(value));
79
+
80
+ useEffect(() => {
81
+ setButtons(parseButtons(value));
82
+ }, [value]);
83
+
84
+ const update = (next: TelegramButton[]) => {
85
+ setButtons(next);
86
+ onChange({ target: { name, value: serializeButtons(next) } });
87
+ };
88
+
89
+ const addButton = () => {
90
+ update([
91
+ ...buttons,
92
+ { id: generateId(), text: 'Button', url: 'https://cases.gg', row: 0 },
93
+ ]);
94
+ };
95
+
96
+ const updateButton = (id: string, patch: Partial<TelegramButton>) => {
97
+ update(buttons.map((b) => (b.id === id ? { ...b, ...patch } : b)));
98
+ };
99
+
100
+ const deleteButton = (id: string) => {
101
+ update(buttons.filter((b) => b.id !== id));
102
+ };
103
+
104
+ const move = (from: number, to: number) => {
105
+ if (to < 0 || to >= buttons.length) return;
106
+ const copy = [...buttons];
107
+ const [item] = copy.splice(from, 1);
108
+ copy.splice(to, 0, item);
109
+ update(copy);
110
+ };
111
+
112
+ const previewRows = useMemo(() => {
113
+ const rows = new Map<number, TelegramButton[]>();
114
+ for (const b of buttons) {
115
+ const row = b.row ?? 0;
116
+ rows.set(row, [...(rows.get(row) || []), b]);
117
+ }
118
+ return Array.from(rows.entries())
119
+ .sort((a, b) => a[0] - b[0])
120
+ .map(([row, items]) => ({ row, items }));
121
+ }, [buttons]);
122
+
123
+ return (
124
+ <Field.Root name={name} error={error} required={required} hint={hint} ref={ref}>
125
+ <Flex direction="column" gap={3}>
126
+ <Field.Label>{intlLabel?.defaultMessage || 'Buttons'}</Field.Label>
127
+ <Typography variant="pi" textColor="neutral600">
128
+ Build Telegram inline keyboard buttons (text + URL). Stored as JSON.
129
+ </Typography>
130
+
131
+ <Flex direction="column" gap={2}>
132
+ {buttons.map((btn, idx) => {
133
+ const urlOk = btn.url.length === 0 ? true : isValidUrl(btn.url);
134
+ return (
135
+ <Flex
136
+ key={btn.id}
137
+ gap={2}
138
+ alignItems="flex-start"
139
+ padding={3}
140
+ background="neutral0"
141
+ hasRadius
142
+ style={{ border: '1px solid #dcdce4' }}
143
+ >
144
+ <Box style={{ flex: 2, minWidth: 180 }}>
145
+ <Field.Root name={`${name}.${btn.id}.text`}>
146
+ <Field.Label>Text</Field.Label>
147
+ <TextInput
148
+ value={btn.text}
149
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
150
+ updateButton(btn.id, { text: e.target.value })
151
+ }
152
+ disabled={disabled}
153
+ />
154
+ </Field.Root>
155
+ </Box>
156
+
157
+ <Box style={{ flex: 3, minWidth: 220 }}>
158
+ <Field.Root name={`${name}.${btn.id}.url`}>
159
+ <Field.Label>URL</Field.Label>
160
+ <TextInput
161
+ value={btn.url}
162
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
163
+ updateButton(btn.id, { url: e.target.value })
164
+ }
165
+ disabled={disabled}
166
+ />
167
+ {!urlOk && (
168
+ <Typography variant="pi" textColor="danger600" style={{ marginTop: 4 }}>
169
+ Please enter a valid http/https URL
170
+ </Typography>
171
+ )}
172
+ </Field.Root>
173
+ </Box>
174
+
175
+ <Box style={{ width: 90 }}>
176
+ <Field.Root name={`${name}.${btn.id}.row`}>
177
+ <Field.Label>Row</Field.Label>
178
+ <TextInput
179
+ type="number"
180
+ value={String(btn.row ?? 0)}
181
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
182
+ updateButton(btn.id, { row: parseInt(e.target.value, 10) || 0 })
183
+ }
184
+ disabled={disabled}
185
+ />
186
+ </Field.Root>
187
+ </Box>
188
+
189
+ <Flex direction="column" gap={1} paddingTop={6}>
190
+ <Tooltip label="Move up">
191
+ <IconButton
192
+ onClick={() => move(idx, idx - 1)}
193
+ label="Move up"
194
+ variant="ghost"
195
+ disabled={disabled || idx === 0}
196
+ >
197
+ <ArrowUp />
198
+ </IconButton>
199
+ </Tooltip>
200
+ <Tooltip label="Move down">
201
+ <IconButton
202
+ onClick={() => move(idx, idx + 1)}
203
+ label="Move down"
204
+ variant="ghost"
205
+ disabled={disabled || idx === buttons.length - 1}
206
+ >
207
+ <ArrowDown />
208
+ </IconButton>
209
+ </Tooltip>
210
+ <Tooltip label="Delete button">
211
+ <IconButton
212
+ onClick={() => deleteButton(btn.id)}
213
+ label="Delete button"
214
+ variant="ghost"
215
+ disabled={disabled}
216
+ >
217
+ <Trash />
218
+ </IconButton>
219
+ </Tooltip>
220
+ </Flex>
221
+ </Flex>
222
+ );
223
+ })}
224
+
225
+ {buttons.length === 0 && (
226
+ <Box padding={4} background="neutral0" hasRadius style={{ border: '1px dashed #dcdce4' }}>
227
+ <Typography variant="omega" textColor="neutral600">
228
+ No buttons. Add one to create an inline keyboard.
229
+ </Typography>
230
+ </Box>
231
+ )}
232
+ </Flex>
233
+
234
+ <Flex gap={2}>
235
+ <Button startIcon={<Plus />} onClick={addButton} disabled={disabled} variant="secondary">
236
+ Add button
237
+ </Button>
238
+ </Flex>
239
+
240
+ {buttons.length > 0 && (
241
+ <Box paddingTop={2}>
242
+ <Typography variant="pi" textColor="neutral600" style={{ marginBottom: 8, display: 'block' }}>
243
+ Preview
244
+ </Typography>
245
+ <Flex direction="column" gap={2}>
246
+ {previewRows.map((row) => (
247
+ <Flex key={row.row} gap={1} wrap="wrap">
248
+ {row.items.map((b) => (
249
+ <Badge key={b.id} backgroundColor="primary100">
250
+ {b.text || '(empty)'}
251
+ </Badge>
252
+ ))}
253
+ </Flex>
254
+ ))}
255
+ </Flex>
256
+ </Box>
257
+ )}
258
+
259
+ {error && <Field.Error>{error}</Field.Error>}
260
+ {hint && <Field.Hint>{hint}</Field.Hint>}
261
+ </Flex>
262
+ </Field.Root>
263
+ );
264
+ }
265
+ );
266
+
267
+ ButtonsBuilder.displayName = 'ButtonsBuilder';
268
+
269
+ export default ButtonsBuilder;
270
+
@@ -34,7 +34,7 @@ interface CancelConfig {
34
34
 
35
35
  interface CancelConditionsFieldProps {
36
36
  name: string;
37
- value?: string | null;
37
+ value?: string | CancelConfig | null;
38
38
  onChange: (event: { target: { name: string; value: string } }) => void;
39
39
  intlLabel: {
40
40
  id: string;
@@ -54,17 +54,35 @@ const DEFAULT_CONFIG: CancelConfig = {
54
54
  rules: [],
55
55
  };
56
56
 
57
- const parseConfig = (value: string | null | undefined): CancelConfig => {
57
+ const parseConfig = (value: string | CancelConfig | null | undefined): CancelConfig => {
58
58
  if (!value) return DEFAULT_CONFIG;
59
- try {
60
- const parsed = JSON.parse(value);
61
- if (parsed.logic && Array.isArray(parsed.rules)) {
62
- return parsed;
59
+ if (typeof value === 'string') {
60
+ try {
61
+ const parsed = JSON.parse(value);
62
+ if (parsed.logic && Array.isArray(parsed.rules)) {
63
+ return {
64
+ ...parsed,
65
+ rules: parsed.rules.map((rule: CancelRule) => ({
66
+ ...rule,
67
+ id: rule.id || generateId(),
68
+ })),
69
+ };
70
+ }
71
+ return DEFAULT_CONFIG;
72
+ } catch {
73
+ return DEFAULT_CONFIG;
63
74
  }
64
- return DEFAULT_CONFIG;
65
- } catch {
66
- return DEFAULT_CONFIG;
67
75
  }
76
+ if (value.logic && Array.isArray(value.rules)) {
77
+ return {
78
+ ...value,
79
+ rules: value.rules.map((rule) => ({
80
+ ...rule,
81
+ id: rule.id || generateId(),
82
+ })),
83
+ };
84
+ }
85
+ return DEFAULT_CONFIG;
68
86
  };
69
87
 
70
88
  const serializeConfig = (config: CancelConfig): string => {
@@ -1,4 +1,4 @@
1
- import React, { forwardRef, useCallback, useMemo, useState } from 'react';
1
+ import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import {
3
3
  Box,
4
4
  Button,
@@ -448,6 +448,10 @@ const RulesBuilder = forwardRef<HTMLDivElement, RulesBuilderProps>(
448
448
  ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
449
449
  const [config, setConfig] = useState<RulesConfig>(() => deserializeConfig(value));
450
450
 
451
+ useEffect(() => {
452
+ setConfig(deserializeConfig(value));
453
+ }, [value]);
454
+
451
455
  const displayLabel = useMemo(() => {
452
456
  if (intlLabel?.defaultMessage && !intlLabel.defaultMessage.includes('.')) {
453
457
  return intlLabel.defaultMessage;
@@ -1,4 +1,4 @@
1
- import { Message, Clock, Cross } from '@strapi/icons';
1
+ import { Message, Clock, Cross, Link } from '@strapi/icons';
2
2
 
3
3
  const PLUGIN_ID = 'crm-dashboard';
4
4
 
@@ -79,6 +79,31 @@ export default {
79
79
  },
80
80
  });
81
81
 
82
+ app.customFields.register({
83
+ name: 'telegram-buttons',
84
+ pluginId: PLUGIN_ID,
85
+ type: 'json',
86
+ intlLabel: {
87
+ id: `${PLUGIN_ID}.telegram-buttons.label`,
88
+ defaultMessage: 'Buttons',
89
+ },
90
+ intlDescription: {
91
+ id: `${PLUGIN_ID}.telegram-buttons.description`,
92
+ defaultMessage: 'Build Telegram inline buttons (text + URL)',
93
+ },
94
+ icon: Link,
95
+ components: {
96
+ Input: async () =>
97
+ import(
98
+ /* webpackChunkName: "crm-telegram-buttons" */ './components/ButtonsBuilder/index'
99
+ ),
100
+ },
101
+ options: {
102
+ base: [],
103
+ advanced: [],
104
+ },
105
+ });
106
+
82
107
  app.addMenuLink({
83
108
  to: `/plugins/${PLUGIN_ID}`,
84
109
  icon: Message,
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const React = require("react");
5
+ const designSystem = require("@strapi/design-system");
6
+ const icons = require("@strapi/icons");
7
+ const utils = require("./utils-CmonL0io.js");
8
+ const parseButtons = (value) => {
9
+ if (!value) return [];
10
+ if (Array.isArray(value)) {
11
+ return value.map((b) => ({
12
+ id: typeof b?.id === "string" ? b.id : utils.generateId(),
13
+ text: typeof b?.text === "string" ? b.text : "",
14
+ url: typeof b?.url === "string" ? b.url : "",
15
+ row: typeof b?.row === "number" ? b.row : 0
16
+ }));
17
+ }
18
+ if (typeof value === "string") {
19
+ try {
20
+ const parsed = JSON.parse(value);
21
+ if (!Array.isArray(parsed)) return [];
22
+ return parsed.map((b) => ({
23
+ id: typeof b?.id === "string" ? b.id : utils.generateId(),
24
+ text: typeof b?.text === "string" ? b.text : "",
25
+ url: typeof b?.url === "string" ? b.url : "",
26
+ row: typeof b?.row === "number" ? b.row : 0
27
+ }));
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+ return [];
33
+ };
34
+ const serializeButtons = (buttons) => JSON.stringify(buttons);
35
+ const isValidUrl = (url) => {
36
+ try {
37
+ const u = new URL(url);
38
+ return u.protocol === "http:" || u.protocol === "https:";
39
+ } catch {
40
+ return false;
41
+ }
42
+ };
43
+ const ButtonsBuilder = React.forwardRef(
44
+ ({ name, value, onChange, intlLabel, disabled, error, required, hint }, ref) => {
45
+ const [buttons, setButtons] = React.useState(() => parseButtons(value));
46
+ React.useEffect(() => {
47
+ setButtons(parseButtons(value));
48
+ }, [value]);
49
+ const update = (next) => {
50
+ setButtons(next);
51
+ onChange({ target: { name, value: serializeButtons(next) } });
52
+ };
53
+ const addButton = () => {
54
+ update([
55
+ ...buttons,
56
+ { id: utils.generateId(), text: "Button", url: "https://cases.gg", row: 0 }
57
+ ]);
58
+ };
59
+ const updateButton = (id, patch) => {
60
+ update(buttons.map((b) => b.id === id ? { ...b, ...patch } : b));
61
+ };
62
+ const deleteButton = (id) => {
63
+ update(buttons.filter((b) => b.id !== id));
64
+ };
65
+ const move = (from, to) => {
66
+ if (to < 0 || to >= buttons.length) return;
67
+ const copy = [...buttons];
68
+ const [item] = copy.splice(from, 1);
69
+ copy.splice(to, 0, item);
70
+ update(copy);
71
+ };
72
+ const previewRows = React.useMemo(() => {
73
+ const rows = /* @__PURE__ */ new Map();
74
+ for (const b of buttons) {
75
+ const row = b.row ?? 0;
76
+ rows.set(row, [...rows.get(row) || [], b]);
77
+ }
78
+ return Array.from(rows.entries()).sort((a, b) => a[0] - b[0]).map(([row, items]) => ({ row, items }));
79
+ }, [buttons]);
80
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Root, { name, error, required, hint, ref, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
81
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: intlLabel?.defaultMessage || "Buttons" }),
82
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Build Telegram inline keyboard buttons (text + URL). Stored as JSON." }),
83
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
84
+ buttons.map((btn, idx) => {
85
+ const urlOk = btn.url.length === 0 ? true : isValidUrl(btn.url);
86
+ return /* @__PURE__ */ jsxRuntime.jsxs(
87
+ designSystem.Flex,
88
+ {
89
+ gap: 2,
90
+ alignItems: "flex-start",
91
+ padding: 3,
92
+ background: "neutral0",
93
+ hasRadius: true,
94
+ style: { border: "1px solid #dcdce4" },
95
+ children: [
96
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 2, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: `${name}.${btn.id}.text`, children: [
97
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Text" }),
98
+ /* @__PURE__ */ jsxRuntime.jsx(
99
+ designSystem.TextInput,
100
+ {
101
+ value: btn.text,
102
+ onChange: (e) => updateButton(btn.id, { text: e.target.value }),
103
+ disabled
104
+ }
105
+ )
106
+ ] }) }),
107
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 3, minWidth: 220 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: `${name}.${btn.id}.url`, children: [
108
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "URL" }),
109
+ /* @__PURE__ */ jsxRuntime.jsx(
110
+ designSystem.TextInput,
111
+ {
112
+ value: btn.url,
113
+ onChange: (e) => updateButton(btn.id, { url: e.target.value }),
114
+ disabled
115
+ }
116
+ ),
117
+ !urlOk && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", style: { marginTop: 4 }, children: "Please enter a valid http/https URL" })
118
+ ] }) }),
119
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 90 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: `${name}.${btn.id}.row`, children: [
120
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Row" }),
121
+ /* @__PURE__ */ jsxRuntime.jsx(
122
+ designSystem.TextInput,
123
+ {
124
+ type: "number",
125
+ value: String(btn.row ?? 0),
126
+ onChange: (e) => updateButton(btn.id, { row: parseInt(e.target.value, 10) || 0 }),
127
+ disabled
128
+ }
129
+ )
130
+ ] }) }),
131
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 1, paddingTop: 6, children: [
132
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Move up", children: /* @__PURE__ */ jsxRuntime.jsx(
133
+ designSystem.IconButton,
134
+ {
135
+ onClick: () => move(idx, idx - 1),
136
+ label: "Move up",
137
+ variant: "ghost",
138
+ disabled: disabled || idx === 0,
139
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUp, {})
140
+ }
141
+ ) }),
142
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Move down", children: /* @__PURE__ */ jsxRuntime.jsx(
143
+ designSystem.IconButton,
144
+ {
145
+ onClick: () => move(idx, idx + 1),
146
+ label: "Move down",
147
+ variant: "ghost",
148
+ disabled: disabled || idx === buttons.length - 1,
149
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDown, {})
150
+ }
151
+ ) }),
152
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: "Delete button", children: /* @__PURE__ */ jsxRuntime.jsx(
153
+ designSystem.IconButton,
154
+ {
155
+ onClick: () => deleteButton(btn.id),
156
+ label: "Delete button",
157
+ variant: "ghost",
158
+ disabled,
159
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
160
+ }
161
+ ) })
162
+ ] })
163
+ ]
164
+ },
165
+ btn.id
166
+ );
167
+ }),
168
+ buttons.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral0", hasRadius: true, style: { border: "1px dashed #dcdce4" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "No buttons. Add one to create an inline keyboard." }) })
169
+ ] }),
170
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: addButton, disabled, variant: "secondary", children: "Add button" }) }),
171
+ buttons.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingTop: 2, children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: 8, display: "block" }, children: "Preview" }),
173
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, children: previewRows.map((row) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, wrap: "wrap", children: row.items.map((b) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "primary100", children: b.text || "(empty)" }, b.id)) }, row.row)) })
174
+ ] }),
175
+ error && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, { children: error }),
176
+ hint && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: hint })
177
+ ] }) });
178
+ }
179
+ );
180
+ ButtonsBuilder.displayName = "ButtonsBuilder";
181
+ exports.default = ButtonsBuilder;