@verbb/plugin-kit-react 1.0.0 → 1.0.2

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 (38) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/components/SelectInput.js +1 -1
  3. package/dist/components/SelectInput.js.map +1 -1
  4. package/dist/components/TiptapEditor.d.ts +4 -2
  5. package/dist/components/TiptapEditor.d.ts.map +1 -1
  6. package/dist/components/TiptapEditor.js +27 -9
  7. package/dist/components/TiptapEditor.js.map +1 -1
  8. package/dist/components/TiptapInput.d.ts +18 -13
  9. package/dist/components/TiptapInput.d.ts.map +1 -1
  10. package/dist/components/TiptapInput.js +3 -1
  11. package/dist/components/TiptapInput.js.map +1 -1
  12. package/dist/components/tiptap/VariableDropdown.d.ts +7 -0
  13. package/dist/components/tiptap/VariableDropdown.d.ts.map +1 -1
  14. package/dist/components/tiptap/VariableDropdown.js.map +1 -1
  15. package/dist/components/tiptap/VariablePickerContext.d.ts +22 -2
  16. package/dist/components/tiptap/VariablePickerContext.d.ts.map +1 -1
  17. package/dist/components/tiptap/VariablePickerContext.js +7 -3
  18. package/dist/components/tiptap/VariablePickerContext.js.map +1 -1
  19. package/dist/components/tiptap/VariableTagView.d.ts.map +1 -1
  20. package/dist/components/tiptap/VariableTagView.js +160 -21
  21. package/dist/components/tiptap/VariableTagView.js.map +1 -1
  22. package/dist/components/tiptap/variableSerialization.d.ts +4 -0
  23. package/dist/components/tiptap/variableSerialization.d.ts.map +1 -1
  24. package/dist/components/tiptap/variableSerialization.js +71 -30
  25. package/dist/components/tiptap/variableSerialization.js.map +1 -1
  26. package/dist/forms/contexts/VariableCategoriesContext.d.ts +3 -1
  27. package/dist/forms/contexts/VariableCategoriesContext.d.ts.map +1 -1
  28. package/dist/forms/contexts/VariableCategoriesContext.js +3 -1
  29. package/dist/forms/contexts/VariableCategoriesContext.js.map +1 -1
  30. package/dist/forms/fields/RichTextField.d.ts.map +1 -1
  31. package/dist/forms/fields/RichTextField.js +3 -1
  32. package/dist/forms/fields/RichTextField.js.map +1 -1
  33. package/dist/forms/fields/SelectField.js +1 -1
  34. package/dist/forms/fields/SelectField.js.map +1 -1
  35. package/dist/forms/fields/VariablePickerField.d.ts.map +1 -1
  36. package/dist/forms/fields/VariablePickerField.js +3 -1
  37. package/dist/forms/fields/VariablePickerField.js.map +1 -1
  38. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.1 - 2026-06-07
4
+
5
+ ### Added
6
+ - Added variable tag extension points for custom configure sections and label resolution.
7
+ - Added support for preserving custom reference metadata in variable tokens.
8
+ - Added support for resolving scoped variable token variants against their base variable option.
9
+
10
+ ### Changed
11
+ - Improved Tiptap variable tag configuration so pending token changes preview immediately and are reverted when the popover is dismissed without saving.
12
+ - Kept variable token parsing generic so host applications can define their own reference semantics without plugin-kit knowing about them.
13
+
14
+ ### Fixed
15
+ - Fixed variable tags showing raw token values instead of matched option labels in some reference-token cases.
16
+ - Fixed configured variable tags losing reference metadata when saved with fallback values or transforms.
17
+
3
18
  ## 1.0.0
4
19
 
5
20
  - Initial public release.
