@bpmn-io/properties-panel 3.40.6 → 3.41.1

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.
package/dist/index.js CHANGED
@@ -7,9 +7,15 @@ var jsxRuntime = require('../preact/jsx-runtime');
7
7
  var preact = require('../preact');
8
8
  var classnames = require('classnames');
9
9
  var minDom = require('min-dom');
10
+ var view = require('@codemirror/view');
11
+ var state = require('@codemirror/state');
12
+ var language = require('@codemirror/language');
13
+ var autocomplete = require('@codemirror/autocomplete');
14
+ var commands = require('@codemirror/commands');
15
+ var langJson = require('@codemirror/lang-json');
16
+ var lint = require('@codemirror/lint');
10
17
  var feelers = require('feelers');
11
18
  var Editor = require('@bpmn-io/feel-editor');
12
- var view = require('@codemirror/view');
13
19
  var focusTrap = require('focus-trap');
14
20
 
15
21
  function _interopNamespaceDefault(e) {
@@ -1760,7 +1766,7 @@ function CheckboxEntry(props) {
1760
1766
  })]
1761
1767
  });
1762
1768
  }
1763
- function isEdited$8(node) {
1769
+ function isEdited$9(node) {
1764
1770
  return node && !!node.checked;
1765
1771
  }
1766
1772
 
@@ -1837,6 +1843,200 @@ function CheckboxGroup(props) {
1837
1843
  });
1838
1844
  }
1839
1845
 
