@btst/stack 2.5.4 → 2.5.5

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.
@@ -20,6 +20,7 @@ const card = require('../../../components/card.cjs');
20
20
  const breakpointClassnameControl = require('../../../components/ui-builder/internal/form-fields/classname-control/breakpoint-classname-control.cjs');
21
21
  const label = require('../../../components/label.cjs');
22
22
  const badge = require('../../../components/badge.cjs');
23
+ const select = require('../../../components/select.cjs');
23
24
 
24
25
  const classNameFieldOverrides = (layer) => {
25
26
  return {
@@ -167,6 +168,210 @@ const commonFieldOverrides = (allowBinding = true) => {
167
168
  memoizedCommonFieldOverrides.set(allowBinding, overrides);
168
169
  return overrides;
169
170
  };
171
+ function FunctionPropField({
172
+ propName,
173
+ label,
174
+ isRequired,
175
+ fieldConfigItem
176
+ }) {
177
+ const selectedLayerId = layerStore.useLayerStore((state) => state.selectedLayerId);
178
+ const findLayerById = layerStore.useLayerStore((state) => state.findLayerById);
179
+ const updateLayer = layerStore.useLayerStore((state) => state.updateLayer);
180
+ const incrementRevision = editorStore.useEditorStore((state) => state.incrementRevision);
181
+ const functionRegistry = editorStore.useEditorStore((state) => state.functionRegistry);
182
+ const unbindPropFromVariable = layerStore.useLayerStore(
183
+ (state) => state.unbindPropFromVariable
184
+ );
185
+ const selectedLayer = findLayerById(selectedLayerId);
186
+ if (!selectedLayer || !functionRegistry) {
187
+ return /* @__PURE__ */ jsxRuntime.jsx(
188
+ FormFieldWrapper,
189
+ {
190
+ label,
191
+ isRequired,
192
+ fieldConfigItem,
193
+ children: /* @__PURE__ */ jsxRuntime.jsx(select.Select, { disabled: true, children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectValue, { placeholder: "No function registry available" }) }) })
194
+ }
195
+ );
196
+ }
197
+ const functionEntries = Object.entries(functionRegistry);
198
+ const getCurrentFunctionId = () => {
199
+ const directFuncId = selectedLayer.props[`__function_${propName}`];
200
+ if (typeof directFuncId === "string") {
201
+ return directFuncId;
202
+ }
203
+ return "";
204
+ };
205
+ const handleValueChange = (value) => {
206
+ if (value === "__none__") {
207
+ unbindPropFromVariable(selectedLayer.id, propName);
208
+ updateLayer(selectedLayer.id, {
209
+ [`__function_${propName}`]: void 0,
210
+ [propName]: void 0
211
+ });
212
+ incrementRevision();
213
+ return;
214
+ }
215
+ const funcDef = functionRegistry[value];
216
+ if (funcDef) {
217
+ unbindPropFromVariable(selectedLayer.id, propName);
218
+ updateLayer(selectedLayer.id, {
219
+ [propName]: funcDef.fn,
220
+ [`__function_${propName}`]: value
221
+ });
222
+ incrementRevision();
223
+ }
224
+ };
225
+ const currentFunctionId = getCurrentFunctionId();
226
+ const getDisplayText = () => {
227
+ if (currentFunctionId) {
228
+ const funcDef = functionRegistry[currentFunctionId];
229
+ return funcDef?.name || currentFunctionId;
230
+ }
231
+ return "Select a function...";
232
+ };
233
+ return /* @__PURE__ */ jsxRuntime.jsx(
234
+ FormFieldWrapper,
235
+ {
236
+ label,
237
+ isRequired,
238
+ fieldConfigItem,
239
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
240
+ select.Select,
241
+ {
242
+ value: currentFunctionId,
243
+ onValueChange: handleValueChange,
244
+ children: [
245
+ /* @__PURE__ */ jsxRuntime.jsx(select.SelectTrigger, { className: "w-full mb-0", children: /* @__PURE__ */ jsxRuntime.jsx(select.SelectValue, { placeholder: "Select a function...", children: getDisplayText() }) }),
246
+ /* @__PURE__ */ jsxRuntime.jsxs(select.SelectContent, { children: [
247
+ /* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: "__none__", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "None (clear)" }) }),
248
+ functionEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: functionEntries.map(([id, funcDef]) => /* @__PURE__ */ jsxRuntime.jsx(select.SelectItem, { value: id, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
249
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: funcDef.name }),
250
+ funcDef.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: funcDef.description })
251
+ ] }) }, id)) })
252
+ ] })
253
+ ]
254
+ }
255
+ )
256
+ }
257
+ );
258
+ }
259
+ const functionPropFieldOverrides = (propName) => {
260
+ return {
261
+ renderParent: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(VariableBindingWrapper, { propName, isFunctionProp: true, children }),
262
+ fieldType: (props) => /* @__PURE__ */ jsxRuntime.jsx(FunctionPropField, { propName, ...props })
263
+ };
264
+ };
265
+ function VariableBindingWrapper({
266
+ propName,
267
+ children,
268
+ isFunctionProp = false
269
+ }) {
270
+ const variables = layerStore.useLayerStore((state) => state.variables);
271
+ const selectedLayerId = layerStore.useLayerStore((state) => state.selectedLayerId);
272
+ const findLayerById = layerStore.useLayerStore((state) => state.findLayerById);
273
+ const isBindingImmutable = layerStore.useLayerStore((state) => state.isBindingImmutable);
274
+ const incrementRevision = editorStore.useEditorStore((state) => state.incrementRevision);
275
+ const functionRegistry = editorStore.useEditorStore((state) => state.functionRegistry);
276
+ const unbindPropFromVariable = layerStore.useLayerStore(
277
+ (state) => state.unbindPropFromVariable
278
+ );
279
+ const bindPropToVariable = layerStore.useLayerStore((state) => state.bindPropToVariable);
280
+ const selectedLayer = findLayerById(selectedLayerId);
281
+ if (!selectedLayer) {
282
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
283
+ }
284
+ const filteredVariables = variables.filter(
285
+ (v) => isFunctionProp ? v.type === "function" : v.type !== "function"
286
+ );
287
+ const currentValue = selectedLayer.props[propName];
288
+ const isCurrentlyBound = types.isVariableReference(currentValue);
289
+ const boundVariable = isCurrentlyBound ? variables.find((v) => v.id === currentValue.__variableRef) : null;
290
+ const isImmutable = isBindingImmutable(selectedLayer.id, propName);
291
+ const getFunctionDisplayValue = (variable) => {
292
+ if (variable.type === "function" && functionRegistry) {
293
+ const funcId = String(variable.defaultValue);
294
+ const funcDef = functionRegistry[funcId];
295
+ return funcDef ? funcDef.name : funcId;
296
+ }
297
+ return String(variable.defaultValue);
298
+ };
299
+ const handleBindToVariable = (variableId) => {
300
+ bindPropToVariable(selectedLayer.id, propName, variableId);
301
+ incrementRevision();
302
+ };
303
+ const handleUnbind = () => {
304
+ unbindPropFromVariable(selectedLayer.id, propName);
305
+ incrementRevision();
306
+ };
307
+ const emptyMessage = isFunctionProp ? "No function variables defined" : "No variables defined";
308
+ const bindLabel = isFunctionProp ? "Bind to Function Variable" : "Bind to Variable";
309
+ const tooltipLabel = isFunctionProp ? "Bind Function" : "Bind Variable";
310
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full gap-2 items-end", children: isCurrentlyBound && boundVariable ? (
311
+ // Bound state - show variable info and unbind button
312
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 w-full", children: [
313
+ /* @__PURE__ */ jsxRuntime.jsx(label.Label, { children: propName.charAt(0).toUpperCase() + propName.slice(1) }),
314
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-2 w-full", children: [
315
+ /* @__PURE__ */ jsxRuntime.jsx(card.Card, { className: "w-full overflow-hidden min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(card.CardContent, { className: "py-1 px-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
316
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Link, { className: "h-4 w-4 flex-shrink-0" }),
317
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
319
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: boundVariable.name }),
320
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1.5 py-0.5 bg-muted rounded text-xs font-mono", children: boundVariable.type }),
321
+ isImmutable && /* @__PURE__ */ jsxRuntime.jsx(badge.Badge, { "data-testid": "immutable-badge", className: "rounded", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.LockKeyhole, { strokeWidth: 3, className: "w-3 h-3" }) })
322
+ ] }),
323
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground truncate", children: getFunctionDisplayValue(boundVariable) })
324
+ ] })
325
+ ] }) }) }),
326
+ !isImmutable && /* @__PURE__ */ jsxRuntime.jsxs(tooltip.Tooltip, { children: [
327
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
328
+ button.Button,
329
+ {
330
+ variant: "outline",
331
+ onClick: handleUnbind,
332
+ className: "px-3 h-10",
333
+ "data-testid": "unbind-variable-button",
334
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Unlink, { className: "h-4 w-4" })
335
+ }
336
+ ) }),
337
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipContent, { children: "Unbind Variable" })
338
+ ] })
339
+ ] })
340
+ ] })
341
+ ) : (
342
+ // Unbound state - show normal field with bind button
343
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
344
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children }),
345
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu, { children: [
346
+ /* @__PURE__ */ jsxRuntime.jsxs(tooltip.Tooltip, { children: [
347
+ /* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(button.Button, { variant: "outline", size: "sm", className: "px-3 h-10", "data-testid": "bind-variable-button", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Link, { className: "h-4 w-4 my-1" }) }) }) }),
348
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipContent, { children: tooltipLabel })
349
+ ] }),
350
+ /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenuContent, { align: "end", className: "w-56", children: [
351
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 text-xs font-medium text-muted-foreground border-b", children: bindLabel }),
352
+ filteredVariables.length > 0 ? filteredVariables.map((variable) => /* @__PURE__ */ jsxRuntime.jsx(
353
+ dropdownMenu.DropdownMenuItem,
354
+ {
355
+ onClick: () => handleBindToVariable(variable.id),
356
+ className: "flex flex-col items-start p-3",
357
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
358
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Link, { className: "h-4 w-4 flex-shrink-0" }),
359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
360
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ", children: [
361
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: variable.name }),
362
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1.5 py-0.5 bg-muted rounded text-xs font-mono", children: variable.type })
363
+ ] }),
364
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground truncate", children: getFunctionDisplayValue(variable) })
365
+ ] })
366
+ ] })
367
+ },
368
+ variable.id
369
+ )) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: emptyMessage })
370
+ ] })
371
+ ] }) })
372
+ ] })
373
+ ) });
374
+ }
170
375
  function FormFieldWrapper({
171
376
  label,
172
377
  isRequired,
@@ -278,9 +483,11 @@ function ChildrenVariableBindingWrapper({
278
483
 
279
484
  exports.ChildrenVariableBindingWrapper = ChildrenVariableBindingWrapper;
280
485
  exports.FormFieldWrapper = FormFieldWrapper;
486
+ exports.VariableBindingWrapper = VariableBindingWrapper;
281
487
  exports.childrenAsTextareaFieldOverrides = childrenAsTextareaFieldOverrides;
282
488
  exports.childrenAsTipTapFieldOverrides = childrenAsTipTapFieldOverrides;
283
489
  exports.childrenFieldOverrides = childrenFieldOverrides;
284
490
  exports.classNameFieldOverrides = classNameFieldOverrides;
285
491
  exports.commonFieldOverrides = commonFieldOverrides;
492
+ exports.functionPropFieldOverrides = functionPropFieldOverrides;
286
493
  exports.iconNameFieldOverrides = iconNameFieldOverrides;
@@ -18,6 +18,7 @@ import { Card, CardContent } from '../../../components/card.mjs';
18
18
  import { BreakpointClassNameControl } from '../../../components/ui-builder/internal/form-fields/classname-control/breakpoint-classname-control.mjs';
19
19
  import { Label } from '../../../components/label.mjs';
20
20
  import { Badge } from '../../../components/badge.mjs';
21
+ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../../../components/select.mjs';
21
22
 
22
23
  const classNameFieldOverrides = (layer) => {
23
24
  return {
@@ -165,6 +166,210 @@ const commonFieldOverrides = (allowBinding = true) => {
165
166
  memoizedCommonFieldOverrides.set(allowBinding, overrides);
166
167
  return overrides;
167
168
  };
169
+ function FunctionPropField({
170
+ propName,
171
+ label,
172
+ isRequired,
173
+ fieldConfigItem
174
+ }) {
175
+ const selectedLayerId = useLayerStore((state) => state.selectedLayerId);
176
+ const findLayerById = useLayerStore((state) => state.findLayerById);
177
+ const updateLayer = useLayerStore((state) => state.updateLayer);
178
+ const incrementRevision = useEditorStore((state) => state.incrementRevision);
179
+ const functionRegistry = useEditorStore((state) => state.functionRegistry);
180
+ const unbindPropFromVariable = useLayerStore(
181
+ (state) => state.unbindPropFromVariable
182
+ );
183
+ const selectedLayer = findLayerById(selectedLayerId);
184
+ if (!selectedLayer || !functionRegistry) {
185
+ return /* @__PURE__ */ jsx(
186
+ FormFieldWrapper,
187
+ {
188
+ label,
189
+ isRequired,
190
+ fieldConfigItem,
191
+ children: /* @__PURE__ */ jsx(Select, { disabled: true, children: /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "No function registry available" }) }) })
192
+ }
193
+ );
194
+ }
195
+ const functionEntries = Object.entries(functionRegistry);
196
+ const getCurrentFunctionId = () => {
197
+ const directFuncId = selectedLayer.props[`__function_${propName}`];
198
+ if (typeof directFuncId === "string") {
199
+ return directFuncId;
200
+ }
201
+ return "";
202
+ };
203
+ const handleValueChange = (value) => {
204
+ if (value === "__none__") {
205
+ unbindPropFromVariable(selectedLayer.id, propName);
206
+ updateLayer(selectedLayer.id, {
207
+ [`__function_${propName}`]: void 0,
208
+ [propName]: void 0
209
+ });
210
+ incrementRevision();
211
+ return;
212
+ }
213
+ const funcDef = functionRegistry[value];
214
+ if (funcDef) {
215
+ unbindPropFromVariable(selectedLayer.id, propName);
216
+ updateLayer(selectedLayer.id, {
217
+ [propName]: funcDef.fn,
218
+ [`__function_${propName}`]: value
219
+ });
220
+ incrementRevision();
221
+ }
222
+ };
223
+ const currentFunctionId = getCurrentFunctionId();
224
+ const getDisplayText = () => {
225
+ if (currentFunctionId) {
226
+ const funcDef = functionRegistry[currentFunctionId];
227
+ return funcDef?.name || currentFunctionId;
228
+ }
229
+ return "Select a function...";
230
+ };
231
+ return /* @__PURE__ */ jsx(
232
+ FormFieldWrapper,
233
+ {
234
+ label,
235
+ isRequired,
236
+ fieldConfigItem,
237
+ children: /* @__PURE__ */ jsxs(
238
+ Select,
239
+ {
240
+ value: currentFunctionId,
241
+ onValueChange: handleValueChange,
242
+ children: [
243
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full mb-0", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a function...", children: getDisplayText() }) }),
244
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
245
+ /* @__PURE__ */ jsx(SelectItem, { value: "__none__", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "None (clear)" }) }),
246
+ functionEntries.length > 0 && /* @__PURE__ */ jsx(Fragment, { children: functionEntries.map(([id, funcDef]) => /* @__PURE__ */ jsx(SelectItem, { value: id, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
247
+ /* @__PURE__ */ jsx("span", { children: funcDef.name }),
248
+ funcDef.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: funcDef.description })
249
+ ] }) }, id)) })
250
+ ] })
251
+ ]
252
+ }
253
+ )
254
+ }
255
+ );
256
+ }
257
+ const functionPropFieldOverrides = (propName) => {
258
+ return {
259
+ renderParent: ({ children }) => /* @__PURE__ */ jsx(VariableBindingWrapper, { propName, isFunctionProp: true, children }),
260
+ fieldType: (props) => /* @__PURE__ */ jsx(FunctionPropField, { propName, ...props })
261
+ };
262
+ };
263
+ function VariableBindingWrapper({
264
+ propName,
265
+ children,
266
+ isFunctionProp = false
267
+ }) {
268
+ const variables = useLayerStore((state) => state.variables);
269
+ const selectedLayerId = useLayerStore((state) => state.selectedLayerId);
270
+ const findLayerById = useLayerStore((state) => state.findLayerById);
271
+ const isBindingImmutable = useLayerStore((state) => state.isBindingImmutable);
272
+ const incrementRevision = useEditorStore((state) => state.incrementRevision);
273
+ const functionRegistry = useEditorStore((state) => state.functionRegistry);
274
+ const unbindPropFromVariable = useLayerStore(
275
+ (state) => state.unbindPropFromVariable
276
+ );
277
+ const bindPropToVariable = useLayerStore((state) => state.bindPropToVariable);
278
+ const selectedLayer = findLayerById(selectedLayerId);
279
+ if (!selectedLayer) {
280
+ return /* @__PURE__ */ jsx(Fragment, { children });
281
+ }
282
+ const filteredVariables = variables.filter(
283
+ (v) => isFunctionProp ? v.type === "function" : v.type !== "function"
284
+ );
285
+ const currentValue = selectedLayer.props[propName];
286
+ const isCurrentlyBound = isVariableReference(currentValue);
287
+ const boundVariable = isCurrentlyBound ? variables.find((v) => v.id === currentValue.__variableRef) : null;
288
+ const isImmutable = isBindingImmutable(selectedLayer.id, propName);
289
+ const getFunctionDisplayValue = (variable) => {
290
+ if (variable.type === "function" && functionRegistry) {
291
+ const funcId = String(variable.defaultValue);
292
+ const funcDef = functionRegistry[funcId];
293
+ return funcDef ? funcDef.name : funcId;
294
+ }
295
+ return String(variable.defaultValue);
296
+ };
297
+ const handleBindToVariable = (variableId) => {
298
+ bindPropToVariable(selectedLayer.id, propName, variableId);
299
+ incrementRevision();
300
+ };
301
+ const handleUnbind = () => {
302
+ unbindPropFromVariable(selectedLayer.id, propName);
303
+ incrementRevision();
304
+ };
305
+ const emptyMessage = isFunctionProp ? "No function variables defined" : "No variables defined";
306
+ const bindLabel = isFunctionProp ? "Bind to Function Variable" : "Bind to Variable";
307
+ const tooltipLabel = isFunctionProp ? "Bind Function" : "Bind Variable";
308
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full gap-2 items-end", children: isCurrentlyBound && boundVariable ? (
309
+ // Bound state - show variable info and unbind button
310
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 w-full", children: [
311
+ /* @__PURE__ */ jsx(Label, { children: propName.charAt(0).toUpperCase() + propName.slice(1) }),
312
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2 w-full", children: [
313
+ /* @__PURE__ */ jsx(Card, { className: "w-full overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(CardContent, { className: "py-1 px-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
314
+ /* @__PURE__ */ jsx(Link, { className: "h-4 w-4 flex-shrink-0" }),
315
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
316
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
317
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: boundVariable.name }),
318
+ /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 bg-muted rounded text-xs font-mono", children: boundVariable.type }),
319
+ isImmutable && /* @__PURE__ */ jsx(Badge, { "data-testid": "immutable-badge", className: "rounded", children: /* @__PURE__ */ jsx(LockKeyhole, { strokeWidth: 3, className: "w-3 h-3" }) })
320
+ ] }),
321
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground truncate", children: getFunctionDisplayValue(boundVariable) })
322
+ ] })
323
+ ] }) }) }),
324
+ !isImmutable && /* @__PURE__ */ jsxs(Tooltip, { children: [
325
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
326
+ Button,
327
+ {
328
+ variant: "outline",
329
+ onClick: handleUnbind,
330
+ className: "px-3 h-10",
331
+ "data-testid": "unbind-variable-button",
332
+ children: /* @__PURE__ */ jsx(Unlink, { className: "h-4 w-4" })
333
+ }
334
+ ) }),
335
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Unbind Variable" })
336
+ ] })
337
+ ] })
338
+ ] })
339
+ ) : (
340
+ // Unbound state - show normal field with bind button
341
+ /* @__PURE__ */ jsxs(Fragment, { children: [
342
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children }),
343
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
344
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
345
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "px-3 h-10", "data-testid": "bind-variable-button", children: /* @__PURE__ */ jsx(Link, { className: "h-4 w-4 my-1" }) }) }) }),
346
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltipLabel })
347
+ ] }),
348
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
349
+ /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-medium text-muted-foreground border-b", children: bindLabel }),
350
+ filteredVariables.length > 0 ? filteredVariables.map((variable) => /* @__PURE__ */ jsx(
351
+ DropdownMenuItem,
352
+ {
353
+ onClick: () => handleBindToVariable(variable.id),
354
+ className: "flex flex-col items-start p-3",
355
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full", children: [
356
+ /* @__PURE__ */ jsx(Link, { className: "h-4 w-4 flex-shrink-0" }),
357
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
358
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 ", children: [
359
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: variable.name }),
360
+ /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 bg-muted rounded text-xs font-mono", children: variable.type })
361
+ ] }),
362
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground truncate", children: getFunctionDisplayValue(variable) })
363
+ ] })
364
+ ] })
365
+ },
366
+ variable.id
367
+ )) : /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: emptyMessage })
368
+ ] })
369
+ ] }) })
370
+ ] })
371
+ ) });
372
+ }
168
373
  function FormFieldWrapper({
169
374
  label,
170
375
  isRequired,
@@ -274,4 +479,4 @@ function ChildrenVariableBindingWrapper({
274
479
  ) });
275
480
  }
276
481
 
277
- export { ChildrenVariableBindingWrapper, FormFieldWrapper, childrenAsTextareaFieldOverrides, childrenAsTipTapFieldOverrides, childrenFieldOverrides, classNameFieldOverrides, commonFieldOverrides, iconNameFieldOverrides };
482
+ export { ChildrenVariableBindingWrapper, FormFieldWrapper, VariableBindingWrapper, childrenAsTextareaFieldOverrides, childrenAsTipTapFieldOverrides, childrenFieldOverrides, classNameFieldOverrides, commonFieldOverrides, functionPropFieldOverrides, iconNameFieldOverrides };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btst/stack",
3
- "version": "2.5.4",
3
+ "version": "2.5.5",
4
4
  "description": "A composable, plugin-based library for building full-stack applications.",
5
5
  "repository": {
6
6
  "type": "git",