@@ -26,7 +26,7 @@ var SelectInput = forwardRef(({ options, placeholder, size, onChange, value, tri
26
26
  return [option];
27
27
  });
28
28
  const selectedOption = flatOptions.find((option) => {
29
- return option.value === value;
29
+ return String(option.value) === String(value);
30
30
  });
31
31
  const resolvedPlaceholder = placeholder || "";
32
32
  const resolvedIsInvalid = Boolean(isInvalid || ariaInvalid === true || ariaInvalid === "true");
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.js","names":[],"sources":["../../src/components/SelectInput.tsx"],"sourcesContent":["import {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n SelectLabel,\n} from '@verbb/plugin-kit-react/components';\n\nimport type React from 'react';\nimport { ComponentProps, forwardRef } from 'react';\nimport { Status } from '@verbb/plugin-kit-react/components/Status';\nimport { cn } from '@verbb/plugin-kit-react/utils';\n\n\nexport interface Option<T = unknown> {\n value: T;\n label: string;\n disabled?: boolean;\n status?: string;\n}\n\ntype OptionGroup<T = unknown> = {\n group: string;\n options: Option<T>[];\n};\n\n// const valueToString = (val: Option['value']) => {\n// if (val === null) { return '__null__'; }\n// if (val === undefined) {\n// console.error('option value cannot be undefined');\n// return '__undefined__';\n// }\n// if (val === Infinity) { return '__Infinity__'; }\n// if (val === -Infinity) { return '__-Infinity__'; }\n// if (Number.isNaN(val)) { return '__NaN__'; }\n// if (typeof val === 'symbol') { return `__symbol__${val.description}`; }\n// // console.log(JSON.stringify(val));\n// return JSON.stringify(val);\n// };\n\n// const stringToValue = (str: string) => {\n// switch (str) {\n// case '__null__':\n// return null;\n// case '__undefined__':\n// return undefined;\n// case '__Infinity__':\n// return Infinity;\n// case '__-Infinity__':\n// return -Infinity;\n// case '__NaN__':\n// return NaN;\n// default:\n// if (str.startsWith('__symbol__')) {\n// return Symbol(str.slice(10));\n// }\n// return JSON.parse(str);\n// }\n// };\n\ntype SelectBaseProps = ComponentProps<typeof Select>;\n\ninterface SelectProps<T = unknown>\n extends Omit<SelectBaseProps, 'children' | 'value' | 'defaultValue' | 'onValueChange'> {\n options: Array<Option<T> | OptionGroup<T>>;\n placeholder?: string;\n onChange?: (value: T) => void;\n value?: T;\n isInvalid?: boolean;\n onBlur?: React.FocusEventHandler<HTMLButtonElement>;\n triggerClassName?: string;\n contentClassName?: string;\n id?: string;\n 'aria-invalid'?: boolean | 'true' | 'false';\n 'aria-describedby'?: string;\n 'aria-errormessage'?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\nexport const SelectInput = forwardRef<HTMLButtonElement, SelectProps>(({\n options,\n placeholder,\n size,\n onChange,\n value,\n triggerClassName,\n contentClassName,\n isInvalid,\n id,\n 'aria-invalid': ariaInvalid,\n 'aria-describedby': ariaDescribedBy,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...selectProps\n}, ref) => {\n const handleValueChange = (nextValue: SelectProps['value']) => {\n if (onChange) {\n onChange(nextValue);\n }\n };\n\n // const hasEmptyOption = options?.find((option) => { return option.value === ''; });\n\n // let defaultValue = undefined;\n\n // // Only show placeholder when value is initially undefined,\n // // or when the value is an empty string and there's an empty option\n // if (value === undefined || value === '') {\n // if (hasEmptyOption) {\n // defaultValue = valueToString('');\n // } else {\n // defaultValue = undefined;\n // }\n // } else {\n // defaultValue = valueToString(value);\n // }\n\n const hasGroup = (option: Option<unknown> | OptionGroup<unknown>): option is OptionGroup<unknown> => {\n return typeof option === 'object' && option !== null && 'group' in option;\n };\n\n const groupedOptions = options.map((option, index) => {\n if (hasGroup(option)) {\n return option;\n }\n\n return {\n group: null,\n options: [option],\n _key: `ungrouped-${index}`,\n };\n });\n\n const flatOptions = options.flatMap((option) => {\n if (hasGroup(option)) {\n return option.options;\n }\n\n return [option];\n });\n\n const selectedOption = flatOptions.find((option) => {\n return option.value === value;\n });\n const resolvedPlaceholder = placeholder || '';\n const resolvedIsInvalid = Boolean(isInvalid || ariaInvalid === true || ariaInvalid === 'true');\n\n return (\n <Select\n value={value}\n onValueChange={handleValueChange}\n size={size}\n items={flatOptions as ComponentProps<typeof Select>['items']}\n {...selectProps}\n >\n <SelectTrigger\n ref={ref}\n id={id}\n aria-invalid={resolvedIsInvalid}\n aria-describedby={ariaDescribedBy}\n aria-errormessage={ariaErrorMessage}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n className={cn(\n selectedOption?.status && 'relative [&_[data-slot=select-value]]:pl-5',\n '[&_[data-slot=select-value]]:overflow-hidden [&_[data-slot=select-value]>span]:block [&_[data-slot=select-value]>span]:min-w-0 [&_[data-slot=select-value]>span]:max-w-full [&_[data-slot=select-value]>span]:truncate',\n triggerClassName,\n )}\n >\n {selectedOption?.status && (\n <Status\n status={selectedOption.status}\n className=\"absolute left-2.5 top-1/2 -translate-y-1/2\"\n />\n )}\n <SelectValue placeholder={placeholder}>\n {selectedOption ? (\n <span className=\"block min-w-0 max-w-full truncate\" title={selectedOption.label}>\n {selectedOption.label}\n </span>\n ) : (\n <span className=\"block min-w-0 max-w-full truncate text-slate-500\" title={resolvedPlaceholder}>\n {resolvedPlaceholder}\n </span>\n )}\n </SelectValue>\n </SelectTrigger>\n\n {options?.length > 0 && (\n <SelectContent className={contentClassName}>\n {groupedOptions.map((group) => {\n return (\n <SelectGroup key={group.group ?? group._key}>\n {group.group && <SelectLabel>{group.group}</SelectLabel>}\n\n {group.options?.map((option) => {\n return (\n <SelectItem\n key={String(option.value)}\n value={option.value}\n disabled={option.disabled}\n >\n {option.status && (\n <Status status={option.status} />\n )}\n <span className=\"block min-w-0 flex-1 truncate\" title={option.label}>\n {option.label}\n </span>\n </SelectItem>\n );\n })}\n </SelectGroup>\n );\n })}\n </SelectContent>\n )}\n </Select>\n );\n});\n\nexport default Select;\nexport type { SelectProps };\n"],"mappings":";;;;;;;;AAkFA,IAAa,cAAc,YAA4C,EACnE,SACA,aACA,MACA,UACA,OACA,kBACA,kBACA,WACA,IACA,gBAAgB,aAChB,oBAAoB,iBACpB,qBAAqB,kBACrB,cAAc,WACd,mBAAmB,gBACnB,GAAG,eACJ,QAAQ;CACP,MAAM,qBAAqB,cAAoC;AAC3D,MAAI,SACA,UAAS,UAAU;;CAoB3B,MAAM,YAAY,WAAmF;AACjG,SAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,WAAW;;CAGvE,MAAM,iBAAiB,QAAQ,KAAK,QAAQ,UAAU;AAClD,MAAI,SAAS,OAAO,CAChB,QAAO;AAGX,SAAO;GACH,OAAO;GACP,SAAS,CAAC,OAAO;GACjB,MAAM,aAAa;GACtB;GACH;CAEF,MAAM,cAAc,QAAQ,SAAS,WAAW;AAC5C,MAAI,SAAS,OAAO,CAChB,QAAO,OAAO;AAGlB,SAAO,CAAC,OAAO;GACjB;CAEF,MAAM,iBAAiB,YAAY,MAAM,WAAW;AAChD,SAAO,OAAO,UAAU;GAC1B;CACF,MAAM,sBAAsB,eAAe;CAC3C,MAAM,oBAAoB,QAAQ,aAAa,gBAAgB,QAAQ,gBAAgB,OAAO;AAE9F,QACI,qBAAC,QAAD;EACW;EACP,eAAe;EACT;EACN,OAAO;EACP,GAAI;YALR,CAOI,qBAAC,eAAD;GACS;GACD;GACJ,gBAAc;GACd,oBAAkB;GAClB,qBAAmB;GACnB,cAAY;GACZ,mBAAiB;GACjB,WAAW,GACP,gBAAgB,UAAU,8CAC1B,0NACA,iBACH;aAZL,CAcK,gBAAgB,UACb,oBAAC,QAAD;IACI,QAAQ,eAAe;IACvB,WAAU;IACZ,CAAA,EAEN,oBAAC,aAAD;IAA0B;cACrB,iBACG,oBAAC,QAAD;KAAM,WAAU;KAAoC,OAAO,eAAe;eACrE,eAAe;KACb,CAAA,GAEP,oBAAC,QAAD;KAAM,WAAU;KAAmD,OAAO;eACrE;KACE,CAAA;IAED,CAAA,CACF;MAEf,SAAS,SAAS,KACf,oBAAC,eAAD;GAAe,WAAW;aACrB,eAAe,KAAK,UAAU;AAC3B,WACI,qBAAC,aAAD,EAAA,UAAA,CACK,MAAM,SAAS,oBAAC,aAAD,EAAA,UAAc,MAAM,OAAoB,CAAA,EAEvD,MAAM,SAAS,KAAK,WAAW;AAC5B,YACI,qBAAC,YAAD;MAEI,OAAO,OAAO;MACd,UAAU,OAAO;gBAHrB,CAKK,OAAO,UACJ,oBAAC,QAAD,EAAQ,QAAQ,OAAO,QAAU,CAAA,EAErC,oBAAC,QAAD;OAAM,WAAU;OAAgC,OAAO,OAAO;iBACzD,OAAO;OACL,CAAA,CACE;QAVJ,OAAO,OAAO,MAAM,CAUhB;MAEnB,CACQ,EAAA,EAnBI,MAAM,SAAS,MAAM,KAmBzB;KAEpB;GACU,CAAA,CAEf;;EAEf;AAEF,IAAA,sBAAe"}
1
+ {"version":3,"file":"SelectInput.js","names":[],"sources":["../../src/components/SelectInput.tsx"],"sourcesContent":["import {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n SelectLabel,\n} from '@verbb/plugin-kit-react/components';\n\nimport type React from 'react';\nimport { ComponentProps, forwardRef } from 'react';\nimport { Status } from '@verbb/plugin-kit-react/components/Status';\nimport { cn } from '@verbb/plugin-kit-react/utils';\n\n\nexport interface Option<T = unknown> {\n value: T;\n label: string;\n disabled?: boolean;\n status?: string;\n}\n\ntype OptionGroup<T = unknown> = {\n group: string;\n options: Option<T>[];\n};\n\n// const valueToString = (val: Option['value']) => {\n// if (val === null) { return '__null__'; }\n// if (val === undefined) {\n// console.error('option value cannot be undefined');\n// return '__undefined__';\n// }\n// if (val === Infinity) { return '__Infinity__'; }\n// if (val === -Infinity) { return '__-Infinity__'; }\n// if (Number.isNaN(val)) { return '__NaN__'; }\n// if (typeof val === 'symbol') { return `__symbol__${val.description}`; }\n// // console.log(JSON.stringify(val));\n// return JSON.stringify(val);\n// };\n\n// const stringToValue = (str: string) => {\n// switch (str) {\n// case '__null__':\n// return null;\n// case '__undefined__':\n// return undefined;\n// case '__Infinity__':\n// return Infinity;\n// case '__-Infinity__':\n// return -Infinity;\n// case '__NaN__':\n// return NaN;\n// default:\n// if (str.startsWith('__symbol__')) {\n// return Symbol(str.slice(10));\n// }\n// return JSON.parse(str);\n// }\n// };\n\ntype SelectBaseProps = ComponentProps<typeof Select>;\n\ninterface SelectProps<T = unknown>\n extends Omit<SelectBaseProps, 'children' | 'value' | 'defaultValue' | 'onValueChange'> {\n options: Array<Option<T> | OptionGroup<T>>;\n placeholder?: string;\n onChange?: (value: T) => void;\n value?: T;\n isInvalid?: boolean;\n onBlur?: React.FocusEventHandler<HTMLButtonElement>;\n triggerClassName?: string;\n contentClassName?: string;\n id?: string;\n 'aria-invalid'?: boolean | 'true' | 'false';\n 'aria-describedby'?: string;\n 'aria-errormessage'?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\nexport const SelectInput = forwardRef<HTMLButtonElement, SelectProps>(({\n options,\n placeholder,\n size,\n onChange,\n value,\n triggerClassName,\n contentClassName,\n isInvalid,\n id,\n 'aria-invalid': ariaInvalid,\n 'aria-describedby': ariaDescribedBy,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...selectProps\n}, ref) => {\n const handleValueChange = (nextValue: SelectProps['value']) => {\n if (onChange) {\n onChange(nextValue);\n }\n };\n\n // const hasEmptyOption = options?.find((option) => { return option.value === ''; });\n\n // let defaultValue = undefined;\n\n // // Only show placeholder when value is initially undefined,\n // // or when the value is an empty string and there's an empty option\n // if (value === undefined || value === '') {\n // if (hasEmptyOption) {\n // defaultValue = valueToString('');\n // } else {\n // defaultValue = undefined;\n // }\n // } else {\n // defaultValue = valueToString(value);\n // }\n\n const hasGroup = (option: Option<unknown> | OptionGroup<unknown>): option is OptionGroup<unknown> => {\n return typeof option === 'object' && option !== null && 'group' in option;\n };\n\n const groupedOptions = options.map((option, index) => {\n if (hasGroup(option)) {\n return option;\n }\n\n return {\n group: null,\n options: [option],\n _key: `ungrouped-${index}`,\n };\n });\n\n const flatOptions = options.flatMap((option) => {\n if (hasGroup(option)) {\n return option.options;\n }\n\n return [option];\n });\n\n const selectedOption = flatOptions.find((option) => {\n return String(option.value) === String(value);\n });\n const resolvedPlaceholder = placeholder || '';\n const resolvedIsInvalid = Boolean(isInvalid || ariaInvalid === true || ariaInvalid === 'true');\n\n return (\n <Select\n value={value}\n onValueChange={handleValueChange}\n size={size}\n items={flatOptions as ComponentProps<typeof Select>['items']}\n {...selectProps}\n >\n <SelectTrigger\n ref={ref}\n id={id}\n aria-invalid={resolvedIsInvalid}\n aria-describedby={ariaDescribedBy}\n aria-errormessage={ariaErrorMessage}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n className={cn(\n selectedOption?.status && 'relative [&_[data-slot=select-value]]:pl-5',\n '[&_[data-slot=select-value]]:overflow-hidden [&_[data-slot=select-value]>span]:block [&_[data-slot=select-value]>span]:min-w-0 [&_[data-slot=select-value]>span]:max-w-full [&_[data-slot=select-value]>span]:truncate',\n triggerClassName,\n )}\n >\n {selectedOption?.status && (\n <Status\n status={selectedOption.status}\n className=\"absolute left-2.5 top-1/2 -translate-y-1/2\"\n />\n )}\n <SelectValue placeholder={placeholder}>\n {selectedOption ? (\n <span className=\"block min-w-0 max-w-full truncate\" title={selectedOption.label}>\n {selectedOption.label}\n </span>\n ) : (\n <span className=\"block min-w-0 max-w-full truncate text-slate-500\" title={resolvedPlaceholder}>\n {resolvedPlaceholder}\n </span>\n )}\n </SelectValue>\n </SelectTrigger>\n\n {options?.length > 0 && (\n <SelectContent className={contentClassName}>\n {groupedOptions.map((group) => {\n return (\n <SelectGroup key={group.group ?? group._key}>\n {group.group && <SelectLabel>{group.group}</SelectLabel>}\n\n {group.options?.map((option) => {\n return (\n <SelectItem\n key={String(option.value)}\n value={option.value}\n disabled={option.disabled}\n >\n {option.status && (\n <Status status={option.status} />\n )}\n <span className=\"block min-w-0 flex-1 truncate\" title={option.label}>\n {option.label}\n </span>\n </SelectItem>\n );\n })}\n </SelectGroup>\n );\n })}\n </SelectContent>\n )}\n </Select>\n );\n});\n\nexport default Select;\nexport type { SelectProps };\n"],"mappings":";;;;;;;;AAkFA,IAAa,cAAc,YAA4C,EACnE,SACA,aACA,MACA,UACA,OACA,kBACA,kBACA,WACA,IACA,gBAAgB,aAChB,oBAAoB,iBACpB,qBAAqB,kBACrB,cAAc,WACd,mBAAmB,gBACnB,GAAG,eACJ,QAAQ;CACP,MAAM,qBAAqB,cAAoC;AAC3D,MAAI,SACA,UAAS,UAAU;;CAoB3B,MAAM,YAAY,WAAmF;AACjG,SAAO,OAAO,WAAW,YAAY,WAAW,QAAQ,WAAW;;CAGvE,MAAM,iBAAiB,QAAQ,KAAK,QAAQ,UAAU;AAClD,MAAI,SAAS,OAAO,CAChB,QAAO;AAGX,SAAO;GACH,OAAO;GACP,SAAS,CAAC,OAAO;GACjB,MAAM,aAAa;GACtB;GACH;CAEF,MAAM,cAAc,QAAQ,SAAS,WAAW;AAC5C,MAAI,SAAS,OAAO,CAChB,QAAO,OAAO;AAGlB,SAAO,CAAC,OAAO;GACjB;CAEF,MAAM,iBAAiB,YAAY,MAAM,WAAW;AAChD,SAAO,OAAO,OAAO,MAAM,KAAK,OAAO,MAAM;GAC/C;CACF,MAAM,sBAAsB,eAAe;CAC3C,MAAM,oBAAoB,QAAQ,aAAa,gBAAgB,QAAQ,gBAAgB,OAAO;AAE9F,QACI,qBAAC,QAAD;EACW;EACP,eAAe;EACT;EACN,OAAO;EACP,GAAI;YALR,CAOI,qBAAC,eAAD;GACS;GACD;GACJ,gBAAc;GACd,oBAAkB;GAClB,qBAAmB;GACnB,cAAY;GACZ,mBAAiB;GACjB,WAAW,GACP,gBAAgB,UAAU,8CAC1B,0NACA,iBACH;aAZL,CAcK,gBAAgB,UACb,oBAAC,QAAD;IACI,QAAQ,eAAe;IACvB,WAAU;IACZ,CAAA,EAEN,oBAAC,aAAD;IAA0B;cACrB,iBACG,oBAAC,QAAD;KAAM,WAAU;KAAoC,OAAO,eAAe;eACrE,eAAe;KACb,CAAA,GAEP,oBAAC,QAAD;KAAM,WAAU;KAAmD,OAAO;eACrE;KACE,CAAA;IAED,CAAA,CACF;MAEf,SAAS,SAAS,KACf,oBAAC,eAAD;GAAe,WAAW;aACrB,eAAe,KAAK,UAAU;AAC3B,WACI,qBAAC,aAAD,EAAA,UAAA,CACK,MAAM,SAAS,oBAAC,aAAD,EAAA,UAAc,MAAM,OAAoB,CAAA,EAEvD,MAAM,SAAS,KAAK,WAAW;AAC5B,YACI,qBAAC,YAAD;MAEI,OAAO,OAAO;MACd,UAAU,OAAO;gBAHrB,CAKK,OAAO,UACJ,oBAAC,QAAD,EAAQ,QAAQ,OAAO,QAAU,CAAA,EAErC,oBAAC,QAAD;OAAM,WAAU;OAAgC,OAAO,OAAO;iBACzD,OAAO;OACL,CAAA,CACE;QAVJ,OAAO,OAAO,MAAM,CAUhB;MAEnB,CACQ,EAAA,EAnBI,MAAM,SAAS,MAAM,KAmBzB;KAEpB;GACU,CAAA,CAEf;;EAEf;AAEF,IAAA,sBAAe"}
@@ -2,7 +2,7 @@ import { ReactNode } from 'react';
2
2
  import { Editor as TiptapEditorInstance } from '@tiptap/core';
3
3
  import { LinkOptions, LinkOptionsInput } from './tiptap/LinkDropdown';
4
4
  import { VariableOption, VariableCategories } from './tiptap/VariableDropdown';
5
- import { VariableTransformerRegistry } from './tiptap/VariablePickerContext';
5
+ import { VariableTransformerRegistry, VariableConfigureSectionProps, VariableTagLabelResolver } from './tiptap/VariablePickerContext';
6
6
  export type { LinkOptions, LinkOptionsInput, VariableOption, VariableCategories, };
7
7
  type TiptapEditorProps = {
8
8
  value?: unknown;
@@ -21,6 +21,8 @@ type TiptapEditorProps = {
21
21
  variableCategoryOrder?: string[];
22
22
  variableTransformerRegistry?: VariableTransformerRegistry;
23
23
  variablePickerTriggerCharacters?: string[];
24
+ renderVariableConfigureSection?: (props: VariableConfigureSectionProps) => ReactNode;
25
+ resolveVariableTagLabel?: VariableTagLabelResolver;
24
26
  toolbarContent?: (params: {
25
27
  editor: TiptapEditorInstance | null;
26
28
  variableCategories: VariableCategories;
@@ -37,5 +39,5 @@ type TiptapEditorProps = {
37
39
  invalidContentMessage?: string;
38
40
  [key: string]: unknown;
39
41
  };
40
- export declare const TiptapEditor: ({ value, onChange, buttons, tableOptions, linkOptions, linkSelectorStorageKeyPrefix, variableCategories, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters, toolbarContent, rows, className, isInvalid, disabled, readOnly, invalidContentMessage, ...props }: TiptapEditorProps) => import("react/jsx-runtime").JSX.Element;
42
+ export declare const TiptapEditor: ({ value, onChange, buttons, tableOptions, linkOptions, linkSelectorStorageKeyPrefix, variableCategories, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters, renderVariableConfigureSection, resolveVariableTagLabel, toolbarContent, rows, className, isInvalid, disabled, readOnly, invalidContentMessage, ...props }: TiptapEditorProps) => import("react/jsx-runtime").JSX.Element;
41
43
  //# sourceMappingURL=TiptapEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TiptapEditor.d.ts","sourceRoot":"","sources":["../../src/components/TiptapEditor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAgB,KAAK,MAAM,IAAI,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIjF,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAKlF,YAAY,EACR,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,GACpE,CAAC;AAqWF,KAAK,iBAAiB,GAAG;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAChF,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,+BAA+B,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE;QACtB,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;QACpC,kBAAkB,EAAE,kBAAkB,CAAC;QACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QACjC,kBAAkB,EAAE,OAAO,CAAC;QAC5B,0BAA0B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;KACvD,KAAK,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,yTAoB1B,iBAAiB,4CA+QnB,CAAC"}
1
+ {"version":3,"file":"TiptapEditor.d.ts","sourceRoot":"","sources":["../../src/components/TiptapEditor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAgB,KAAK,MAAM,IAAI,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIjF,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,KAAK,EAAE,2BAA2B,EAAE,6BAA6B,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAK3I,YAAY,EACR,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,GACpE,CAAC;AAqWF,KAAK,iBAAiB,GAAG;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAChF,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,+BAA+B,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3C,8BAA8B,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,SAAS,CAAC;IACrF,uBAAuB,CAAC,EAAE,wBAAwB,CAAC;IACnD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE;QACtB,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;QACpC,kBAAkB,EAAE,kBAAkB,CAAC;QACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QACjC,kBAAkB,EAAE,OAAO,CAAC;QAC5B,0BAA0B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;KACvD,KAAK,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,kXAsB1B,iBAAiB,4CAoTnB,CAAC"}
@@ -345,10 +345,11 @@ var MenuBar = ({ editor, buttons = ["bold", "italic"], linkOptions, linkSelector
345
345
  children: renderedButtons
346
346
  });
347
347
  };
348
- var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableOptions = [], linkOptions, linkSelectorStorageKeyPrefix, variableCategories = {}, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters = ["@"], toolbarContent, rows, className, isInvalid, disabled = false, readOnly = false, invalidContentMessage, ...props }) => {
348
+ var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableOptions = [], linkOptions, linkSelectorStorageKeyPrefix, variableCategories = {}, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters = ["@"], renderVariableConfigureSection, resolveVariableTagLabel, toolbarContent, rows, className, isInvalid, disabled = false, readOnly = false, invalidContentMessage, ...props }) => {
349
349
  useTranslation();
350
350
  const wrapperRef = useRef(null);
351
351
  const handleKeyDownRef = useRef(null);
352
+ const lastEmittedContentRef = useRef(null);
352
353
  const extensions = useMemo(() => {
353
354
  return createTiptapExtensions({ trailingCursorText: "⁠" });
354
355
  }, []);
@@ -368,6 +369,9 @@ var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableO
368
369
  const serializeContent = (content) => {
369
370
  return normalizeContentArray(content);
370
371
  };
372
+ const serializeEditorDocument = useCallback((editorInstance) => {
373
+ return JSON.stringify(serializeContent(editorInstance.getJSON().content));
374
+ }, []);
371
375
  const editor = useEditor({
372
376
  extensions,
373
377
  content: contentError ? null : editorContent,
@@ -375,8 +379,10 @@ var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableO
375
379
  editorProps: { handleKeyDown: (view, event) => {
376
380
  return handleKeyDownRef.current?.(view, event) ?? false;
377
381
  } },
378
- onUpdate: ({ editor }) => {
379
- if (onChange) onChange(serializeContent(editor.getJSON().content));
382
+ onUpdate: ({ editor: editorInstance }) => {
383
+ const serialized = serializeContent(editorInstance.getJSON().content);
384
+ lastEmittedContentRef.current = JSON.stringify(serialized);
385
+ if (onChange) onChange(serialized);
380
386
  }
381
387
  });
382
388
  const inlinePicker = useInlineVariablePicker(editor, {
@@ -438,15 +444,25 @@ var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableO
438
444
  }
439
445
  }, [editor]);
440
446
  useEffect(() => {
441
- if (editor) {
442
- const newContent = contentError ? null : editorContent;
443
- const currentContent = editor.getJSON();
444
- if (JSON.stringify(newContent) !== JSON.stringify(currentContent)) editor.commands.setContent(newContent);
445
- }
447
+ if (!editor) return;
448
+ const incomingContent = contentError ? null : editorContent;
449
+ const incomingSerialized = JSON.stringify(incomingContent?.content ?? []);
450
+ const currentSerialized = serializeEditorDocument(editor);
451
+ const isVariableConfigActive = Boolean(document.activeElement?.closest("[data-variable-config-popover]"));
452
+ if (incomingSerialized === currentSerialized) return;
453
+ if (lastEmittedContentRef.current === incomingSerialized) return;
454
+ if (!readOnly && (editor.isFocused || isVariableConfigActive || lastEmittedContentRef.current && currentSerialized === lastEmittedContentRef.current && incomingSerialized !== lastEmittedContentRef.current)) return;
455
+ editor.commands.setContent(incomingContent ?? {
456
+ type: "doc",
457
+ content: []
458
+ });
459
+ lastEmittedContentRef.current = incomingSerialized;
446
460
  }, [
447
461
  contentError,
448
462
  editor,
449
- editorContent
463
+ editorContent,
464
+ readOnly,
465
+ serializeEditorDocument
450
466
  ]);
451
467
  const handleLinkBubbleEdit = useCallback(() => {
452
468
  if (!editor) return;
@@ -470,6 +486,8 @@ var TiptapEditor = ({ value = "", onChange, buttons = ["bold", "italic"], tableO
470
486
  variableCategoryLabels,
471
487
  variableCategoryOrder,
472
488
  variableTransformerRegistry,
489
+ renderVariableConfigureSection,
490
+ resolveVariableTagLabel,
473
491
  children: [/* @__PURE__ */ jsxs(EditorContext.Provider, {
474
492
  value: { editor },
475
493
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"TiptapEditor.js","names":[],"sources":["../../src/components/TiptapEditor.tsx"],"sourcesContent":["import {\n useEffect, useCallback, useMemo, useRef, useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport { useEditor, EditorContent, EditorContext } from '@tiptap/react';\nimport { getMarkRange, type Editor as TiptapEditorInstance } from '@tiptap/core';\n\nimport { Button } from '@verbb/plugin-kit-react/components';\nimport { LinkDropdown } from './tiptap/LinkDropdown';\nimport type { LinkOptions, LinkOptionsInput } from './tiptap/LinkDropdown';\nimport { VariableDropdown } from './tiptap/VariableDropdown';\nimport type { VariableOption, VariableCategories } from './tiptap/VariableDropdown';\nimport type { VariableTransformerRegistry } from './tiptap/VariablePickerContext';\nimport { VariablePickerProvider } from './tiptap/VariablePickerContext';\nimport { InlineVariablePickerPopover } from './tiptap/InlineVariablePickerPopover';\nimport { useInlineVariablePicker } from './tiptap/useInlineVariablePicker';\n\nexport type {\n LinkOptions, LinkOptionsInput, VariableOption, VariableCategories,\n};\nimport { LinkBubbleMenu } from './tiptap/LinkBubbleMenu';\nimport { InsertLinkDialog } from './tiptap/InsertLinkDialog';\n\nimport {\n createTiptapExtensions,\n getFatalTiptapContentError,\n normalizeContentArray,\n valueToContent,\n} from './tiptap/editorConfig';\n\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\n\nimport {\n faAlignCenter,\n faAlignJustify,\n faAlignLeft,\n faAlignRight,\n faArrowRotateLeft,\n faArrowRotateRight,\n faBold,\n faBracketsCurly,\n faCode,\n faH1,\n faH2,\n faH3,\n faH4,\n faH5,\n faH6,\n faHighlighter,\n faItalic,\n faListOl,\n faListUl,\n faMinus,\n faQuoteRight,\n faStrikethrough,\n faSubscript,\n faSuperscript,\n faTriangleExclamation,\n\n faUnderline,\n faTextSlash,\n} from '@fortawesome/pro-solid-svg-icons';\n\nimport {\n faFileDashedLine,\n faTable,\n} from '@fortawesome/pro-regular-svg-icons';\n\nimport { cn } from '@verbb/plugin-kit-react/utils';\nimport { useTranslation } from '@verbb/plugin-kit-react/hooks';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@verbb/plugin-kit-react/components/Tooltip';\n\nconst MenuBar = ({\n editor,\n buttons = ['bold', 'italic'],\n linkOptions,\n linkSelectorStorageKeyPrefix,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerOpen,\n onVariablePickerOpenChange,\n openInsertLinkDialog,\n}: {\n editor: TiptapEditorInstance | null | undefined;\n buttons?: string[];\n linkOptions?: LinkOptionsInput;\n linkSelectorStorageKeyPrefix?: string;\n variableCategories?: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variablePickerOpen?: boolean;\n onVariablePickerOpenChange?: (open: boolean) => void;\n openInsertLinkDialog?: (initial?: { url?: string; text?: string; from?: number; to?: number }) => void;\n}) => {\n const t = useTranslation();\n\n if (!editor) {\n return null;\n }\n\n const hasAnyVariables = Object.values(variableCategories ?? {}).some(\n items => {\n return Array.isArray(items) && items.length > 0;\n },\n );\n\n const visibleButtons = buttons.filter((buttonName) => {\n if (buttonName === 'variableTag') {\n return hasAnyVariables;\n }\n\n return true;\n });\n\n const buttonConfig = {\n bold: {\n icon: FontAwesomeIcon,\n iconProp: faBold,\n title: t('Bold'),\n action: () => { return editor.chain().focus().toggleBold().run(); },\n isActive: () => { return editor.isActive('bold'); },\n },\n italic: {\n icon: FontAwesomeIcon,\n iconProp: faItalic,\n title: t('Italic'),\n action: () => { return editor.chain().focus().toggleItalic().run(); },\n isActive: () => { return editor.isActive('italic'); },\n },\n underline: {\n icon: FontAwesomeIcon,\n iconProp: faUnderline,\n title: t('Underline'),\n action: () => { return editor.chain().focus().toggleUnderline().run(); },\n isActive: () => { return editor.isActive('underline'); },\n },\n strikethrough: {\n icon: FontAwesomeIcon,\n iconProp: faStrikethrough,\n title: t('Strikethrough'),\n action: () => { return editor.chain().focus().toggleStrike().run(); },\n isActive: () => { return editor.isActive('strike'); },\n },\n subscript: {\n icon: FontAwesomeIcon,\n iconProp: faSubscript,\n title: t('Subscript'),\n action: () => { return editor.chain().focus().toggleSubscript().run(); },\n isActive: () => { return editor.isActive('subscript'); },\n },\n superscript: {\n icon: FontAwesomeIcon,\n iconProp: faSuperscript,\n title: t('Superscript'),\n action: () => { return editor.chain().focus().toggleSuperscript().run(); },\n isActive: () => { return editor.isActive('superscript'); },\n },\n 'unordered-list': {\n icon: FontAwesomeIcon,\n iconProp: faListUl,\n title: t('Bullet List'),\n action: () => { return editor.chain().focus().toggleBulletList().run(); },\n isActive: () => { return editor.isActive('bulletList'); },\n },\n 'ordered-list': {\n icon: FontAwesomeIcon,\n iconProp: faListOl,\n title: t('Ordered List'),\n action: () => { return editor.chain().focus().toggleOrderedList().run(); },\n isActive: () => { return editor.isActive('orderedList'); },\n },\n blockquote: {\n icon: FontAwesomeIcon,\n iconProp: faQuoteRight,\n title: t('Blockquote'),\n action: () => { return editor.chain().focus().toggleBlockquote().run(); },\n isActive: () => { return editor.isActive('blockquote'); },\n },\n highlight: {\n icon: FontAwesomeIcon,\n iconProp: faHighlighter,\n title: t('Highlight'),\n action: () => { return editor.chain().focus().toggleHighlight().run(); },\n isActive: () => { return editor.isActive('highlight'); },\n },\n code: {\n icon: FontAwesomeIcon,\n iconProp: faBracketsCurly,\n title: t('Inline Code'),\n action: () => { return editor.chain().focus().toggleCode().run(); },\n isActive: () => { return editor.isActive('code'); },\n },\n 'code-block': {\n icon: FontAwesomeIcon,\n iconProp: faCode,\n title: t('Code Block'),\n action: () => { return editor.chain().focus().toggleCodeBlock().run(); },\n isActive: () => { return editor.isActive('codeBlock'); },\n },\n hr: {\n icon: FontAwesomeIcon,\n iconProp: faMinus,\n title: t('Horizontal Rule'),\n action: () => { return editor.chain().focus().setHorizontalRule().run(); },\n },\n 'line-break': {\n icon: FontAwesomeIcon,\n iconProp: faFileDashedLine,\n title: t('Line Break'),\n action: () => { return editor.chain().focus().setHardBreak().run(); },\n },\n 'align-left': {\n icon: FontAwesomeIcon,\n iconProp: faAlignLeft,\n title: t('Align Left'),\n action: () => { return editor.chain().focus().setTextAlign('left').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'left' }); },\n },\n 'align-center': {\n icon: FontAwesomeIcon,\n iconProp: faAlignCenter,\n title: t('Align Center'),\n action: () => { return editor.chain().focus().setTextAlign('center').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'center' }); },\n },\n 'align-right': {\n icon: FontAwesomeIcon,\n iconProp: faAlignRight,\n title: t('Align Right'),\n action: () => { return editor.chain().focus().setTextAlign('right').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'right' }); },\n },\n 'align-justify': {\n icon: FontAwesomeIcon,\n iconProp: faAlignJustify,\n title: t('Justify'),\n action: () => { return editor.chain().focus().setTextAlign('justify').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'justify' }); },\n },\n 'clear-format': {\n icon: FontAwesomeIcon,\n iconProp: faTextSlash,\n title: t('Clear Format'),\n action: () => { return editor.chain().focus().clearNodes().unsetAllMarks().run(); },\n },\n undo: {\n icon: FontAwesomeIcon,\n iconProp: faArrowRotateLeft,\n title: t('Undo'),\n action: () => { return editor.chain().focus().undo().run(); },\n },\n redo: {\n icon: FontAwesomeIcon,\n iconProp: faArrowRotateRight,\n title: t('Redo'),\n action: () => { return editor.chain().focus().redo().run(); },\n },\n link: {\n title: t('Link'),\n isActive: () => { return editor.isActive('link'); },\n isDropdown: true,\n },\n table: {\n icon: FontAwesomeIcon,\n iconProp: faTable,\n title: t('Insert Table'),\n action: () => { return editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(); },\n },\n variableTag: {\n title: t('Insert Variable'),\n isActive: () => { return editor.isActive('variableTag'); },\n isDropdown: true,\n },\n };\n\n // Add heading levels h1–h6\n [1, 2, 3, 4, 5, 6].forEach((level) => {\n buttonConfig[`h${level}`] = {\n icon: FontAwesomeIcon,\n iconProp: {\n 1: faH1,\n 2: faH2,\n 3: faH3,\n 4: faH4,\n 5: faH5,\n 6: faH6,\n }[level],\n title: t('Heading {level}', { level: String(level) }),\n action: () => { return editor.chain().focus().toggleHeading({ level }).run(); },\n isActive: () => { return editor.isActive('heading', { level }); },\n };\n });\n\n const resolveIsActive = (config) => {\n if (!config.isActive) {\n return false;\n }\n return typeof config.isActive === 'function' ? config.isActive() : config.isActive;\n };\n\n const renderedButtons = visibleButtons\n .map((buttonName) => {\n const config = buttonConfig[buttonName];\n\n if (!config) { return null; }\n\n if (config.isDropdown && buttonName === 'link') {\n return (\n <LinkDropdown\n key={buttonName}\n editor={editor}\n linkOptions={linkOptions}\n linkSelectorStorageKeyPrefix={linkSelectorStorageKeyPrefix}\n openInsertLinkDialog={openInsertLinkDialog!}\n title={config.title}\n />\n );\n }\n\n if (config.isDropdown && buttonName === 'variableTag') {\n return (\n <VariableDropdown\n key={buttonName}\n editor={editor}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n title={config.title}\n open={variablePickerOpen}\n onOpenChange={onVariablePickerOpenChange}\n />\n );\n }\n\n const Icon = config.icon;\n\n return (\n <Tooltip key={buttonName}>\n <TooltipTrigger\n render={\n <Button\n variant=\"transparent\"\n onClick={config.action}\n className={cn(\n 'w-[32px] h-[32px]',\n 'text-[#1c2e36]',\n 'hover:bg-slate-100!',\n resolveIsActive(config) && 'bg-slate-250! hover:bg-slate-250!',\n )}\n >\n <Icon icon={config.iconProp} className=\"size-4\" />\n </Button>\n }\n />\n <TooltipContent sideOffset={4}>{config.title}</TooltipContent>\n </Tooltip>\n );\n })\n .filter(Boolean);\n\n if (renderedButtons.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\n 'flex flex-wrap relative z-10 gap-1 px-[8px] py-[4px]',\n 'border-b border-[rgba(96,125,159,0.4)] bg-white',\n 'shadow-[0_2px_3px_rgba(49,49,93,.07)]',\n )}>\n {renderedButtons}\n </div>\n );\n};\n\ntype TiptapEditorProps = {\n value?: unknown;\n onChange?: (value: unknown) => void;\n placeholder?: string;\n buttons?: string[];\n tableOptions?: Array<{ rows?: number; cols?: number; withHeaderRow?: boolean }>;\n linkOptions?: LinkOptionsInput;\n linkSelectorStorageKeyPrefix?: string;\n variableCategories?: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variableTransformerRegistry?: VariableTransformerRegistry;\n variablePickerTriggerCharacters?: string[];\n toolbarContent?: (params: {\n editor: TiptapEditorInstance | null;\n variableCategories: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variablePickerOpen: boolean;\n onVariablePickerOpenChange: (open: boolean) => void;\n }) => ReactNode;\n rows?: number;\n className?: string;\n isInvalid?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n invalidContentMessage?: string;\n [key: string]: unknown;\n};\n\nexport const TiptapEditor = ({\n value = '',\n onChange,\n buttons = ['bold', 'italic'],\n tableOptions = [],\n linkOptions,\n linkSelectorStorageKeyPrefix,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variableTransformerRegistry,\n variablePickerTriggerCharacters = ['@'],\n toolbarContent,\n rows,\n className,\n isInvalid,\n disabled = false,\n readOnly = false,\n invalidContentMessage,\n ...props\n}: TiptapEditorProps) => {\n // Ensure value is a string and handle null/undefined\n // const safeValue = value || '';\n const t = useTranslation();\n\n const wrapperRef = useRef<HTMLDivElement | null>(null);\n const handleKeyDownRef = useRef<import('./tiptap/useInlineVariablePicker').InlineVariablePickerHandleKeyDown | null>(null);\n\n const extensions = useMemo(() => {\n return createTiptapExtensions({ trailingCursorText: '\\u2060' });\n }, []);\n const [isVariablePickerOpen, setIsVariablePickerOpen] = useState(false);\n const hasAnyVariables = useMemo(() => {\n return Object.values(variableCategories || {}).some((variables) => {\n return Array.isArray(variables) && variables.length > 0;\n });\n }, [variableCategories]);\n const editorContent = useMemo(() => {\n return valueToContent(value, { trailingCursorText: '\\u2060' });\n }, [value]);\n const contentError = useMemo(() => {\n const detectedError = getFatalTiptapContentError(value);\n return detectedError ? (invalidContentMessage || detectedError) : '';\n }, [invalidContentMessage, value]);\n\n const serializeContent = (content: unknown) => {\n return normalizeContentArray(content);\n };\n\n const editor = useEditor({\n extensions,\n content: contentError ? null : editorContent,\n editable: !disabled && !readOnly,\n editorProps: {\n handleKeyDown: (view, event) => {\n return handleKeyDownRef.current?.(view, event) ?? false;\n },\n },\n onUpdate: ({ editor }) => {\n if (onChange) {\n onChange(serializeContent(editor.getJSON().content));\n }\n },\n });\n\n const inlinePicker = useInlineVariablePicker(editor, {\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerTriggerCharacters,\n disabled,\n readOnly,\n wrapperRef,\n onOpenDropdown: () => {\n return setIsVariablePickerOpen(true);\n },\n });\n\n useEffect(() => {\n handleKeyDownRef.current = inlinePicker.handleKeyDown;\n }, [inlinePicker.handleKeyDown]);\n\n const [insertLinkDialogOpen, setInsertLinkDialogOpen] = useState(false);\n const [insertLinkInitialValues, setInsertLinkInitialValues] = useState<{ url?: string; text?: string; openInNewTab?: boolean; from?: number; to?: number } | undefined>();\n const editorMinHeight = useMemo(() => {\n const normalizedRows = Math.max(1, Number(rows || 0));\n const lineHeight = 24;\n const verticalPadding = 32;\n\n return `${(normalizedRows * lineHeight) + verticalPadding}px`;\n }, [rows]);\n\n useEffect(() => {\n if (!editor?.view?.dom) {\n return;\n }\n\n editor.view.dom.style.minHeight = editorMinHeight;\n }, [editor, editorMinHeight]);\n\n const openInsertLinkDialog = useCallback((initial?: { url?: string; text?: string; from?: number; to?: number }) => {\n if (initial) {\n const openInNewTab = editor?.isActive('link') ? editor.getAttributes('link').target === '_blank' : false;\n setInsertLinkInitialValues({ ...initial, openInNewTab });\n } else {\n setInsertLinkInitialValues(undefined);\n }\n setInsertLinkDialogOpen(true);\n }, [editor]);\n\n const insertLink = useCallback(\n (params: { url: string; text: string; openInNewTab: boolean; from?: number; to?: number }) => {\n if (!editor) { return; }\n const {\n url, text, openInNewTab, from: fromParam, to: toParam,\n } = params;\n const chain = editor.chain().focus();\n const linkAttrs: { href: string; target?: string | null } = { href: url };\n if (openInNewTab) {\n linkAttrs.target = '_blank';\n }\n\n const content = {\n type: 'text',\n text: text.trim() || url,\n marks: [{ type: 'link', attrs: linkAttrs }],\n };\n\n if (typeof fromParam === 'number' && typeof toParam === 'number' && fromParam !== toParam) {\n chain.insertContentAt({ from: fromParam, to: toParam }, [content]).run();\n } else {\n const { from, to } = editor.state.selection;\n const selectedText = editor.state.doc.textBetween(from, to, ' ');\n if (selectedText) {\n chain.extendMarkRange('link').setLink(linkAttrs).run();\n } else {\n chain.insertContent([content]).run();\n }\n }\n },\n [editor],\n );\n\n // Watch for value changes and update editor content\n useEffect(() => {\n if (editor) {\n const newContent = contentError ? null : editorContent;\n const currentContent = editor.getJSON();\n\n // Only update if content has actually changed\n if (JSON.stringify(newContent) !== JSON.stringify(currentContent)) {\n editor.commands.setContent(newContent);\n }\n }\n }, [contentError, editor, editorContent]);\n\n const handleLinkBubbleEdit = useCallback(() => {\n if (!editor) { return; }\n const { href } = editor.getAttributes('link');\n const { state } = editor;\n const linkType = state.schema.marks.link;\n const range = getMarkRange(state.selection.$from, linkType);\n const from = range?.from ?? state.selection.from;\n const to = range?.to ?? state.selection.to;\n const text = editor.state.doc.textBetween(from, to, ' ');\n openInsertLinkDialog({\n url: href, text, from, to,\n });\n }, [editor, openInsertLinkDialog]);\n\n return (\n <div className={cn(\n 'border border-[rgba(96,125,159,0.4)] rounded-sm overflow-hidden',\n isInvalid && [\n 'border-rose-600!',\n '[focus-visible:shadow-[0_0_0_1px_var(--color-rose-600),0_0_4px_0_hsl(from_var(--color-rose-600)_h_s_l/0.7)]!',\n ],\n className,\n )}>\n <VariablePickerProvider\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variableTransformerRegistry={variableTransformerRegistry}\n >\n <EditorContext.Provider value={{ editor }}>\n {toolbarContent ? (\n toolbarContent({\n editor,\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerOpen: isVariablePickerOpen,\n onVariablePickerOpenChange: setIsVariablePickerOpen,\n })\n ) : (\n <MenuBar\n editor={editor}\n buttons={buttons}\n tableOptions={tableOptions}\n linkOptions={linkOptions}\n linkSelectorStorageKeyPrefix={linkSelectorStorageKeyPrefix}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variablePickerOpen={isVariablePickerOpen}\n onVariablePickerOpenChange={setIsVariablePickerOpen}\n openInsertLinkDialog={openInsertLinkDialog}\n />\n )}\n\n <div ref={wrapperRef} className=\"relative\">\n {contentError && (\n <div className=\"flex items-start gap-2 border-b border-rose-200 bg-rose-50 px-4 py-2 text-sm text-rose-800\">\n <FontAwesomeIcon icon={faTriangleExclamation} className=\"mt-0.5 size-3.5 shrink-0\" />\n <p>{contentError}</p>\n </div>\n )}\n\n <EditorContent\n editor={editor}\n className={cn(\n '[&_.ProseMirror]:outline-none',\n '[&_.ProseMirror]:min-h-8',\n '[&_.ProseMirror]:p-4',\n '[&_.ProseMirror]:bg-[#fbfcfe]',\n '[&_.ProseMirror]:shadow-none',\n '[&_.ProseMirror]:whitespace-pre-wrap',\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p]:mb-2',\n '[&_.ProseMirror_p:last-child]:mb-0',\n '[&_.ProseMirror_h1]:text-xl [&_.ProseMirror_h1]:font-bold [&_.ProseMirror_h1]:mb-2',\n '[&_.ProseMirror_h2]:text-lg [&_.ProseMirror_h2]:font-semibold [&_.ProseMirror_h2]:mb-2',\n '[&_.ProseMirror_ul]:list-disc [&_.ProseMirror_ul]:pl-5 [&_.ProseMirror_ul]:mb-2',\n '[&_.ProseMirror_ol]:list-decimal [&_.ProseMirror_ol]:pl-5 [&_.ProseMirror_ol]:mb-2',\n '[&_.ProseMirror_li]:mb-1',\n '[&_.ProseMirror_hr]:border-slate-300 [&_.ProseMirror_hr]:my-4',\n '[&_.ProseMirror_code]:bg-slate-100 [&_.ProseMirror_code]:px-1 [&_.ProseMirror_code]:py-0.5 [&_.ProseMirror_code]:rounded [&_.ProseMirror_code]:text-sm',\n '[&_.ProseMirror_pre]:bg-slate-100 [&_.ProseMirror_pre]:p-3 [&_.ProseMirror_pre]:rounded [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:mb-2',\n '[&_.ProseMirror_blockquote]:border-l-4 [&_.ProseMirror_blockquote]:border-slate-300 [&_.ProseMirror_blockquote]:pl-4 [&_.ProseMirror_blockquote]:italic [&_.ProseMirror_blockquote]:text-slate-600 [&_.ProseMirror_blockquote]:mb-2',\n '[&_.ProseMirror_table]:border-collapse [&_.ProseMirror_table]:w-full [&_.ProseMirror_table]:mb-2',\n '[&_.ProseMirror_th]:border [&_.ProseMirror_th]:border-slate-300 [&_.ProseMirror_th]:px-3 [&_.ProseMirror_th]:py-2 [&_.ProseMirror_th]:bg-slate-100 [&_.ProseMirror_th]:text-left',\n '[&_.ProseMirror_td]:border [&_.ProseMirror_td]:border-slate-300 [&_.ProseMirror_td]:px-3 [&_.ProseMirror_td]:py-2',\n '[&_.ProseMirror_a]:text-blue-600 [&_.ProseMirror_a]:underline [&_.ProseMirror_a]:cursor-pointer',\n )}\n {...props}\n />\n\n {hasAnyVariables && !readOnly && (\n <InlineVariablePickerPopover\n open={inlinePicker.state.open}\n onOpenChange={(open) => {\n if (!open) {\n inlinePicker.closePicker();\n }\n }}\n position={{ top: inlinePicker.state.top, left: inlinePicker.state.left }}\n isChildMode={inlinePicker.filteredVariables.isChildMode}\n query={inlinePicker.state.query}\n onQueryChange={inlinePicker.setQuery}\n filteredVariables={inlinePicker.filteredVariables}\n onSelect={inlinePicker.handleSelect}\n onBack={inlinePicker.goBack}\n />\n )}\n </div>\n\n {buttons.includes('link') && editor && (\n <LinkBubbleMenu\n editor={editor}\n onEdit={handleLinkBubbleEdit}\n dialogOpen={insertLinkDialogOpen}\n />\n )}\n </EditorContext.Provider>\n\n <InsertLinkDialog\n open={insertLinkDialogOpen}\n onOpenChange={setInsertLinkDialogOpen}\n initialValues={insertLinkInitialValues}\n onInsert={(values) => {\n insertLink({\n ...values,\n from: insertLinkInitialValues?.from,\n to: insertLinkInitialValues?.to,\n });\n setInsertLinkDialogOpen(false);\n }}\n />\n </VariablePickerProvider>\n </div >\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"TiptapEditor.js","names":[],"sources":["../../src/components/TiptapEditor.tsx"],"sourcesContent":["import {\n useEffect, useCallback, useMemo, useRef, useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport { useEditor, EditorContent, EditorContext } from '@tiptap/react';\nimport { getMarkRange, type Editor as TiptapEditorInstance } from '@tiptap/core';\n\nimport { Button } from '@verbb/plugin-kit-react/components';\nimport { LinkDropdown } from './tiptap/LinkDropdown';\nimport type { LinkOptions, LinkOptionsInput } from './tiptap/LinkDropdown';\nimport { VariableDropdown } from './tiptap/VariableDropdown';\nimport type { VariableOption, VariableCategories } from './tiptap/VariableDropdown';\nimport type { VariableTransformerRegistry, VariableConfigureSectionProps, VariableTagLabelResolver } from './tiptap/VariablePickerContext';\nimport { VariablePickerProvider } from './tiptap/VariablePickerContext';\nimport { InlineVariablePickerPopover } from './tiptap/InlineVariablePickerPopover';\nimport { useInlineVariablePicker } from './tiptap/useInlineVariablePicker';\n\nexport type {\n LinkOptions, LinkOptionsInput, VariableOption, VariableCategories,\n};\nimport { LinkBubbleMenu } from './tiptap/LinkBubbleMenu';\nimport { InsertLinkDialog } from './tiptap/InsertLinkDialog';\n\nimport {\n createTiptapExtensions,\n getFatalTiptapContentError,\n normalizeContentArray,\n valueToContent,\n} from './tiptap/editorConfig';\n\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\n\nimport {\n faAlignCenter,\n faAlignJustify,\n faAlignLeft,\n faAlignRight,\n faArrowRotateLeft,\n faArrowRotateRight,\n faBold,\n faBracketsCurly,\n faCode,\n faH1,\n faH2,\n faH3,\n faH4,\n faH5,\n faH6,\n faHighlighter,\n faItalic,\n faListOl,\n faListUl,\n faMinus,\n faQuoteRight,\n faStrikethrough,\n faSubscript,\n faSuperscript,\n faTriangleExclamation,\n\n faUnderline,\n faTextSlash,\n} from '@fortawesome/pro-solid-svg-icons';\n\nimport {\n faFileDashedLine,\n faTable,\n} from '@fortawesome/pro-regular-svg-icons';\n\nimport { cn } from '@verbb/plugin-kit-react/utils';\nimport { useTranslation } from '@verbb/plugin-kit-react/hooks';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@verbb/plugin-kit-react/components/Tooltip';\n\nconst MenuBar = ({\n editor,\n buttons = ['bold', 'italic'],\n linkOptions,\n linkSelectorStorageKeyPrefix,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerOpen,\n onVariablePickerOpenChange,\n openInsertLinkDialog,\n}: {\n editor: TiptapEditorInstance | null | undefined;\n buttons?: string[];\n linkOptions?: LinkOptionsInput;\n linkSelectorStorageKeyPrefix?: string;\n variableCategories?: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variablePickerOpen?: boolean;\n onVariablePickerOpenChange?: (open: boolean) => void;\n openInsertLinkDialog?: (initial?: { url?: string; text?: string; from?: number; to?: number }) => void;\n}) => {\n const t = useTranslation();\n\n if (!editor) {\n return null;\n }\n\n const hasAnyVariables = Object.values(variableCategories ?? {}).some(\n items => {\n return Array.isArray(items) && items.length > 0;\n },\n );\n\n const visibleButtons = buttons.filter((buttonName) => {\n if (buttonName === 'variableTag') {\n return hasAnyVariables;\n }\n\n return true;\n });\n\n const buttonConfig = {\n bold: {\n icon: FontAwesomeIcon,\n iconProp: faBold,\n title: t('Bold'),\n action: () => { return editor.chain().focus().toggleBold().run(); },\n isActive: () => { return editor.isActive('bold'); },\n },\n italic: {\n icon: FontAwesomeIcon,\n iconProp: faItalic,\n title: t('Italic'),\n action: () => { return editor.chain().focus().toggleItalic().run(); },\n isActive: () => { return editor.isActive('italic'); },\n },\n underline: {\n icon: FontAwesomeIcon,\n iconProp: faUnderline,\n title: t('Underline'),\n action: () => { return editor.chain().focus().toggleUnderline().run(); },\n isActive: () => { return editor.isActive('underline'); },\n },\n strikethrough: {\n icon: FontAwesomeIcon,\n iconProp: faStrikethrough,\n title: t('Strikethrough'),\n action: () => { return editor.chain().focus().toggleStrike().run(); },\n isActive: () => { return editor.isActive('strike'); },\n },\n subscript: {\n icon: FontAwesomeIcon,\n iconProp: faSubscript,\n title: t('Subscript'),\n action: () => { return editor.chain().focus().toggleSubscript().run(); },\n isActive: () => { return editor.isActive('subscript'); },\n },\n superscript: {\n icon: FontAwesomeIcon,\n iconProp: faSuperscript,\n title: t('Superscript'),\n action: () => { return editor.chain().focus().toggleSuperscript().run(); },\n isActive: () => { return editor.isActive('superscript'); },\n },\n 'unordered-list': {\n icon: FontAwesomeIcon,\n iconProp: faListUl,\n title: t('Bullet List'),\n action: () => { return editor.chain().focus().toggleBulletList().run(); },\n isActive: () => { return editor.isActive('bulletList'); },\n },\n 'ordered-list': {\n icon: FontAwesomeIcon,\n iconProp: faListOl,\n title: t('Ordered List'),\n action: () => { return editor.chain().focus().toggleOrderedList().run(); },\n isActive: () => { return editor.isActive('orderedList'); },\n },\n blockquote: {\n icon: FontAwesomeIcon,\n iconProp: faQuoteRight,\n title: t('Blockquote'),\n action: () => { return editor.chain().focus().toggleBlockquote().run(); },\n isActive: () => { return editor.isActive('blockquote'); },\n },\n highlight: {\n icon: FontAwesomeIcon,\n iconProp: faHighlighter,\n title: t('Highlight'),\n action: () => { return editor.chain().focus().toggleHighlight().run(); },\n isActive: () => { return editor.isActive('highlight'); },\n },\n code: {\n icon: FontAwesomeIcon,\n iconProp: faBracketsCurly,\n title: t('Inline Code'),\n action: () => { return editor.chain().focus().toggleCode().run(); },\n isActive: () => { return editor.isActive('code'); },\n },\n 'code-block': {\n icon: FontAwesomeIcon,\n iconProp: faCode,\n title: t('Code Block'),\n action: () => { return editor.chain().focus().toggleCodeBlock().run(); },\n isActive: () => { return editor.isActive('codeBlock'); },\n },\n hr: {\n icon: FontAwesomeIcon,\n iconProp: faMinus,\n title: t('Horizontal Rule'),\n action: () => { return editor.chain().focus().setHorizontalRule().run(); },\n },\n 'line-break': {\n icon: FontAwesomeIcon,\n iconProp: faFileDashedLine,\n title: t('Line Break'),\n action: () => { return editor.chain().focus().setHardBreak().run(); },\n },\n 'align-left': {\n icon: FontAwesomeIcon,\n iconProp: faAlignLeft,\n title: t('Align Left'),\n action: () => { return editor.chain().focus().setTextAlign('left').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'left' }); },\n },\n 'align-center': {\n icon: FontAwesomeIcon,\n iconProp: faAlignCenter,\n title: t('Align Center'),\n action: () => { return editor.chain().focus().setTextAlign('center').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'center' }); },\n },\n 'align-right': {\n icon: FontAwesomeIcon,\n iconProp: faAlignRight,\n title: t('Align Right'),\n action: () => { return editor.chain().focus().setTextAlign('right').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'right' }); },\n },\n 'align-justify': {\n icon: FontAwesomeIcon,\n iconProp: faAlignJustify,\n title: t('Justify'),\n action: () => { return editor.chain().focus().setTextAlign('justify').run(); },\n isActive: () => { return editor.isActive({ textAlign: 'justify' }); },\n },\n 'clear-format': {\n icon: FontAwesomeIcon,\n iconProp: faTextSlash,\n title: t('Clear Format'),\n action: () => { return editor.chain().focus().clearNodes().unsetAllMarks().run(); },\n },\n undo: {\n icon: FontAwesomeIcon,\n iconProp: faArrowRotateLeft,\n title: t('Undo'),\n action: () => { return editor.chain().focus().undo().run(); },\n },\n redo: {\n icon: FontAwesomeIcon,\n iconProp: faArrowRotateRight,\n title: t('Redo'),\n action: () => { return editor.chain().focus().redo().run(); },\n },\n link: {\n title: t('Link'),\n isActive: () => { return editor.isActive('link'); },\n isDropdown: true,\n },\n table: {\n icon: FontAwesomeIcon,\n iconProp: faTable,\n title: t('Insert Table'),\n action: () => { return editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(); },\n },\n variableTag: {\n title: t('Insert Variable'),\n isActive: () => { return editor.isActive('variableTag'); },\n isDropdown: true,\n },\n };\n\n // Add heading levels h1–h6\n [1, 2, 3, 4, 5, 6].forEach((level) => {\n buttonConfig[`h${level}`] = {\n icon: FontAwesomeIcon,\n iconProp: {\n 1: faH1,\n 2: faH2,\n 3: faH3,\n 4: faH4,\n 5: faH5,\n 6: faH6,\n }[level],\n title: t('Heading {level}', { level: String(level) }),\n action: () => { return editor.chain().focus().toggleHeading({ level }).run(); },\n isActive: () => { return editor.isActive('heading', { level }); },\n };\n });\n\n const resolveIsActive = (config) => {\n if (!config.isActive) {\n return false;\n }\n return typeof config.isActive === 'function' ? config.isActive() : config.isActive;\n };\n\n const renderedButtons = visibleButtons\n .map((buttonName) => {\n const config = buttonConfig[buttonName];\n\n if (!config) { return null; }\n\n if (config.isDropdown && buttonName === 'link') {\n return (\n <LinkDropdown\n key={buttonName}\n editor={editor}\n linkOptions={linkOptions}\n linkSelectorStorageKeyPrefix={linkSelectorStorageKeyPrefix}\n openInsertLinkDialog={openInsertLinkDialog!}\n title={config.title}\n />\n );\n }\n\n if (config.isDropdown && buttonName === 'variableTag') {\n return (\n <VariableDropdown\n key={buttonName}\n editor={editor}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n title={config.title}\n open={variablePickerOpen}\n onOpenChange={onVariablePickerOpenChange}\n />\n );\n }\n\n const Icon = config.icon;\n\n return (\n <Tooltip key={buttonName}>\n <TooltipTrigger\n render={\n <Button\n variant=\"transparent\"\n onClick={config.action}\n className={cn(\n 'w-[32px] h-[32px]',\n 'text-[#1c2e36]',\n 'hover:bg-slate-100!',\n resolveIsActive(config) && 'bg-slate-250! hover:bg-slate-250!',\n )}\n >\n <Icon icon={config.iconProp} className=\"size-4\" />\n </Button>\n }\n />\n <TooltipContent sideOffset={4}>{config.title}</TooltipContent>\n </Tooltip>\n );\n })\n .filter(Boolean);\n\n if (renderedButtons.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\n 'flex flex-wrap relative z-10 gap-1 px-[8px] py-[4px]',\n 'border-b border-[rgba(96,125,159,0.4)] bg-white',\n 'shadow-[0_2px_3px_rgba(49,49,93,.07)]',\n )}>\n {renderedButtons}\n </div>\n );\n};\n\ntype TiptapEditorProps = {\n value?: unknown;\n onChange?: (value: unknown) => void;\n placeholder?: string;\n buttons?: string[];\n tableOptions?: Array<{ rows?: number; cols?: number; withHeaderRow?: boolean }>;\n linkOptions?: LinkOptionsInput;\n linkSelectorStorageKeyPrefix?: string;\n variableCategories?: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variableTransformerRegistry?: VariableTransformerRegistry;\n variablePickerTriggerCharacters?: string[];\n renderVariableConfigureSection?: (props: VariableConfigureSectionProps) => ReactNode;\n resolveVariableTagLabel?: VariableTagLabelResolver;\n toolbarContent?: (params: {\n editor: TiptapEditorInstance | null;\n variableCategories: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variablePickerOpen: boolean;\n onVariablePickerOpenChange: (open: boolean) => void;\n }) => ReactNode;\n rows?: number;\n className?: string;\n isInvalid?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n invalidContentMessage?: string;\n [key: string]: unknown;\n};\n\nexport const TiptapEditor = ({\n value = '',\n onChange,\n buttons = ['bold', 'italic'],\n tableOptions = [],\n linkOptions,\n linkSelectorStorageKeyPrefix,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variableTransformerRegistry,\n variablePickerTriggerCharacters = ['@'],\n renderVariableConfigureSection,\n resolveVariableTagLabel,\n toolbarContent,\n rows,\n className,\n isInvalid,\n disabled = false,\n readOnly = false,\n invalidContentMessage,\n ...props\n}: TiptapEditorProps) => {\n // Ensure value is a string and handle null/undefined\n // const safeValue = value || '';\n const t = useTranslation();\n\n const wrapperRef = useRef<HTMLDivElement | null>(null);\n const handleKeyDownRef = useRef<import('./tiptap/useInlineVariablePicker').InlineVariablePickerHandleKeyDown | null>(null);\n const lastEmittedContentRef = useRef<string | null>(null);\n\n const extensions = useMemo(() => {\n return createTiptapExtensions({ trailingCursorText: '\\u2060' });\n }, []);\n const [isVariablePickerOpen, setIsVariablePickerOpen] = useState(false);\n const hasAnyVariables = useMemo(() => {\n return Object.values(variableCategories || {}).some((variables) => {\n return Array.isArray(variables) && variables.length > 0;\n });\n }, [variableCategories]);\n const editorContent = useMemo(() => {\n return valueToContent(value, { trailingCursorText: '\\u2060' });\n }, [value]);\n const contentError = useMemo(() => {\n const detectedError = getFatalTiptapContentError(value);\n return detectedError ? (invalidContentMessage || detectedError) : '';\n }, [invalidContentMessage, value]);\n\n const serializeContent = (content: unknown) => {\n return normalizeContentArray(content);\n };\n\n const serializeEditorDocument = useCallback((editorInstance: NonNullable<ReturnType<typeof useEditor>>) => {\n return JSON.stringify(serializeContent(editorInstance.getJSON().content));\n }, []);\n\n const editor = useEditor({\n extensions,\n content: contentError ? null : editorContent,\n editable: !disabled && !readOnly,\n editorProps: {\n handleKeyDown: (view, event) => {\n return handleKeyDownRef.current?.(view, event) ?? false;\n },\n },\n onUpdate: ({ editor: editorInstance }) => {\n const serialized = serializeContent(editorInstance.getJSON().content);\n lastEmittedContentRef.current = JSON.stringify(serialized);\n\n if (onChange) {\n onChange(serialized);\n }\n },\n });\n\n const inlinePicker = useInlineVariablePicker(editor, {\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerTriggerCharacters,\n disabled,\n readOnly,\n wrapperRef,\n onOpenDropdown: () => {\n return setIsVariablePickerOpen(true);\n },\n });\n\n useEffect(() => {\n handleKeyDownRef.current = inlinePicker.handleKeyDown;\n }, [inlinePicker.handleKeyDown]);\n\n const [insertLinkDialogOpen, setInsertLinkDialogOpen] = useState(false);\n const [insertLinkInitialValues, setInsertLinkInitialValues] = useState<{ url?: string; text?: string; openInNewTab?: boolean; from?: number; to?: number } | undefined>();\n const editorMinHeight = useMemo(() => {\n const normalizedRows = Math.max(1, Number(rows || 0));\n const lineHeight = 24;\n const verticalPadding = 32;\n\n return `${(normalizedRows * lineHeight) + verticalPadding}px`;\n }, [rows]);\n\n useEffect(() => {\n if (!editor?.view?.dom) {\n return;\n }\n\n editor.view.dom.style.minHeight = editorMinHeight;\n }, [editor, editorMinHeight]);\n\n const openInsertLinkDialog = useCallback((initial?: { url?: string; text?: string; from?: number; to?: number }) => {\n if (initial) {\n const openInNewTab = editor?.isActive('link') ? editor.getAttributes('link').target === '_blank' : false;\n setInsertLinkInitialValues({ ...initial, openInNewTab });\n } else {\n setInsertLinkInitialValues(undefined);\n }\n setInsertLinkDialogOpen(true);\n }, [editor]);\n\n const insertLink = useCallback(\n (params: { url: string; text: string; openInNewTab: boolean; from?: number; to?: number }) => {\n if (!editor) { return; }\n const {\n url, text, openInNewTab, from: fromParam, to: toParam,\n } = params;\n const chain = editor.chain().focus();\n const linkAttrs: { href: string; target?: string | null } = { href: url };\n if (openInNewTab) {\n linkAttrs.target = '_blank';\n }\n\n const content = {\n type: 'text',\n text: text.trim() || url,\n marks: [{ type: 'link', attrs: linkAttrs }],\n };\n\n if (typeof fromParam === 'number' && typeof toParam === 'number' && fromParam !== toParam) {\n chain.insertContentAt({ from: fromParam, to: toParam }, [content]).run();\n } else {\n const { from, to } = editor.state.selection;\n const selectedText = editor.state.doc.textBetween(from, to, ' ');\n if (selectedText) {\n chain.extendMarkRange('link').setLink(linkAttrs).run();\n } else {\n chain.insertContent([content]).run();\n }\n }\n },\n [editor],\n );\n\n // Watch for value changes and update editor content\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const incomingContent = contentError ? null : editorContent;\n const incomingSerialized = JSON.stringify(incomingContent?.content ?? []);\n const currentSerialized = serializeEditorDocument(editor);\n const isVariableConfigActive = Boolean(\n document.activeElement?.closest('[data-variable-config-popover]'),\n );\n\n if (incomingSerialized === currentSerialized) {\n return;\n }\n\n if (lastEmittedContentRef.current === incomingSerialized) {\n return;\n }\n\n if (\n !readOnly\n && (\n editor.isFocused\n || isVariableConfigActive\n || (\n lastEmittedContentRef.current\n && currentSerialized === lastEmittedContentRef.current\n && incomingSerialized !== lastEmittedContentRef.current\n )\n )\n ) {\n return;\n }\n\n editor.commands.setContent(incomingContent ?? { type: 'doc', content: [] });\n lastEmittedContentRef.current = incomingSerialized;\n }, [contentError, editor, editorContent, readOnly, serializeEditorDocument]);\n\n const handleLinkBubbleEdit = useCallback(() => {\n if (!editor) { return; }\n const { href } = editor.getAttributes('link');\n const { state } = editor;\n const linkType = state.schema.marks.link;\n const range = getMarkRange(state.selection.$from, linkType);\n const from = range?.from ?? state.selection.from;\n const to = range?.to ?? state.selection.to;\n const text = editor.state.doc.textBetween(from, to, ' ');\n openInsertLinkDialog({\n url: href, text, from, to,\n });\n }, [editor, openInsertLinkDialog]);\n\n return (\n <div className={cn(\n 'border border-[rgba(96,125,159,0.4)] rounded-sm overflow-hidden',\n isInvalid && [\n 'border-rose-600!',\n '[focus-visible:shadow-[0_0_0_1px_var(--color-rose-600),0_0_4px_0_hsl(from_var(--color-rose-600)_h_s_l/0.7)]!',\n ],\n className,\n )}>\n <VariablePickerProvider\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variableTransformerRegistry={variableTransformerRegistry}\n renderVariableConfigureSection={renderVariableConfigureSection}\n resolveVariableTagLabel={resolveVariableTagLabel}\n >\n <EditorContext.Provider value={{ editor }}>\n {toolbarContent ? (\n toolbarContent({\n editor,\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerOpen: isVariablePickerOpen,\n onVariablePickerOpenChange: setIsVariablePickerOpen,\n })\n ) : (\n <MenuBar\n editor={editor}\n buttons={buttons}\n tableOptions={tableOptions}\n linkOptions={linkOptions}\n linkSelectorStorageKeyPrefix={linkSelectorStorageKeyPrefix}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variablePickerOpen={isVariablePickerOpen}\n onVariablePickerOpenChange={setIsVariablePickerOpen}\n openInsertLinkDialog={openInsertLinkDialog}\n />\n )}\n\n <div ref={wrapperRef} className=\"relative\">\n {contentError && (\n <div className=\"flex items-start gap-2 border-b border-rose-200 bg-rose-50 px-4 py-2 text-sm text-rose-800\">\n <FontAwesomeIcon icon={faTriangleExclamation} className=\"mt-0.5 size-3.5 shrink-0\" />\n <p>{contentError}</p>\n </div>\n )}\n\n <EditorContent\n editor={editor}\n className={cn(\n '[&_.ProseMirror]:outline-none',\n '[&_.ProseMirror]:min-h-8',\n '[&_.ProseMirror]:p-4',\n '[&_.ProseMirror]:bg-[#fbfcfe]',\n '[&_.ProseMirror]:shadow-none',\n '[&_.ProseMirror]:whitespace-pre-wrap',\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p]:mb-2',\n '[&_.ProseMirror_p:last-child]:mb-0',\n '[&_.ProseMirror_h1]:text-xl [&_.ProseMirror_h1]:font-bold [&_.ProseMirror_h1]:mb-2',\n '[&_.ProseMirror_h2]:text-lg [&_.ProseMirror_h2]:font-semibold [&_.ProseMirror_h2]:mb-2',\n '[&_.ProseMirror_ul]:list-disc [&_.ProseMirror_ul]:pl-5 [&_.ProseMirror_ul]:mb-2',\n '[&_.ProseMirror_ol]:list-decimal [&_.ProseMirror_ol]:pl-5 [&_.ProseMirror_ol]:mb-2',\n '[&_.ProseMirror_li]:mb-1',\n '[&_.ProseMirror_hr]:border-slate-300 [&_.ProseMirror_hr]:my-4',\n '[&_.ProseMirror_code]:bg-slate-100 [&_.ProseMirror_code]:px-1 [&_.ProseMirror_code]:py-0.5 [&_.ProseMirror_code]:rounded [&_.ProseMirror_code]:text-sm',\n '[&_.ProseMirror_pre]:bg-slate-100 [&_.ProseMirror_pre]:p-3 [&_.ProseMirror_pre]:rounded [&_.ProseMirror_pre]:overflow-x-auto [&_.ProseMirror_pre]:mb-2',\n '[&_.ProseMirror_blockquote]:border-l-4 [&_.ProseMirror_blockquote]:border-slate-300 [&_.ProseMirror_blockquote]:pl-4 [&_.ProseMirror_blockquote]:italic [&_.ProseMirror_blockquote]:text-slate-600 [&_.ProseMirror_blockquote]:mb-2',\n '[&_.ProseMirror_table]:border-collapse [&_.ProseMirror_table]:w-full [&_.ProseMirror_table]:mb-2',\n '[&_.ProseMirror_th]:border [&_.ProseMirror_th]:border-slate-300 [&_.ProseMirror_th]:px-3 [&_.ProseMirror_th]:py-2 [&_.ProseMirror_th]:bg-slate-100 [&_.ProseMirror_th]:text-left',\n '[&_.ProseMirror_td]:border [&_.ProseMirror_td]:border-slate-300 [&_.ProseMirror_td]:px-3 [&_.ProseMirror_td]:py-2',\n '[&_.ProseMirror_a]:text-blue-600 [&_.ProseMirror_a]:underline [&_.ProseMirror_a]:cursor-pointer',\n )}\n {...props}\n />\n\n {hasAnyVariables && !readOnly && (\n <InlineVariablePickerPopover\n open={inlinePicker.state.open}\n onOpenChange={(open) => {\n if (!open) {\n inlinePicker.closePicker();\n }\n }}\n position={{ top: inlinePicker.state.top, left: inlinePicker.state.left }}\n isChildMode={inlinePicker.filteredVariables.isChildMode}\n query={inlinePicker.state.query}\n onQueryChange={inlinePicker.setQuery}\n filteredVariables={inlinePicker.filteredVariables}\n onSelect={inlinePicker.handleSelect}\n onBack={inlinePicker.goBack}\n />\n )}\n </div>\n\n {buttons.includes('link') && editor && (\n <LinkBubbleMenu\n editor={editor}\n onEdit={handleLinkBubbleEdit}\n dialogOpen={insertLinkDialogOpen}\n />\n )}\n </EditorContext.Provider>\n\n <InsertLinkDialog\n open={insertLinkDialogOpen}\n onOpenChange={setInsertLinkDialogOpen}\n initialValues={insertLinkInitialValues}\n onInsert={(values) => {\n insertLink({\n ...values,\n from: insertLinkInitialValues?.from,\n to: insertLinkInitialValues?.to,\n });\n setInsertLinkDialogOpen(false);\n }}\n />\n </VariablePickerProvider>\n </div >\n );\n};\n"],"mappings":"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"}
@@ -1,15 +1,20 @@
1
- export declare const TiptapInput: ({ value, onChange, className, isInvalid, disabled, readOnly, variableCategories, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters, ...props }: {
2
- [x: string]: any;
3
- value?: string | undefined;
4
- onChange: any;
5
- className: any;
6
- isInvalid: any;
7
- disabled?: boolean | undefined;
8
- readOnly?: boolean | undefined;
9
- variableCategories?: {} | undefined;
10
- variableCategoryLabels: any;
11
- variableCategoryOrder: any;
12
- variableTransformerRegistry: any;
13
- variablePickerTriggerCharacters?: string[] | undefined;
1
+ import { ReactNode } from 'react';
2
+ import { VariableCategories } from './tiptap/VariableDropdown';
3
+ import { VariableConfigureSectionProps, VariableTransformerRegistry, VariableTagLabelResolver } from './tiptap/VariablePickerContext';
4
+ export declare const TiptapInput: ({ value, onChange, className, isInvalid, disabled, readOnly, variableCategories, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters, renderVariableConfigureSection, resolveVariableTagLabel, ...props }: {
5
+ value?: string;
6
+ onChange?: (value: string) => void;
7
+ className?: string;
8
+ isInvalid?: boolean;
9
+ disabled?: boolean;
10
+ readOnly?: boolean;
11
+ variableCategories?: VariableCategories;
12
+ variableCategoryLabels?: Record<string, string>;
13
+ variableCategoryOrder?: string[];
14
+ variableTransformerRegistry?: VariableTransformerRegistry;
15
+ variablePickerTriggerCharacters?: string[];
16
+ renderVariableConfigureSection?: (props: VariableConfigureSectionProps) => ReactNode;
17
+ resolveVariableTagLabel?: VariableTagLabelResolver;
18
+ [key: string]: unknown;
14
19
  }) => import("react/jsx-runtime").JSX.Element;
15
20
  //# sourceMappingURL=TiptapInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TiptapInput.d.ts","sourceRoot":"","sources":["../../src/components/TiptapInput.tsx"],"names":[],"mappings":"AAyBA,eAAO,MAAM,WAAW,GAAI;;;;;;;;;;;;;CAa3B,4CAgJA,CAAC"}
1
+ {"version":3,"file":"TiptapInput.d.ts","sourceRoot":"","sources":["../../src/components/TiptapInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4DAA4D,CAAC;AACrG,OAAO,KAAK,EAAE,6BAA6B,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,MAAM,iEAAiE,CAAC;AAiB5K,eAAO,MAAM,WAAW,GAAI,mQAezB;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,+BAA+B,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3C,8BAA8B,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,SAAS,CAAC;IACrF,uBAAuB,CAAC,EAAE,wBAAwB,CAAC;IACnD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,4CAkJA,CAAC"}
@@ -13,7 +13,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  import { EditorContent, useEditor } from "@tiptap/react";
14
14
  //#region src/components/TiptapInput.tsx
15
15
  var OneLinerDocument = Document.extend({ content: "inline*" });
16
- var TiptapInput = ({ value = "", onChange, className, isInvalid, disabled = false, readOnly = false, variableCategories = {}, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters = ["@"], ...props }) => {
16
+ var TiptapInput = ({ value = "", onChange, className, isInvalid, disabled = false, readOnly = false, variableCategories = {}, variableCategoryLabels, variableCategoryOrder, variableTransformerRegistry, variablePickerTriggerCharacters = ["@"], renderVariableConfigureSection, resolveVariableTagLabel, ...props }) => {
17
17
  const wrapperRef = useRef(null);
18
18
  const [isVariablePickerOpen, setIsVariablePickerOpen] = useState(false);
19
19
  const handleKeyDownRef = useRef(null);
@@ -82,6 +82,8 @@ var TiptapInput = ({ value = "", onChange, className, isInvalid, disabled = fals
82
82
  variableCategoryLabels,
83
83
  variableCategoryOrder,
84
84
  variableTransformerRegistry,
85
+ renderVariableConfigureSection,
86
+ resolveVariableTagLabel,
85
87
  children: /* @__PURE__ */ jsxs("div", {
86
88
  ref: wrapperRef,
87
89
  className: cn("relative", className),
@@ -1 +1 @@
1
- {"version":3,"file":"TiptapInput.js","names":[],"sources":["../../src/components/TiptapInput.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { useEditor, EditorContent } from '@tiptap/react';\n\nimport Document from '@tiptap/extension-document';\nimport Text from '@tiptap/extension-text';\n\nimport VariableTag from '@verbb/plugin-kit-react/components/tiptap/VariableTag';\nimport { VariableDropdown } from '@verbb/plugin-kit-react/components/tiptap/VariableDropdown';\nimport type { VariableTransformerRegistry } from '@verbb/plugin-kit-react/components/tiptap/VariablePickerContext';\nimport { VariablePickerProvider } from '@verbb/plugin-kit-react/components/tiptap/VariablePickerContext';\nimport { InlineVariablePickerPopover } from '@verbb/plugin-kit-react/components/tiptap/InlineVariablePickerPopover';\nimport { useInlineVariablePicker } from '@verbb/plugin-kit-react/components/tiptap/useInlineVariablePicker';\nimport {\n contentToValue,\n dedupeVariableOptions,\n flattenVariableOptions,\n valueToContent,\n} from '@verbb/plugin-kit-react/components/tiptap/variableSerialization';\n\nimport { cn } from '@verbb/plugin-kit-react/utils';\n\nconst OneLinerDocument = Document.extend({\n content: 'inline*',\n});\n\nexport const TiptapInput = ({\n value = '',\n onChange,\n className,\n isInvalid,\n disabled = false,\n readOnly = false,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variableTransformerRegistry,\n variablePickerTriggerCharacters = ['@'],\n ...props\n}) => {\n const wrapperRef = useRef<HTMLDivElement | null>(null);\n const [isVariablePickerOpen, setIsVariablePickerOpen] = useState(false);\n const handleKeyDownRef = useRef<import('./tiptap/useInlineVariablePicker').InlineVariablePickerHandleKeyDown | null>(null);\n\n const topLevelVariables = useMemo(() => {\n const values = Object.values(variableCategories ?? {}).flatMap(items => {\n return Array.isArray(items) ? items : [];\n },\n );\n return dedupeVariableOptions(values);\n }, [variableCategories]);\n\n const variables = useMemo(() => {\n return flattenVariableOptions(topLevelVariables);\n }, [topLevelVariables]);\n\n const extensions = useMemo(\n () => {\n return [OneLinerDocument, Text, VariableTag.configure({})];\n },\n [],\n );\n\n const editor = useEditor({\n extensions,\n content: valueToContent(value, topLevelVariables, variables) as Parameters<typeof useEditor>[0]['content'],\n editable: !disabled && !readOnly,\n editorProps: {\n handleKeyDown: (view, event) => {\n return handleKeyDownRef.current?.(view, event) ?? false;\n },\n } as Parameters<typeof useEditor>[0]['editorProps'],\n onUpdate: ({ editor: ed }) => {\n if (onChange) {\n onChange(contentToValue(ed.getJSON().content));\n }\n },\n });\n\n const inlinePicker = useInlineVariablePicker(editor, {\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerTriggerCharacters,\n disabled,\n readOnly,\n wrapperRef,\n onOpenDropdown: () => {\n return setIsVariablePickerOpen(true);\n },\n });\n\n useEffect(() => {\n handleKeyDownRef.current = inlinePicker.handleKeyDown;\n }, [inlinePicker.handleKeyDown]);\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n if (!readOnly && editor.isFocused) {\n return;\n }\n\n const newContent = valueToContent(value, topLevelVariables, variables);\n const currentContent = editor.getJSON();\n if (JSON.stringify(newContent) !== JSON.stringify(currentContent)) {\n queueMicrotask(() => {\n const content = newContent ?? { type: 'doc' as const, content: [] as const };\n editor.commands.setContent(content);\n });\n }\n }, [editor, value, readOnly, topLevelVariables, variables]);\n\n const hasVariables = variables.length > 0;\n\n return (\n <VariablePickerProvider\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variableTransformerRegistry={variableTransformerRegistry as VariableTransformerRegistry | undefined}\n >\n <div ref={wrapperRef} className={cn('relative', className)}>\n <EditorContent\n editor={editor}\n className={cn(\n !readOnly && [\n '[&_.ProseMirror]:outline-none [&_.ProseMirror]:bg-clip-padding',\n '[&_.ProseMirror]:rounded-sm',\n '[&_.ProseMirror]:border [&_.ProseMirror]:border-[rgba(96,125,159,0.4)]',\n '[&_.ProseMirror]:bg-[rgb(251,252,254)]',\n '[&_.ProseMirror]:whitespace-pre-wrap',\n '[&_.ProseMirror]:w-full [&_.ProseMirror]:h-[34px] [&_.ProseMirror]:px-2 [&_.ProseMirror]:pr-10 [&_.ProseMirror]:pt-[6px] [&_.ProseMirror]:text-sm',\n '[&_.ProseMirror]:whitespace-nowrap [&_.ProseMirror]:overflow-x-auto [&_.ProseMirror]:overflow-y-hidden',\n '[&_.ProseMirror]:[scrollbar-width:none] [&_.ProseMirror::-webkit-scrollbar]:hidden',\n '[&_.ProseMirror]:placeholder:text-[#7c8793]',\n '[&_.ProseMirror]:focus-visible:border-sky-600 [&_.ProseMirror]:focus-visible:shadow-[0_0_0_1px_var(--color-sky-600),0_0_4px_0_hsl(from_var(--color-sky-600)_h_s_l/0.7)]',\n '[&_.ProseMirror]:disabled:cursor-not-allowed [&_.ProseMirror]:disabled:opacity-50',\n ],\n isInvalid && [\n '[&_.ProseMirror]:border-rose-600',\n '[&_.ProseMirror]:focus-visible:shadow-[0_0_0_1px_var(--color-rose-600),0_0_4px_0_hsl(from_var(--color-rose-600)_h_s_l/0.7)]',\n ],\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p]:inline',\n '[&_.ProseMirror_p]:leading-tight',\n '[&_.ProseMirror-trailingBreak]:inline [&_.ProseMirror-trailingBreak]:leading-none [&_.ProseMirror-trailingBreak]:w-0 [&_.ProseMirror-trailingBreak]:h-0',\n )}\n {...props}\n />\n\n {hasVariables && !readOnly && (\n <VariableDropdown\n editor={editor}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n triggerMode=\"input\"\n open={isVariablePickerOpen}\n onOpenChange={setIsVariablePickerOpen}\n />\n )}\n\n {hasVariables && !readOnly && (\n <InlineVariablePickerPopover\n open={inlinePicker.state.open}\n onOpenChange={(open) => {\n if (!open) {\n inlinePicker.closePicker();\n }\n }}\n position={{ top: inlinePicker.state.top, left: inlinePicker.state.left }}\n isChildMode={inlinePicker.filteredVariables.isChildMode}\n query={inlinePicker.state.query}\n onQueryChange={inlinePicker.setQuery}\n filteredVariables={inlinePicker.filteredVariables}\n onSelect={inlinePicker.handleSelect}\n onBack={inlinePicker.goBack}\n />\n )}\n </div>\n </VariablePickerProvider>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"TiptapInput.js","names":[],"sources":["../../src/components/TiptapInput.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { useEditor, EditorContent } from '@tiptap/react';\n\nimport Document from '@tiptap/extension-document';\nimport Text from '@tiptap/extension-text';\n\nimport VariableTag from '@verbb/plugin-kit-react/components/tiptap/VariableTag';\nimport { VariableDropdown } from '@verbb/plugin-kit-react/components/tiptap/VariableDropdown';\nimport type { VariableCategories } from '@verbb/plugin-kit-react/components/tiptap/VariableDropdown';\nimport type { VariableConfigureSectionProps, VariableTransformerRegistry, VariableTagLabelResolver } from '@verbb/plugin-kit-react/components/tiptap/VariablePickerContext';\nimport { VariablePickerProvider } from '@verbb/plugin-kit-react/components/tiptap/VariablePickerContext';\nimport { InlineVariablePickerPopover } from '@verbb/plugin-kit-react/components/tiptap/InlineVariablePickerPopover';\nimport { useInlineVariablePicker } from '@verbb/plugin-kit-react/components/tiptap/useInlineVariablePicker';\nimport {\n contentToValue,\n dedupeVariableOptions,\n flattenVariableOptions,\n valueToContent,\n} from '@verbb/plugin-kit-react/components/tiptap/variableSerialization';\n\nimport { cn } from '@verbb/plugin-kit-react/utils';\n\nconst OneLinerDocument = Document.extend({\n content: 'inline*',\n});\n\nexport const TiptapInput = ({\n value = '',\n onChange,\n className,\n isInvalid,\n disabled = false,\n readOnly = false,\n variableCategories = {},\n variableCategoryLabels,\n variableCategoryOrder,\n variableTransformerRegistry,\n variablePickerTriggerCharacters = ['@'],\n renderVariableConfigureSection,\n resolveVariableTagLabel,\n ...props\n}: {\n value?: string;\n onChange?: (value: string) => void;\n className?: string;\n isInvalid?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n variableCategories?: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n variableTransformerRegistry?: VariableTransformerRegistry;\n variablePickerTriggerCharacters?: string[];\n renderVariableConfigureSection?: (props: VariableConfigureSectionProps) => ReactNode;\n resolveVariableTagLabel?: VariableTagLabelResolver;\n [key: string]: unknown;\n}) => {\n const wrapperRef = useRef<HTMLDivElement | null>(null);\n const [isVariablePickerOpen, setIsVariablePickerOpen] = useState(false);\n const handleKeyDownRef = useRef<import('./tiptap/useInlineVariablePicker').InlineVariablePickerHandleKeyDown | null>(null);\n\n const topLevelVariables = useMemo(() => {\n const values = Object.values(variableCategories ?? {}).flatMap(items => {\n return Array.isArray(items) ? items : [];\n },\n );\n return dedupeVariableOptions(values);\n }, [variableCategories]);\n\n const variables = useMemo(() => {\n return flattenVariableOptions(topLevelVariables);\n }, [topLevelVariables]);\n\n const extensions = useMemo(\n () => {\n return [OneLinerDocument, Text, VariableTag.configure({})];\n },\n [],\n );\n\n const editor = useEditor({\n extensions,\n content: valueToContent(value, topLevelVariables, variables) as Parameters<typeof useEditor>[0]['content'],\n editable: !disabled && !readOnly,\n editorProps: {\n handleKeyDown: (view, event) => {\n return handleKeyDownRef.current?.(view, event) ?? false;\n },\n } as Parameters<typeof useEditor>[0]['editorProps'],\n onUpdate: ({ editor: ed }) => {\n if (onChange) {\n onChange(contentToValue(ed.getJSON().content));\n }\n },\n });\n\n const inlinePicker = useInlineVariablePicker(editor, {\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n variablePickerTriggerCharacters,\n disabled,\n readOnly,\n wrapperRef,\n onOpenDropdown: () => {\n return setIsVariablePickerOpen(true);\n },\n });\n\n useEffect(() => {\n handleKeyDownRef.current = inlinePicker.handleKeyDown;\n }, [inlinePicker.handleKeyDown]);\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n if (!readOnly && editor.isFocused) {\n return;\n }\n\n const newContent = valueToContent(value, topLevelVariables, variables);\n const currentContent = editor.getJSON();\n if (JSON.stringify(newContent) !== JSON.stringify(currentContent)) {\n queueMicrotask(() => {\n const content = newContent ?? { type: 'doc' as const, content: [] as const };\n editor.commands.setContent(content);\n });\n }\n }, [editor, value, readOnly, topLevelVariables, variables]);\n\n const hasVariables = variables.length > 0;\n\n return (\n <VariablePickerProvider\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n variableTransformerRegistry={variableTransformerRegistry as VariableTransformerRegistry | undefined}\n renderVariableConfigureSection={renderVariableConfigureSection}\n resolveVariableTagLabel={resolveVariableTagLabel}\n >\n <div ref={wrapperRef} className={cn('relative', className)}>\n <EditorContent\n editor={editor}\n className={cn(\n !readOnly && [\n '[&_.ProseMirror]:outline-none [&_.ProseMirror]:bg-clip-padding',\n '[&_.ProseMirror]:rounded-sm',\n '[&_.ProseMirror]:border [&_.ProseMirror]:border-[rgba(96,125,159,0.4)]',\n '[&_.ProseMirror]:bg-[rgb(251,252,254)]',\n '[&_.ProseMirror]:whitespace-pre-wrap',\n '[&_.ProseMirror]:w-full [&_.ProseMirror]:h-[34px] [&_.ProseMirror]:px-2 [&_.ProseMirror]:pr-10 [&_.ProseMirror]:pt-[6px] [&_.ProseMirror]:text-sm',\n '[&_.ProseMirror]:whitespace-nowrap [&_.ProseMirror]:overflow-x-auto [&_.ProseMirror]:overflow-y-hidden',\n '[&_.ProseMirror]:[scrollbar-width:none] [&_.ProseMirror::-webkit-scrollbar]:hidden',\n '[&_.ProseMirror]:placeholder:text-[#7c8793]',\n '[&_.ProseMirror]:focus-visible:border-sky-600 [&_.ProseMirror]:focus-visible:shadow-[0_0_0_1px_var(--color-sky-600),0_0_4px_0_hsl(from_var(--color-sky-600)_h_s_l/0.7)]',\n '[&_.ProseMirror]:disabled:cursor-not-allowed [&_.ProseMirror]:disabled:opacity-50',\n ],\n isInvalid && [\n '[&_.ProseMirror]:border-rose-600',\n '[&_.ProseMirror]:focus-visible:shadow-[0_0_0_1px_var(--color-rose-600),0_0_4px_0_hsl(from_var(--color-rose-600)_h_s_l/0.7)]',\n ],\n '[&_.ProseMirror_p]:m-0 [&_.ProseMirror_p]:inline',\n '[&_.ProseMirror_p]:leading-tight',\n '[&_.ProseMirror-trailingBreak]:inline [&_.ProseMirror-trailingBreak]:leading-none [&_.ProseMirror-trailingBreak]:w-0 [&_.ProseMirror-trailingBreak]:h-0',\n )}\n {...props}\n />\n\n {hasVariables && !readOnly && (\n <VariableDropdown\n editor={editor}\n variableCategories={variableCategories}\n variableCategoryLabels={variableCategoryLabels}\n variableCategoryOrder={variableCategoryOrder}\n triggerMode=\"input\"\n open={isVariablePickerOpen}\n onOpenChange={setIsVariablePickerOpen}\n />\n )}\n\n {hasVariables && !readOnly && (\n <InlineVariablePickerPopover\n open={inlinePicker.state.open}\n onOpenChange={(open) => {\n if (!open) {\n inlinePicker.closePicker();\n }\n }}\n position={{ top: inlinePicker.state.top, left: inlinePicker.state.left }}\n isChildMode={inlinePicker.filteredVariables.isChildMode}\n query={inlinePicker.state.query}\n onQueryChange={inlinePicker.setQuery}\n filteredVariables={inlinePicker.filteredVariables}\n onSelect={inlinePicker.handleSelect}\n onBack={inlinePicker.goBack}\n />\n )}\n </div>\n </VariablePickerProvider>\n );\n};\n"],"mappings":"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"}
@@ -7,8 +7,15 @@ export type VariableOption = {
7
7
  pageLabel?: string;
8
8
  /** For child items: selector | format | value. Used by variableSerialization. */
9
9
  group?: string;
10
+ /** Raw variable source value types from the server (e.g. text, number, date, url). */
11
+ types?: string[];
10
12
  /** Supported transform value types for this variable (e.g. text, number, date, url). */
11
13
  transformValueTypes?: string[];
14
+ /** Explicitly disables transforms for aggregate/content variables such as field summaries. */
15
+ allowTransforms?: boolean;
16
+ /** Application-specific metadata consumed by custom configure/label resolvers. */
17
+ meta?: Record<string, unknown>;
18
+ [key: string]: unknown;
12
19
  };
13
20
  export type VariableCategories = {
14
21
  [key: string]: VariableOption[] | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"VariableDropdown.d.ts","sourceRoot":"","sources":["../../../src/components/tiptap/VariableDropdown.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAa3C,MAAM,MAAM,cAAc,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,GAAG,SAAS,CAAC;CAC/C,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,CAEvG;AAED,KAAK,qBAAqB,GAAG;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7G,UAAU,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CACrC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,EACL,WAAW,EACX,aAAa,EACb,UAAU,EACV,eAAe,EACf,IAAI,EACJ,YAAY,EACZ,WAAuB,GAC1B,EAAE,qBAAqB,kDA2HvB"}
1
+ {"version":3,"file":"VariableDropdown.d.ts","sourceRoot":"","sources":["../../../src/components/tiptap/VariableDropdown.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAa3C,MAAM,MAAM,cAAc,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,8FAA8F;IAC9F,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,GAAG,SAAS,CAAC;CAC/C,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,CAEvG;AAED,KAAK,qBAAqB,GAAG;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7G,UAAU,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CACrC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,EACL,WAAW,EACX,aAAa,EACb,UAAU,EACV,eAAe,EACf,IAAI,EACJ,YAAY,EACZ,WAAuB,GAC1B,EAAE,qBAAqB,kDA2HvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"VariableDropdown.js","names":[],"sources":["../../../src/components/tiptap/VariableDropdown.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { useEditorState } from '@tiptap/react';\nimport type { Editor } from '@tiptap/core';\nimport { Button } from '@verbb/plugin-kit-react/components/Button';\nimport { Popover, PopoverContent, PopoverTrigger } from '@verbb/plugin-kit-react/components';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@verbb/plugin-kit-react/components/Tooltip';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faPlusCircle } from '@fortawesome/pro-regular-svg-icons';\nimport { cn } from '@verbb/plugin-kit-react/utils';\nimport { useTranslation } from '@verbb/plugin-kit-react/hooks';\n\nimport { buildVariableTagAttrs } from './variableSerialization';\nimport { VariableCommandList } from './VariableCommandList';\nimport { useVariablePicker } from './useVariablePicker';\n\nexport type VariableOption = {\n label: string;\n value?: string;\n children?: VariableOption[];\n /** Optional display bucket for first-level grouping (e.g. page headings). */\n pageLabel?: string;\n /** For child items: selector | format | value. Used by variableSerialization. */\n group?: string;\n /** Supported transform value types for this variable (e.g. text, number, date, url). */\n transformValueTypes?: string[];\n};\n\nexport type VariableCategories = {\n [key: string]: VariableOption[] | undefined;\n};\n\nexport function formatVariableCategoryLabel(key: string, labels?: Record<string, string> | null): string {\n return labels?.[key] ?? key;\n}\n\ntype VariableDropdownProps = {\n editor: Editor | null | undefined;\n variableCategories: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n title?: string;\n buttonLabel?: string;\n buttonVariant?: 'default' | 'primary' | 'secondary' | 'dashed' | 'outline' | 'transparent' | 'link' | 'none';\n buttonSize?: 'default' | 'none' | 'xs' | 'sm' | 'lg' | 'xl';\n buttonClassName?: string;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n triggerMode?: 'toolbar' | 'input';\n};\n\nexport function VariableDropdown({\n editor,\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n title,\n buttonLabel,\n buttonVariant,\n buttonSize,\n buttonClassName,\n open,\n onOpenChange,\n triggerMode = 'toolbar',\n}: VariableDropdownProps) {\n const t = useTranslation();\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n\n const isControlledOpen = typeof open === 'boolean';\n const isOpen = isControlledOpen ? open : uncontrolledOpen;\n\n const picker = useVariablePicker({\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n isOpen,\n onApply: (baseVariable, variable) => {\n const attrs = buildVariableTagAttrs(baseVariable, variable);\n const chain = editor?.chain();\n chain?.focus?.()?.setVariableTag?.(attrs)?.run?.();\n if (!isControlledOpen) {\n setUncontrolledOpen(false);\n }\n onOpenChange?.(false);\n picker.reset();\n },\n });\n\n const isVariableActive = useEditorState({\n editor: editor as import('@tiptap/core').Editor | null,\n selector: ({ editor: ed }) => {\n return (ed?.isFocused && ed?.isActive('variableTag')) ?? false;\n },\n });\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (!nextOpen) {\n picker.reset();\n }\n if (!isControlledOpen) {\n setUncontrolledOpen(nextOpen);\n }\n onOpenChange?.(nextOpen);\n };\n\n const hasAnyVariables = Object.values(variableCategories ?? {}).some(\n items => {\n return Array.isArray(items) && items.length > 0;\n },\n );\n\n if (!hasAnyVariables) {\n return null;\n }\n\n const triggerButton = (\n <Button\n variant={buttonVariant ?? 'none'}\n size={buttonSize}\n className={cn(\n triggerMode === 'toolbar' && [\n buttonLabel ? 'h-[32px] px-[8px] gap-1.5' : 'w-[32px] h-[32px]',\n 'text-[#1c2e36]',\n 'hover:bg-slate-100!',\n isVariableActive && 'bg-slate-250! hover:bg-slate-250!',\n ],\n triggerMode === 'input' && [\n 'absolute right-[1px] top-1/2 -translate-y-1/2',\n 'border-l border-transparent',\n 'rounded-[3px] rounded-l-none',\n 'h-[calc(100%-2px)]',\n 'text-[#8d959b]',\n 'bg-white hover:bg-slate-50',\n 'border-[#d7dfe7]',\n 'text-[#1c2e36]',\n ],\n\n buttonClassName ?? '',\n )}\n >\n <FontAwesomeIcon icon={faPlusCircle} className=\"size-4\" />\n {buttonLabel && <span>{buttonLabel}</span>}\n </Button>\n );\n\n const content = (\n <Popover modal={false} open={isOpen} onOpenChange={handleOpenChange}>\n {(buttonLabel || title) ? (\n <Tooltip>\n <TooltipTrigger render={<PopoverTrigger nativeButton={true} render={triggerButton} />} />\n <TooltipContent sideOffset={4}>{buttonLabel || title}</TooltipContent>\n </Tooltip>\n ) : (\n <PopoverTrigger nativeButton={true} render={triggerButton} />\n )}\n <PopoverContent\n align={triggerMode === 'input' ? 'end' : 'start'}\n side=\"bottom\"\n sideOffset={6}\n positionMethod=\"fixed\"\n collisionAvoidance={{\n side: 'flip',\n align: 'shift',\n fallbackAxisSide: 'none',\n }}\n className=\"min-w-[260px] max-w-[360px] p-0 overflow-hidden flex flex-col\"\n portalClassName=\"z-250\"\n >\n <VariableCommandList\n search={picker.search}\n onSearchChange={picker.setSearch}\n groups={picker.groups}\n options={picker.options}\n onSelect={picker.handleSelect}\n placeholder={t('Search variables')}\n showSearch\n shouldFilter={false}\n onBack={picker.page ? picker.handleBack : undefined}\n isChildMode={!!picker.page}\n selectFirstItem={triggerMode === 'input'}\n autoFocusSearchInput={triggerMode !== 'input'}\n />\n </PopoverContent>\n </Popover>\n );\n\n return content;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA+BA,SAAgB,4BAA4B,KAAa,QAAgD;AACrG,QAAO,SAAS,QAAQ;;AAkB5B,SAAgB,iBAAiB,EAC7B,QACA,oBACA,wBACA,uBACA,OACA,aACA,eACA,YACA,iBACA,MACA,cACA,cAAc,aACQ;CACtB,MAAM,IAAI,gBAAgB;CAC1B,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,MAAM;CAE/D,MAAM,mBAAmB,OAAO,SAAS;CACzC,MAAM,SAAS,mBAAmB,OAAO;CAEzC,MAAM,SAAS,kBAAkB;EAC7B;EACA;EACA;EACA;EACA,UAAU,cAAc,aAAa;GACjC,MAAM,QAAQ,sBAAsB,cAAc,SAAS;AAE3D,IADc,QAAQ,OAAO,GACtB,SAAS,EAAE,iBAAiB,MAAM,EAAE,OAAO;AAClD,OAAI,CAAC,iBACD,qBAAoB,MAAM;AAE9B,kBAAe,MAAM;AACrB,UAAO,OAAO;;EAErB,CAAC;CAEF,MAAM,mBAAmB,eAAe;EAC5B;EACR,WAAW,EAAE,QAAQ,SAAS;AAC1B,WAAQ,IAAI,aAAa,IAAI,SAAS,cAAc,KAAK;;EAEhE,CAAC;CAEF,MAAM,oBAAoB,aAAsB;AAC5C,MAAI,CAAC,SACD,QAAO,OAAO;AAElB,MAAI,CAAC,iBACD,qBAAoB,SAAS;AAEjC,iBAAe,SAAS;;AAS5B,KAAI,CANoB,OAAO,OAAO,sBAAsB,EAAE,CAAC,CAAC,MAC5D,UAAS;AACL,SAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS;GAIjD,CACD,QAAO;CAGX,MAAM,gBACF,qBAAC,QAAD;EACI,SAAS,iBAAiB;EAC1B,MAAM;EACN,WAAW,GACP,gBAAgB,aAAa;GACzB,cAAc,8BAA8B;GAC5C;GACA;GACA,oBAAoB;GACvB,EACD,gBAAgB,WAAW;GACvB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACH,EAED,mBAAmB,GACtB;YAtBL,CAwBI,oBAAC,iBAAD;GAAiB,MAAM;GAAc,WAAU;GAAW,CAAA,EACzD,eAAe,oBAAC,QAAD,EAAA,UAAO,aAAmB,CAAA,CACrC;;AA4Cb,QAxCI,qBAAC,SAAD;EAAS,OAAO;EAAO,MAAM;EAAQ,cAAc;YAAnD,CACM,eAAe,QACb,qBAAC,SAAD,EAAA,UAAA,CACI,oBAAC,gBAAD,EAAgB,QAAQ,oBAAC,gBAAD;GAAgB,cAAc;GAAM,QAAQ;GAAiB,CAAA,EAAI,CAAA,EACzF,oBAAC,gBAAD;GAAgB,YAAY;aAAI,eAAe;GAAuB,CAAA,CAChE,EAAA,CAAA,GAEV,oBAAC,gBAAD;GAAgB,cAAc;GAAM,QAAQ;GAAiB,CAAA,EAEjE,oBAAC,gBAAD;GACI,OAAO,gBAAgB,UAAU,QAAQ;GACzC,MAAK;GACL,YAAY;GACZ,gBAAe;GACf,oBAAoB;IAChB,MAAM;IACN,OAAO;IACP,kBAAkB;IACrB;GACD,WAAU;GACV,iBAAgB;aAEhB,oBAAC,qBAAD;IACI,QAAQ,OAAO;IACf,gBAAgB,OAAO;IACvB,QAAQ,OAAO;IACf,SAAS,OAAO;IAChB,UAAU,OAAO;IACjB,aAAa,EAAE,mBAAmB;IAClC,YAAA;IACA,cAAc;IACd,QAAQ,OAAO,OAAO,OAAO,aAAa,KAAA;IAC1C,aAAa,CAAC,CAAC,OAAO;IACtB,iBAAiB,gBAAgB;IACjC,sBAAsB,gBAAgB;IACxC,CAAA;GACW,CAAA,CACX;GAGP"}
1
+ {"version":3,"file":"VariableDropdown.js","names":[],"sources":["../../../src/components/tiptap/VariableDropdown.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { useEditorState } from '@tiptap/react';\nimport type { Editor } from '@tiptap/core';\nimport { Button } from '@verbb/plugin-kit-react/components/Button';\nimport { Popover, PopoverContent, PopoverTrigger } from '@verbb/plugin-kit-react/components';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@verbb/plugin-kit-react/components/Tooltip';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faPlusCircle } from '@fortawesome/pro-regular-svg-icons';\nimport { cn } from '@verbb/plugin-kit-react/utils';\nimport { useTranslation } from '@verbb/plugin-kit-react/hooks';\n\nimport { buildVariableTagAttrs } from './variableSerialization';\nimport { VariableCommandList } from './VariableCommandList';\nimport { useVariablePicker } from './useVariablePicker';\n\nexport type VariableOption = {\n label: string;\n value?: string;\n children?: VariableOption[];\n /** Optional display bucket for first-level grouping (e.g. page headings). */\n pageLabel?: string;\n /** For child items: selector | format | value. Used by variableSerialization. */\n group?: string;\n /** Raw variable source value types from the server (e.g. text, number, date, url). */\n types?: string[];\n /** Supported transform value types for this variable (e.g. text, number, date, url). */\n transformValueTypes?: string[];\n /** Explicitly disables transforms for aggregate/content variables such as field summaries. */\n allowTransforms?: boolean;\n /** Application-specific metadata consumed by custom configure/label resolvers. */\n meta?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type VariableCategories = {\n [key: string]: VariableOption[] | undefined;\n};\n\nexport function formatVariableCategoryLabel(key: string, labels?: Record<string, string> | null): string {\n return labels?.[key] ?? key;\n}\n\ntype VariableDropdownProps = {\n editor: Editor | null | undefined;\n variableCategories: VariableCategories;\n variableCategoryLabels?: Record<string, string>;\n variableCategoryOrder?: string[];\n title?: string;\n buttonLabel?: string;\n buttonVariant?: 'default' | 'primary' | 'secondary' | 'dashed' | 'outline' | 'transparent' | 'link' | 'none';\n buttonSize?: 'default' | 'none' | 'xs' | 'sm' | 'lg' | 'xl';\n buttonClassName?: string;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n triggerMode?: 'toolbar' | 'input';\n};\n\nexport function VariableDropdown({\n editor,\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n title,\n buttonLabel,\n buttonVariant,\n buttonSize,\n buttonClassName,\n open,\n onOpenChange,\n triggerMode = 'toolbar',\n}: VariableDropdownProps) {\n const t = useTranslation();\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n\n const isControlledOpen = typeof open === 'boolean';\n const isOpen = isControlledOpen ? open : uncontrolledOpen;\n\n const picker = useVariablePicker({\n variableCategories,\n variableCategoryLabels,\n variableCategoryOrder,\n isOpen,\n onApply: (baseVariable, variable) => {\n const attrs = buildVariableTagAttrs(baseVariable, variable);\n const chain = editor?.chain();\n chain?.focus?.()?.setVariableTag?.(attrs)?.run?.();\n if (!isControlledOpen) {\n setUncontrolledOpen(false);\n }\n onOpenChange?.(false);\n picker.reset();\n },\n });\n\n const isVariableActive = useEditorState({\n editor: editor as import('@tiptap/core').Editor | null,\n selector: ({ editor: ed }) => {\n return (ed?.isFocused && ed?.isActive('variableTag')) ?? false;\n },\n });\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (!nextOpen) {\n picker.reset();\n }\n if (!isControlledOpen) {\n setUncontrolledOpen(nextOpen);\n }\n onOpenChange?.(nextOpen);\n };\n\n const hasAnyVariables = Object.values(variableCategories ?? {}).some(\n items => {\n return Array.isArray(items) && items.length > 0;\n },\n );\n\n if (!hasAnyVariables) {\n return null;\n }\n\n const triggerButton = (\n <Button\n variant={buttonVariant ?? 'none'}\n size={buttonSize}\n className={cn(\n triggerMode === 'toolbar' && [\n buttonLabel ? 'h-[32px] px-[8px] gap-1.5' : 'w-[32px] h-[32px]',\n 'text-[#1c2e36]',\n 'hover:bg-slate-100!',\n isVariableActive && 'bg-slate-250! hover:bg-slate-250!',\n ],\n triggerMode === 'input' && [\n 'absolute right-[1px] top-1/2 -translate-y-1/2',\n 'border-l border-transparent',\n 'rounded-[3px] rounded-l-none',\n 'h-[calc(100%-2px)]',\n 'text-[#8d959b]',\n 'bg-white hover:bg-slate-50',\n 'border-[#d7dfe7]',\n 'text-[#1c2e36]',\n ],\n\n buttonClassName ?? '',\n )}\n >\n <FontAwesomeIcon icon={faPlusCircle} className=\"size-4\" />\n {buttonLabel && <span>{buttonLabel}</span>}\n </Button>\n );\n\n const content = (\n <Popover modal={false} open={isOpen} onOpenChange={handleOpenChange}>\n {(buttonLabel || title) ? (\n <Tooltip>\n <TooltipTrigger render={<PopoverTrigger nativeButton={true} render={triggerButton} />} />\n <TooltipContent sideOffset={4}>{buttonLabel || title}</TooltipContent>\n </Tooltip>\n ) : (\n <PopoverTrigger nativeButton={true} render={triggerButton} />\n )}\n <PopoverContent\n align={triggerMode === 'input' ? 'end' : 'start'}\n side=\"bottom\"\n sideOffset={6}\n positionMethod=\"fixed\"\n collisionAvoidance={{\n side: 'flip',\n align: 'shift',\n fallbackAxisSide: 'none',\n }}\n className=\"min-w-[260px] max-w-[360px] p-0 overflow-hidden flex flex-col\"\n portalClassName=\"z-250\"\n >\n <VariableCommandList\n search={picker.search}\n onSearchChange={picker.setSearch}\n groups={picker.groups}\n options={picker.options}\n onSelect={picker.handleSelect}\n placeholder={t('Search variables')}\n showSearch\n shouldFilter={false}\n onBack={picker.page ? picker.handleBack : undefined}\n isChildMode={!!picker.page}\n selectFirstItem={triggerMode === 'input'}\n autoFocusSearchInput={triggerMode !== 'input'}\n />\n </PopoverContent>\n </Popover>\n );\n\n return content;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsCA,SAAgB,4BAA4B,KAAa,QAAgD;AACrG,QAAO,SAAS,QAAQ;;AAkB5B,SAAgB,iBAAiB,EAC7B,QACA,oBACA,wBACA,uBACA,OACA,aACA,eACA,YACA,iBACA,MACA,cACA,cAAc,aACQ;CACtB,MAAM,IAAI,gBAAgB;CAC1B,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,MAAM;CAE/D,MAAM,mBAAmB,OAAO,SAAS;CACzC,MAAM,SAAS,mBAAmB,OAAO;CAEzC,MAAM,SAAS,kBAAkB;EAC7B;EACA;EACA;EACA;EACA,UAAU,cAAc,aAAa;GACjC,MAAM,QAAQ,sBAAsB,cAAc,SAAS;AAE3D,IADc,QAAQ,OAAO,GACtB,SAAS,EAAE,iBAAiB,MAAM,EAAE,OAAO;AAClD,OAAI,CAAC,iBACD,qBAAoB,MAAM;AAE9B,kBAAe,MAAM;AACrB,UAAO,OAAO;;EAErB,CAAC;CAEF,MAAM,mBAAmB,eAAe;EAC5B;EACR,WAAW,EAAE,QAAQ,SAAS;AAC1B,WAAQ,IAAI,aAAa,IAAI,SAAS,cAAc,KAAK;;EAEhE,CAAC;CAEF,MAAM,oBAAoB,aAAsB;AAC5C,MAAI,CAAC,SACD,QAAO,OAAO;AAElB,MAAI,CAAC,iBACD,qBAAoB,SAAS;AAEjC,iBAAe,SAAS;;AAS5B,KAAI,CANoB,OAAO,OAAO,sBAAsB,EAAE,CAAC,CAAC,MAC5D,UAAS;AACL,SAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS;GAIjD,CACD,QAAO;CAGX,MAAM,gBACF,qBAAC,QAAD;EACI,SAAS,iBAAiB;EAC1B,MAAM;EACN,WAAW,GACP,gBAAgB,aAAa;GACzB,cAAc,8BAA8B;GAC5C;GACA;GACA,oBAAoB;GACvB,EACD,gBAAgB,WAAW;GACvB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACH,EAED,mBAAmB,GACtB;YAtBL,CAwBI,oBAAC,iBAAD;GAAiB,MAAM;GAAc,WAAU;GAAW,CAAA,EACzD,eAAe,oBAAC,QAAD,EAAA,UAAO,aAAmB,CAAA,CACrC;;AA4Cb,QAxCI,qBAAC,SAAD;EAAS,OAAO;EAAO,MAAM;EAAQ,cAAc;YAAnD,CACM,eAAe,QACb,qBAAC,SAAD,EAAA,UAAA,CACI,oBAAC,gBAAD,EAAgB,QAAQ,oBAAC,gBAAD;GAAgB,cAAc;GAAM,QAAQ;GAAiB,CAAA,EAAI,CAAA,EACzF,oBAAC,gBAAD;GAAgB,YAAY;aAAI,eAAe;GAAuB,CAAA,CAChE,EAAA,CAAA,GAEV,oBAAC,gBAAD;GAAgB,cAAc;GAAM,QAAQ;GAAiB,CAAA,EAEjE,oBAAC,gBAAD;GACI,OAAO,gBAAgB,UAAU,QAAQ;GACzC,MAAK;GACL,YAAY;GACZ,gBAAe;GACf,oBAAoB;IAChB,MAAM;IACN,OAAO;IACP,kBAAkB;IACrB;GACD,WAAU;GACV,iBAAgB;aAEhB,oBAAC,qBAAD;IACI,QAAQ,OAAO;IACf,gBAAgB,OAAO;IACvB,QAAQ,OAAO;IACf,SAAS,OAAO;IAChB,UAAU,OAAO;IACjB,aAAa,EAAE,mBAAmB;IAClC,YAAA;IACA,cAAc;IACd,QAAQ,OAAO,OAAO,OAAO,aAAa,KAAA;IAC1C,aAAa,CAAC,CAAC,OAAO;IACtB,iBAAiB,gBAAgB;IACjC,sBAAsB,gBAAgB;IACxC,CAAA;GACW,CAAA,CACX;GAGP"}