1846
+ const ExternalChange = state.Annotation.define();
1847
+ const parseJsonLinter = langJson.jsonParseLinter();
1848
+
1849
+ /**
1850
+ * A CodeMirror based JSON editor for the properties panel.
1851
+ *
1852
+ * @param {object} props
1853
+ * @param {string} props.id
1854
+ * @param {string} props.label
1855
+ * @param {string} [props.value]
1856
+ * @param {Function} props.onInput
1857
+ * @param {boolean} [props.disabled]
1858
+ * @param {string} [props.placeholder]
1859
+ * @param {string} [props.tooltip]
1860
+ * @param {object} [props.element]
1861
+ */
1862
+ function JsonEditor(props) {
1863
+ const {
1864
+ id,
1865
+ label,
1866
+ debounce,
1867
+ value = '',
1868
+ onInput: commitValue,
1869
+ disabled,
1870
+ placeholder,
1871
+ tooltip,
1872
+ element
1873
+ } = props;
1874
+ const containerRef = hooks.useRef(null);
1875
+ const viewRef = hooks.useRef(null);
1876
+ const editorRef = useShowEntryEvent(id);
1877
+ const onInput = useStaticCallback(newValue => {
1878
+ commitValue(newValue === '' ? undefined : newValue);
1879
+ });
1880
+ const handleChange = useDebounce(onInput, debounce);
1881
+ hooks.useEffect(() => {
1882
+ const view$1 = new view.EditorView({
1883
+ state: state.EditorState.create({
1884
+ doc: value,
1885
+ extensions: [view.highlightSpecialChars(), commands.history(), view.drawSelection(), language.syntaxHighlighting(language.defaultHighlightStyle, {
1886
+ fallback: true
1887
+ }), language.foldGutter(), language.bracketMatching(), autocomplete.closeBrackets(), view.keymap.of([...commands.defaultKeymap, ...commands.historyKeymap, ...autocomplete.closeBracketsKeymap, ...language.foldKeymap]), state.EditorState.tabSize.of(2), view.EditorView.lineWrapping, state.EditorState.readOnly.of(!!disabled), ...(placeholder ? [view.placeholder(placeholder)] : []), view.EditorView.updateListener.of(update => {
1888
+ const isExternal = update.transactions.some(tr => tr.annotation(ExternalChange));
1889
+ if (update.docChanged && !isExternal) {
1890
+ handleChange(update.state.doc.toString());
1891
+ }
1892
+ }), langJson.json(), lint.linter(view => {
1893
+ const content = view.state.doc.toString();
1894
+ if (!content.trim()) return [];
1895
+ return parseJsonLinter(view);
1896
+ }, {
1897
+ delay: 300
1898
+ })]
1899
+ }),
1900
+ parent: containerRef.current
1901
+ });
1902
+ viewRef.current = view$1;
1903
+
1904
+ // Allow useShowEntryEvent to focus the editor
1905
+ editorRef.current = view$1.contentDOM;
1906
+ const prefixedId = `bio-properties-panel-${id}`;
1907
+ view$1.contentDOM.setAttribute('id', prefixedId);
1908
+ view$1.contentDOM.setAttribute('aria-label', label);
1909
+ return () => {
1910
+ view$1.destroy();
1911
+ };
1912
+ }, []);
1913
+
1914
+ // Sync external value changes into the editor
1915
+ hooks.useEffect(() => {
1916
+ const view = viewRef.current;
1917
+ if (!view) return;
1918
+ const currentValue = view.state.doc.toString();
1919
+ if (value === currentValue) return;
1920
+ view.dispatch({
1921
+ changes: {
1922
+ from: 0,
1923
+ to: currentValue.length,
1924
+ insert: value || ''
1925
+ },
1926
+ annotations: ExternalChange.of(true)
1927
+ });
1928
+ }, [value]);
1929
+
1930
+ // Focus editor on label click manually, as the native `for`
1931
+ // attribute does not work with contenteditable elements
1932
+ const focusEditor = () => {
1933
+ viewRef.current && viewRef.current.focus();
1934
+ };
1935
+ return jsxRuntime.jsxs("div", {
1936
+ class: "bio-properties-panel-json-editor",
1937
+ children: [jsxRuntime.jsx("label", {
1938
+ class: "bio-properties-panel-label",
1939
+ onClick: focusEditor,
1940
+ children: jsxRuntime.jsx(TooltipWrapper, {
1941
+ value: tooltip,
1942
+ forId: id,
1943
+ element: element,
1944
+ children: label
1945
+ })
1946
+ }), jsxRuntime.jsx("div", {
1947
+ ref: containerRef
1948
+ })]
1949
+ });
1950
+ }
1951
+
1952
+ /**
1953
+ * Entry wrapper for JsonEditor, handles getValue/setValue, built-in JSON validation, error display, and description.
1954
+ *
1955
+ * @param {object} props
1956
+ * @param {object} props.element
1957
+ * @param {string} props.id
1958
+ * @param {string} [props.description]
1959
+ * @param {string} props.label
1960
+ * @param {Function} props.debounce
1961
+ * @param {Function} props.getValue
1962
+ * @param {Function} props.setValue
1963
+ * @param {boolean} [props.disabled]
1964
+ * @param {string} [props.placeholder]
1965
+ * @param {string} [props.tooltip]
1966
+ */
1967
+ function JsonEditorEntry(props) {
1968
+ const {
1969
+ element,
1970
+ id,
1971
+ description,
1972
+ debounce,
1973
+ label,
1974
+ getValue,
1975
+ setValue,
1976
+ disabled,
1977
+ placeholder,
1978
+ tooltip
1979
+ } = props;
1980
+ const globalError = useError(id);
1981
+ let value = getValue(element);
1982
+ const [editorValue, setEditorValue] = hooks.useState(value);
1983
+ hooks.useEffect(() => {
1984
+ if (value === editorValue) {
1985
+ return;
1986
+ }
1987
+ setEditorValue(value);
1988
+ }, [value]);
1989
+ const onInput = useStaticCallback(newValue => {
1990
+ setEditorValue(newValue);
1991
+ const currentValue = getValue(element);
1992
+ if (newValue !== currentValue) {
1993
+ setValue(newValue);
1994
+ }
1995
+ });
1996
+ const error = globalError || validateJson(editorValue);
1997
+ return jsxRuntime.jsxs("div", {
1998
+ class: classnames('bio-properties-panel-entry', error && 'has-error'),
1999
+ "data-entry-id": id,
2000
+ children: [jsxRuntime.jsx(JsonEditor, {
2001
+ id: id,
2002
+ label: label,
2003
+ debounce: debounce,
2004
+ value: value,
2005
+ onInput: onInput,
2006
+ disabled: disabled,
2007
+ placeholder: placeholder,
2008
+ tooltip: tooltip,
2009
+ element: element
2010
+ }, element), error && jsxRuntime.jsx("div", {
2011
+ class: "bio-properties-panel-error",
2012
+ children: error
2013
+ }), jsxRuntime.jsx(Description, {
2014
+ forId: id,
2015
+ element: element,
2016
+ value: description
2017
+ })]
2018
+ });
2019
+ }
2020
+
2021
+ /**
2022
+ * Check if the JSON editor entry has been edited.
2023
+ */
2024
+ function isEdited$8(node) {
2025
+ const cmContent = node && node.querySelector('.cm-content');
2026
+ return cmContent ? cmContent.textContent.trim().length > 0 : false;
2027
+ }
2028
+
2029
+ // helpers /////////////////
2030
+
2031
+ function validateJson(value) {
2032
+ if (!value || !value.trim()) return null;
2033
+ try {
2034
+ return minDash.isObject(JSON.parse(value)) ? null : 'JSON contains errors';
2035
+ } catch (e) {
2036
+ return 'JSON contains errors';
2037
+ }
2038
+ }
2039
+
1840
2040
  /**
1841
2041
  * Button to open popups.
1842
2042
  *
@@ -4947,6 +5147,7 @@ exports.FeelToggleSwitchEntry = FeelToggleSwitchEntry;
4947
5147
  exports.Group = Group;
4948
5148
  exports.Header = Header;
4949
5149
  exports.HeaderButton = HeaderButton;
5150
+ exports.JsonEditorEntry = JsonEditorEntry;
4950
5151
  exports.LaunchIcon = LaunchIcon;
4951
5152
  exports.LayoutContext = LayoutContext;
4952
5153
  exports.ListEntry = List;
@@ -4965,8 +5166,9 @@ exports.TextFieldEntry = TextfieldEntry;
4965
5166
  exports.ToggleSwitchEntry = ToggleSwitchEntry;
4966
5167
  exports.TooltipContext = TooltipContext;
4967
5168
  exports.TooltipEntry = TooltipWrapper;
4968
- exports.isCheckboxEntryEdited = isEdited$8;
5169
+ exports.isCheckboxEntryEdited = isEdited$9;
4969
5170
  exports.isFeelEntryEdited = isEdited$5;
5171
+ exports.isJsonEditorEntryEdited = isEdited$8;
4970
5172
  exports.isNumberFieldEntryEdited = isEdited$6;
4971
5173
  exports.isSelectEntryEdited = isEdited$3;
4972
5174
  exports.isSimpleEntryEdited = isEdited$2;