@nuraly/lumenui 0.3.5 → 0.3.6

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 (80) hide show
  1. package/dist/nuralyui.bundle.js +2575 -1483
  2. package/dist/nuralyui.bundle.js.gz +0 -0
  3. package/dist/src/components/button/bundle.js +130 -39
  4. package/dist/src/components/button/bundle.js.gz +0 -0
  5. package/dist/src/components/button/button.component.js +7 -4
  6. package/dist/src/components/button/button.style.js +92 -2
  7. package/dist/src/components/canvas/base-canvas.component.d.ts +8 -0
  8. package/dist/src/components/canvas/base-canvas.component.js +75 -3
  9. package/dist/src/components/canvas/bundle.js +2525 -1185
  10. package/dist/src/components/canvas/bundle.js.gz +0 -0
  11. package/dist/src/components/canvas/controllers/collaboration.controller.d.ts +24 -11
  12. package/dist/src/components/canvas/controllers/collaboration.controller.js +176 -120
  13. package/dist/src/components/canvas/controllers/selection.controller.js +20 -0
  14. package/dist/src/components/canvas/interfaces/collaboration.interface.d.ts +8 -0
  15. package/dist/src/components/canvas/templates/index.d.ts +1 -0
  16. package/dist/src/components/canvas/templates/index.js +2 -0
  17. package/dist/src/components/canvas/templates/lock-overlay.template.d.ts +20 -0
  18. package/dist/src/components/canvas/templates/lock-overlay.template.js +33 -0
  19. package/dist/src/components/canvas/workflow-canvas.component.js +52 -24
  20. package/dist/src/components/canvas/workflow-canvas.style.js +62 -1
  21. package/dist/src/components/canvas/workflow-canvas.types.js +50 -4
  22. package/dist/src/components/chat-panel/bundle.js +10 -10
  23. package/dist/src/components/chat-panel/bundle.js.gz +0 -0
  24. package/dist/src/components/chat-panel/chat-panel.component.js +8 -8
  25. package/dist/src/components/chatbot/bundle.js +401 -242
  26. package/dist/src/components/chatbot/bundle.js.gz +0 -0
  27. package/dist/src/components/chatbot/chatbot.style.js +156 -21
  28. package/dist/src/components/chatbot/chatbot.types.d.ts +1 -0
  29. package/dist/src/components/chatbot/core/chatbot-core.controller.js +13 -7
  30. package/dist/src/components/chatbot/providers/workflow-socket-provider.js +1 -2
  31. package/dist/src/components/chatbot/templates/input-box.template.js +58 -30
  32. package/dist/src/components/chatbot/templates/message.template.js +41 -31
  33. package/dist/src/components/chatbot/templates/thread-sidebar.template.js +38 -39
  34. package/dist/src/components/colorpicker/bundle.js +15 -10
  35. package/dist/src/components/colorpicker/bundle.js.gz +0 -0
  36. package/dist/src/components/colorpicker/color-picker.component.js +15 -10
  37. package/dist/src/components/datepicker/bundle.js +10 -10
  38. package/dist/src/components/datepicker/bundle.js.gz +0 -0
  39. package/dist/src/components/datepicker/datepicker.component.js +14 -22
  40. package/dist/src/components/dropdown/bundle.js +13 -12
  41. package/dist/src/components/dropdown/bundle.js.gz +0 -0
  42. package/dist/src/components/dropdown/dropdown.component.js +10 -9
  43. package/dist/src/components/file-upload/bundle.js +15 -14
  44. package/dist/src/components/file-upload/bundle.js.gz +0 -0
  45. package/dist/src/components/file-upload/file-upload.component.js +15 -14
  46. package/dist/src/components/icon/bundle.js +7 -7
  47. package/dist/src/components/icon/bundle.js.gz +0 -0
  48. package/dist/src/components/icon/icon-paths.js +15 -0
  49. package/dist/src/components/iconpicker/bundle.js +214 -122
  50. package/dist/src/components/iconpicker/bundle.js.gz +0 -0
  51. package/dist/src/components/iconpicker/icon-picker.component.js +4 -4
  52. package/dist/src/components/menu/bundle.js +5 -2
  53. package/dist/src/components/menu/bundle.js.gz +0 -0
  54. package/dist/src/components/menu/menu.component.js +5 -2
  55. package/dist/src/components/modal/bundle.js +16 -13
  56. package/dist/src/components/modal/bundle.js.gz +0 -0
  57. package/dist/src/components/modal/modal.component.js +16 -13
  58. package/dist/src/components/panel/bundle.js +28 -28
  59. package/dist/src/components/panel/bundle.js.gz +0 -0
  60. package/dist/src/components/popconfirm/bundle.js +135 -41
  61. package/dist/src/components/popconfirm/bundle.js.gz +0 -0
  62. package/dist/src/components/popconfirm/popconfirm.component.d.ts +15 -119
  63. package/dist/src/components/popconfirm/popconfirm.component.js +158 -162
  64. package/dist/src/components/popconfirm/popconfirm.style.js +94 -0
  65. package/dist/src/components/presence/bundle.js +2 -1
  66. package/dist/src/components/presence/bundle.js.gz +0 -0
  67. package/dist/src/components/presence/presence.component.js +2 -1
  68. package/dist/src/components/table/bundle.js +3 -2
  69. package/dist/src/components/table/bundle.js.gz +0 -0
  70. package/dist/src/components/table/table.component.js +3 -2
  71. package/dist/src/components/tabs/bundle.js +3 -3
  72. package/dist/src/components/tabs/bundle.js.gz +0 -0
  73. package/dist/src/components/timepicker/bundle.js +3 -3
  74. package/dist/src/components/timepicker/bundle.js.gz +0 -0
  75. package/package.json +1 -1
  76. package/packages/common/dist/VERSIONS.md +1 -1
  77. package/packages/common/dist/shared/controllers/dropdown.controller.d.ts +4 -0
  78. package/packages/common/dist/shared/controllers/dropdown.controller.d.ts.map +1 -1
  79. package/packages/common/dist/shared/controllers/dropdown.controller.js +29 -3
  80. package/packages/common/dist/shared/controllers/dropdown.controller.js.map +1 -1
Binary file
@@ -1,4 +1,4 @@
1
- import{css as t,nothing as e,html as i,LitElement as o}from"lit";import{property as s,customElement as n}from"lit/decorators.js";import{ifDefined as r}from"lit/directives/if-defined.js";const a="",d=t`
1
+ import{css as t,nothing as e,html as o,LitElement as i}from"lit";import{property as n,customElement as r}from"lit/decorators.js";import{ifDefined as s}from"lit/directives/if-defined.js";const a="",d=t`
2
2
  :host {
3
3
  display: inline-block;
4
4
  vertical-align: middle;
@@ -211,7 +211,26 @@ import{css as t,nothing as e,html as i,LitElement as o}from"lit";import{property
211
211
  /* ======== Loading ======== */
212
212
  :host([loading]) button {
213
213
  cursor: not-allowed;
214
- opacity: 0.5;
214
+ opacity: 0.7;
215
+ }
216
+
217
+ .button-spinner {
218
+ display: inline-block;
219
+ width: 1em;
220
+ height: 1em;
221
+ border: 2px solid currentColor;
222
+ border-right-color: transparent;
223
+ border-radius: 50%;
224
+ animation: nr-button-spin 0.75s linear infinite;
225
+ flex-shrink: 0;
226
+ box-sizing: border-box;
227
+ }
228
+
229
+ :host([size="small"]) .button-spinner { width: 0.875em; height: 0.875em; border-width: 2px; }
230
+ :host([size="large"]) .button-spinner { width: 1.125em; height: 1.125em; border-width: 2px; }
231
+
232
+ @keyframes nr-button-spin {
233
+ to { transform: rotate(360deg); }
215
234
  }
216
235
 
217
236
  /* ======== Shape: Round ======== */
@@ -236,9 +255,80 @@ import{css as t,nothing as e,html as i,LitElement as o}from"lit";import{property
236
255
  height: 44px;
237
256
  }
238
257
 
239
- /* ======== Dashed ======== */
258
+ /* ======== Dashed ========
259
+ * Dashed turns any type into an outlined style so the dashed pattern
260
+ * is visible against a transparent background (filled variants otherwise
261
+ * hide the border because border-color matches background-color).
262
+ */
240
263
  button.button-dashed {
241
264
  border-style: dashed;
265
+ border-width: 1px;
266
+ }
267
+
268
+ :host([type="primary"]) button.button-dashed {
269
+ background-color: transparent;
270
+ border-color: #7c3aed;
271
+ color: #7c3aed;
272
+ }
273
+ :host([type="primary"]) button.button-dashed nr-icon {
274
+ color: #7c3aed !important;
275
+ }
276
+ :host([type="primary"]) button.button-dashed:hover:not(:disabled) {
277
+ background-color: rgba(124, 58, 237, 0.08);
278
+ border-color: #6d28d9;
279
+ color: #6d28d9;
280
+ }
281
+ :host([type="primary"]) button.button-dashed:active:not(:disabled) {
282
+ background-color: rgba(124, 58, 237, 0.15);
283
+ filter: none;
284
+ }
285
+
286
+ :host([type="secondary"]) button.button-dashed {
287
+ background-color: transparent;
288
+ border-color: #0f1419;
289
+ color: #0f1419;
290
+ }
291
+ :host([type="secondary"]) button.button-dashed:hover:not(:disabled) {
292
+ background-color: rgba(15, 20, 25, 0.06);
293
+ border-color: #272c30;
294
+ color: #272c30;
295
+ }
296
+ :host([type="secondary"]) button.button-dashed:active:not(:disabled) {
297
+ background-color: rgba(15, 20, 25, 0.12);
298
+ }
299
+
300
+ :host([type="default"]) button.button-dashed {
301
+ background-color: #fff;
302
+ border-color: #8c8c8c;
303
+ color: #536471;
304
+ }
305
+ :host([type="default"]) button.button-dashed:hover:not(:disabled) {
306
+ border-color: #7c3aed;
307
+ color: #7c3aed;
308
+ background-color: #fff;
309
+ }
310
+
311
+ :host([type="ghost"]) button.button-dashed {
312
+ background-color: transparent;
313
+ border-color: #7c3aed;
314
+ color: #7c3aed;
315
+ }
316
+
317
+ :host([type="danger"]) button.button-dashed {
318
+ background-color: transparent;
319
+ border-color: #dc2626;
320
+ color: #dc2626;
321
+ }
322
+ :host([type="danger"]) button.button-dashed nr-icon {
323
+ color: #dc2626 !important;
324
+ }
325
+ :host([type="danger"]) button.button-dashed:hover:not(:disabled) {
326
+ background-color: rgba(220, 38, 38, 0.08);
327
+ filter: none;
328
+ }
329
+ :host([type="danger"]) button.button-dashed:active:not(:disabled) {
330
+ background-color: rgba(220, 38, 38, 0.15);
331
+ filter: none;
242
332
  }
243
333
 
244
334
  /* ======== Ripple ======== */
@@ -263,28 +353,28 @@ import{css as t,nothing as e,html as i,LitElement as o}from"lit";import{property
263
353
  :host([type="default"]) .ripple { background: rgba(0, 0, 0, 0.06); }
264
354
  :host([type="ghost"]) .ripple { background: rgba(124, 58, 237, 0.15); }
265
355
  :host([type="danger"]) .ripple { background: rgba(255, 255, 255, 0.3); }
266
- `,h=t=>class extends t{constructor(){super(...arguments),this.handleSystemThemeChange=()=>{this.closest("[data-theme]")||document.documentElement.hasAttribute("data-theme")||this.requestUpdate()}}connectedCallback(){super.connectedCallback(),this.setupThemeObserver(),this.setupDesignSystemObserver(),this.setupSystemThemeListener()}disconnectedCallback(){var t,e,i;super.disconnectedCallback(),null===(t=this.themeObserver)||void 0===t||t.disconnect(),null===(e=this.designSystemObserver)||void 0===e||e.disconnect(),null===(i=this.mediaQuery)||void 0===i||i.removeEventListener("change",this.handleSystemThemeChange)}get currentTheme(){var t,e;const i=(null===(t=this.closest("[data-theme]"))||void 0===t?void 0:t.getAttribute("data-theme"))||document.documentElement.getAttribute("data-theme");return i||((null===(e=window.matchMedia)||void 0===e?void 0:e.call(window,"(prefers-color-scheme: dark)").matches)?"dark":"light")}get currentDesignSystem(){var t;const e=(null===(t=this.closest("[design-system]"))||void 0===t?void 0:t.getAttribute("design-system"))||document.documentElement.getAttribute("design-system");return"carbon"===e?e:"default"}setupThemeObserver(){this.themeObserver=new MutationObserver(()=>{this.requestUpdate()}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]})}setupDesignSystemObserver(){this.designSystemObserver=new MutationObserver(()=>{this.requestUpdate()}),this.designSystemObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["design-system"]})}setupSystemThemeListener(){window.matchMedia&&(this.mediaQuery=window.matchMedia("(prefers-color-scheme: dark)"),this.mediaQuery.addEventListener("change",this.handleSystemThemeChange))}},l=()=>{var t;return void 0!==globalThis.litElementVersions||"undefined"!=typeof process&&"development"===(null===(t=process.env)||void 0===t?void 0:t.NODE_ENV)||"undefined"!=typeof window&&("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname)},c=t=>class extends t{constructor(){super(...arguments),this.requiredComponents=[]}validateDependencies(){if(l())for(const t of this.requiredComponents)if(!this.isComponentAvailable(t))throw new Error(`Required component "${t}" is not registered. Please import and register the component before using ${this.tagName.toLowerCase()}. Example: import '@nuralyui/${t}';`)}validateDependenciesWithHandler(t){if(!l())return!0;let e=!0;for(const i of this.requiredComponents)if(!this.isComponentAvailable(i)){e=!1;const o=new Error(`Required component "${i}" is not registered. Please import and register the component before using ${this.tagName.toLowerCase()}.`);t?t(i,o):console.error(o.message)}return e}isComponentAvailable(t){return!!customElements.get(t)}getMissingDependencies(){return this.requiredComponents.filter(t=>!this.isComponentAvailable(t))}areDependenciesAvailable(){return this.requiredComponents.every(t=>this.isComponentAvailable(t))}addRequiredComponent(t){this.requiredComponents.includes(t)||this.requiredComponents.push(t)}removeRequiredComponent(t){const e=this.requiredComponents.indexOf(t);e>-1&&this.requiredComponents.splice(e,1)}},u=t=>class extends t{dispatchCustomEvent(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}dispatchEventWithMetadata(t,e){var i;const o=Object.assign(Object.assign({},e),{timestamp:Date.now(),componentName:(null===(i=this.tagName)||void 0===i?void 0:i.toLowerCase())||"unknown"});this.dispatchCustomEvent(t,o)}dispatchInputEvent(t,e){const i=Object.assign({target:e.target||this,value:e.value,originalEvent:e.originalEvent},e);this.dispatchCustomEvent(t,i)}dispatchFocusEvent(t,e){const i=Object.assign({target:e.target||this,value:e.value,focused:e.focused,cursorPosition:e.cursorPosition,selectedText:e.selectedText},e);this.dispatchCustomEvent(t,i)}dispatchValidationEvent(t,e){var i;const o=Object.assign({target:e.target||this,value:e.value,isValid:null!==(i=e.isValid)&&void 0!==i&&i,error:e.error},e);this.dispatchCustomEvent(t,o)}dispatchActionEvent(t,e){const i=Object.assign({target:e.target||this,action:e.action,previousValue:e.previousValue,newValue:e.newValue},e);this.dispatchCustomEvent(t,i)}isReadonlyKeyAllowed(t){if(t.ctrlKey||t.metaKey){return["KeyA","KeyC"].includes(t.code)}return["Tab","Escape","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","PageUp","PageDown"].includes(t.key)}isActivationKey(t){return"Enter"===t.key||" "===t.key}},p=new Set,b=new Map;
356
+ `,c=t=>class extends t{constructor(){super(...arguments),this.handleSystemThemeChange=()=>{this.closest("[data-theme]")||document.documentElement.hasAttribute("data-theme")||this.requestUpdate()}}connectedCallback(){super.connectedCallback(),this.setupThemeObserver(),this.setupDesignSystemObserver(),this.setupSystemThemeListener()}disconnectedCallback(){var t,e,o;super.disconnectedCallback(),null===(t=this.themeObserver)||void 0===t||t.disconnect(),null===(e=this.designSystemObserver)||void 0===e||e.disconnect(),null===(o=this.mediaQuery)||void 0===o||o.removeEventListener("change",this.handleSystemThemeChange)}get currentTheme(){var t,e;const o=(null===(t=this.closest("[data-theme]"))||void 0===t?void 0:t.getAttribute("data-theme"))||document.documentElement.getAttribute("data-theme");return o||((null===(e=window.matchMedia)||void 0===e?void 0:e.call(window,"(prefers-color-scheme: dark)").matches)?"dark":"light")}get currentDesignSystem(){var t;const e=(null===(t=this.closest("[design-system]"))||void 0===t?void 0:t.getAttribute("design-system"))||document.documentElement.getAttribute("design-system");return"carbon"===e?e:"default"}setupThemeObserver(){this.themeObserver=new MutationObserver(()=>{this.requestUpdate()}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme"]})}setupDesignSystemObserver(){this.designSystemObserver=new MutationObserver(()=>{this.requestUpdate()}),this.designSystemObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["design-system"]})}setupSystemThemeListener(){window.matchMedia&&(this.mediaQuery=window.matchMedia("(prefers-color-scheme: dark)"),this.mediaQuery.addEventListener("change",this.handleSystemThemeChange))}},h=()=>{var t;return void 0!==globalThis.litElementVersions||"undefined"!=typeof process&&"development"===(null===(t=process.env)||void 0===t?void 0:t.NODE_ENV)||"undefined"!=typeof window&&("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname)},l=t=>class extends t{constructor(){super(...arguments),this.requiredComponents=[]}validateDependencies(){if(h())for(const t of this.requiredComponents)if(!this.isComponentAvailable(t))throw new Error(`Required component "${t}" is not registered. Please import and register the component before using ${this.tagName.toLowerCase()}. Example: import '@nuralyui/${t}';`)}validateDependenciesWithHandler(t){if(!h())return!0;let e=!0;for(const o of this.requiredComponents)if(!this.isComponentAvailable(o)){e=!1;const i=new Error(`Required component "${o}" is not registered. Please import and register the component before using ${this.tagName.toLowerCase()}.`);t?t(o,i):console.error(i.message)}return e}isComponentAvailable(t){return!!customElements.get(t)}getMissingDependencies(){return this.requiredComponents.filter(t=>!this.isComponentAvailable(t))}areDependenciesAvailable(){return this.requiredComponents.every(t=>this.isComponentAvailable(t))}addRequiredComponent(t){this.requiredComponents.includes(t)||this.requiredComponents.push(t)}removeRequiredComponent(t){const e=this.requiredComponents.indexOf(t);e>-1&&this.requiredComponents.splice(e,1)}},u=t=>class extends t{dispatchCustomEvent(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}dispatchEventWithMetadata(t,e){var o;const i=Object.assign(Object.assign({},e),{timestamp:Date.now(),componentName:(null===(o=this.tagName)||void 0===o?void 0:o.toLowerCase())||"unknown"});this.dispatchCustomEvent(t,i)}dispatchInputEvent(t,e){const o=Object.assign({target:e.target||this,value:e.value,originalEvent:e.originalEvent},e);this.dispatchCustomEvent(t,o)}dispatchFocusEvent(t,e){const o=Object.assign({target:e.target||this,value:e.value,focused:e.focused,cursorPosition:e.cursorPosition,selectedText:e.selectedText},e);this.dispatchCustomEvent(t,o)}dispatchValidationEvent(t,e){var o;const i=Object.assign({target:e.target||this,value:e.value,isValid:null!==(o=e.isValid)&&void 0!==o&&o,error:e.error},e);this.dispatchCustomEvent(t,i)}dispatchActionEvent(t,e){const o=Object.assign({target:e.target||this,action:e.action,previousValue:e.previousValue,newValue:e.newValue},e);this.dispatchCustomEvent(t,o)}isReadonlyKeyAllowed(t){if(t.ctrlKey||t.metaKey){return["KeyA","KeyC"].includes(t.code)}return["Tab","Escape","ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End","PageUp","PageDown"].includes(t.key)}isActivationKey(t){return"Enter"===t.key||" "===t.key}},p=new Set,b=new Map;
267
357
  /**
268
358
  * @license
269
359
  * Copyright 2023 Nuraly, Laabidi Aymen
270
360
  * SPDX-License-Identifier: MIT
271
361
  */
272
- const f=t=>{class e extends t{constructor(){super(...arguments),this.t=null}createRenderRoot(){return this.constructor.useShadowDom?super.createRenderRoot():this}connectedCallback(){const t=this.constructor.useShadowDom;if(!t&&null===this.t)for(this.t=[];this.firstChild;)this.t.push(this.removeChild(this.firstChild));if(super.connectedCallback(),!t){const t=this.constructor,e=this.tagName.toLowerCase(),i=t.styles;if(i){const t=g(i);t&&function(t,e,i){var o;if(!b.has(t)){const i=new CSSStyleSheet;i.replaceSync(e),b.set(t,i)}const s=b.get(t),n=`doc:${t}`;if(p.has(n)||(document.adoptedStyleSheets=[...document.adoptedStyleSheets,s],p.add(n)),i){let e=i;for(;e;){const i=e.getRootNode();if(!(i instanceof ShadowRoot))break;{const n=`shadow:${((null===(o=i.host)||void 0===o?void 0:o.tagName)||"").toLowerCase()}:${t}`;p.has(n)||(i.adoptedStyleSheets=[...i.adoptedStyleSheets,s],p.add(n)),e=i.host}}}}(e,t,this)}}}get lightChildren(){return this.t?this.t.filter(t=>!(t instanceof Element&&t.hasAttribute("slot"))):[]}lightChildrenNamed(t){return this.t?this.t.filter(e=>e instanceof Element&&e.getAttribute("slot")===t):[]}}return e.useShadowDom=!1,e};function g(t){return Array.isArray(t)?t.map(t=>g(t)).filter(Boolean).join("\n"):t&&"string"==typeof t.cssText?t.cssText:"string"==typeof t?t:""}
362
+ const g=t=>{class e extends t{constructor(){super(...arguments),this.t=null}createRenderRoot(){return this.constructor.useShadowDom?super.createRenderRoot():this}connectedCallback(){const t=this.constructor.useShadowDom;if(!t&&null===this.t)for(this.t=[];this.firstChild;)this.t.push(this.removeChild(this.firstChild));if(super.connectedCallback(),!t){const t=this.constructor,e=this.tagName.toLowerCase(),o=t.styles;if(o){const t=y(o);t&&function(t,e,o){var i;if(!b.has(t)){const o=new CSSStyleSheet;o.replaceSync(e),b.set(t,o)}const n=b.get(t),r=`doc:${t}`;if(p.has(r)||(document.adoptedStyleSheets=[...document.adoptedStyleSheets,n],p.add(r)),o){let e=o;for(;e;){const o=e.getRootNode();if(!(o instanceof ShadowRoot))break;{const r=`shadow:${((null===(i=o.host)||void 0===i?void 0:i.tagName)||"").toLowerCase()}:${t}`;p.has(r)||(o.adoptedStyleSheets=[...o.adoptedStyleSheets,n],p.add(r)),e=o.host}}}}(e,t,this)}}}get lightChildren(){return this.t?this.t.filter(t=>!(t instanceof Element&&t.hasAttribute("slot"))):[]}lightChildrenNamed(t){return this.t?this.t.filter(e=>e instanceof Element&&e.getAttribute("slot")===t):[]}}return e.useShadowDom=!1,e};function y(t){return Array.isArray(t)?t.map(t=>y(t)).filter(Boolean).join("\n"):t&&"string"==typeof t.cssText?t.cssText:"string"==typeof t?t:""}
273
363
  /**
274
364
  * @license
275
365
  * Copyright 2023 Nuraly, Laabidi Aymen
276
366
  * SPDX-License-Identifier: MIT
277
- */class y{constructor(t){this._host=t,t.addController(this)}get host(){return this._host}hostConnected(){}hostDisconnected(){}hostUpdate(){}hostUpdated(){}requestUpdate(){try{this._host.requestUpdate()}catch(t){this.handleError(t,"requestUpdate")}}dispatchEvent(t){try{return this._host.dispatchEvent(t)}catch(t){return this.handleError(t,"dispatchEvent"),!1}}handleError(t,e){console.error(`[${this.constructor.name}] Error in ${e}:`,t);try{this._host.dispatchEvent(new CustomEvent("nr-controller-error",{detail:{error:t.message,context:e,controller:this.constructor.name},bubbles:!0,composed:!0}))}catch(t){}}safeExecute(t,e,i){try{return t()}catch(t){return this.handleError(t,e),i}}debounce(t,e){let i;const o=(...o)=>{void 0!==i&&clearTimeout(i),i=setTimeout(()=>{i=void 0,t.apply(this,o)},e)};return o.cancel=()=>{void 0!==i&&(clearTimeout(i),i=void 0)},o}}
367
+ */class f{constructor(t){this._host=t,t.addController(this)}get host(){return this._host}hostConnected(){}hostDisconnected(){}hostUpdate(){}hostUpdated(){}requestUpdate(){try{this._host.requestUpdate()}catch(t){this.handleError(t,"requestUpdate")}}dispatchEvent(t){try{return this._host.dispatchEvent(t)}catch(t){return this.handleError(t,"dispatchEvent"),!1}}handleError(t,e){console.error(`[${this.constructor.name}] Error in ${e}:`,t);try{this._host.dispatchEvent(new CustomEvent("nr-controller-error",{detail:{error:t.message,context:e,controller:this.constructor.name},bubbles:!0,composed:!0}))}catch(t){}}safeExecute(t,e,o){try{return t()}catch(t){return this.handleError(t,e),o}}debounce(t,e){let o;const i=(...i)=>{void 0!==o&&clearTimeout(o),o=setTimeout(()=>{o=void 0,t.apply(this,i)},e)};return i.cancel=()=>{void 0!==o&&(clearTimeout(o),o=void 0)},i}}
278
368
  /**
279
369
  * @license
280
370
  * Copyright 2023 Nuraly, Laabidi Aymen
281
371
  * SPDX-License-Identifier: MIT
282
- */class m extends y{}
372
+ */class m extends f{}
283
373
  /**
284
374
  * @license
285
375
  * Copyright 2023 Nuraly, Laabidi Aymen
286
376
  * SPDX-License-Identifier: MIT
287
- */class v extends m{createRipple(t){try{if(!this.host.ripple||this.host.disabled)return;const e=t.currentTarget,i=e.getBoundingClientRect(),o=2*Math.max(i.width,i.height),s=t.clientX-i.left-o/2,n=t.clientY-i.top-o/2,r=document.createElement("span");r.className="ripple",r.style.width=r.style.height=o+"px",r.style.left=s+"px",r.style.top=n+"px";e.querySelectorAll(".ripple").forEach(t=>t.remove()),e.appendChild(r),setTimeout(()=>{r.remove()},600)}catch(t){this.handleError(t,"createRipple")}}handleRippleClick(t){try{this.createRipple(t),this.dispatchEvent(new CustomEvent("button-click",{detail:{disabled:this.host.disabled,timestamp:Date.now(),coordinates:{x:t.clientX,y:t.clientY}},bubbles:!0,composed:!0}))}catch(t){this.handleError(t,"handleRippleClick")}}}
377
+ */class v extends m{createRipple(t){try{if(!this.host.ripple||this.host.disabled)return;const e=t.currentTarget,o=e.getBoundingClientRect(),i=2*Math.max(o.width,o.height),n=t.clientX-o.left-i/2,r=t.clientY-o.top-i/2,s=document.createElement("span");s.className="ripple",s.style.width=s.style.height=i+"px",s.style.left=n+"px",s.style.top=r+"px";e.querySelectorAll(".ripple").forEach(t=>t.remove()),e.appendChild(s),setTimeout(()=>{s.remove()},600)}catch(t){this.handleError(t,"createRipple")}}handleRippleClick(t){try{this.createRipple(t),this.dispatchEvent(new CustomEvent("button-click",{detail:{disabled:this.host.disabled,timestamp:Date.now(),coordinates:{x:t.clientX,y:t.clientY}},bubbles:!0,composed:!0}))}catch(t){this.handleError(t,"handleRippleClick")}}}
288
378
  /**
289
379
  * @license
290
380
  * Copyright 2023 Nuraly, Laabidi Aymen
@@ -299,31 +389,31 @@ const f=t=>{class e extends t{constructor(){super(...arguments),this.t=null}crea
299
389
  * @license
300
390
  * Copyright 2023 Nuraly, Laabidi Aymen
301
391
  * SPDX-License-Identifier: MIT
302
- */var $=function(t,e,i,o){for(var s,n=arguments.length,r=n<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,i):o,a=t.length-1;a>=0;a--)(s=t[a])&&(r=(n<3?s(r):n>3?s(e,i,r):s(e,i))||r);return n>3&&r&&Object.defineProperty(e,i,r),r};let x=class extends((t=>c(h(u(f(t)))))(o)){constructor(){super(...arguments),this.disabled=!1,this.loading=!1,this.size=a,this.type="default",this.shape="default",this.block=!1,this.dashed=!1,this.icon=[],this.iconPosition="left",this.href=a,this.target=a,this.ripple=!0,this.buttonAriaLabel=a,this.ariaDescribedBy=a,this.htmlType=a,this.requiredComponents=["nr-icon"],this.rippleController=new v(this),this.keyboardController=new w(this),this.linkController=new k(this)}connectedCallback(){super.connectedCallback(),this.validateDependencies()}getCommonAttributes(){return{"data-type":this.type,"data-shape":this.shape,"data-size":this.size||e,"data-state":this.loading?"loading":e,"data-block":this.block?"true":e,class:this.dashed?"button-dashed":"","aria-disabled":this.disabled?"true":"false","aria-label":this.buttonAriaLabel||e,"aria-describedby":this.ariaDescribedBy||e,tabindex:this.disabled?"-1":"0"}}renderIcon(t){if(!this.isComponentAvailable("nr-icon")){const i="string"==typeof t?t:t.name;return console.warn(`[nr-button] Icon component 'nr-icon' not available. Icon "${i}" will not render. Ensure the icon component is imported and registered.`),e}const o=()=>{switch(this.size){case"small":return"small";case"medium":default:return"medium";case"large":return"large"}};if("string"==typeof t){const e=o();return i`<nr-icon name=${t} size=${r(e)}></nr-icon>`}const{name:s,type:n="solid",size:a,color:d,alt:h}=t,l=a||o();return i`<nr-icon
303
- name=${s}
304
- type=${n}
305
- alt=${h||""}
306
- size=${r(l)}
392
+ */var x=function(t,e,o,i){for(var n,r=arguments.length,s=r<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,o):i,a=t.length-1;a>=0;a--)(n=t[a])&&(s=(r<3?n(s):r>3?n(e,o,s):n(e,o))||s);return r>3&&s&&Object.defineProperty(e,o,s),s};let $=class extends((t=>l(c(u(g(t)))))(i)){constructor(){super(...arguments),this.disabled=!1,this.loading=!1,this.size=a,this.type="default",this.shape="default",this.block=!1,this.dashed=!1,this.icon=[],this.iconPosition="left",this.href=a,this.target=a,this.ripple=!0,this.buttonAriaLabel=a,this.ariaDescribedBy=a,this.htmlType=a,this.requiredComponents=["nr-icon"],this.rippleController=new v(this),this.keyboardController=new w(this),this.linkController=new k(this)}connectedCallback(){super.connectedCallback(),this.validateDependencies()}getCommonAttributes(){return{"data-type":this.type,"data-shape":this.shape,"data-size":this.size||e,"data-state":this.loading?"loading":e,"data-block":this.block?"true":e,class:this.dashed?"button-dashed":"","aria-disabled":this.disabled?"true":"false","aria-label":this.buttonAriaLabel||e,"aria-describedby":this.ariaDescribedBy||e,tabindex:this.disabled?"-1":"0"}}renderIcon(t){if(!this.isComponentAvailable("nr-icon")){const o="string"==typeof t?t:t.name;return console.warn(`[nr-button] Icon component 'nr-icon' not available. Icon "${o}" will not render. Ensure the icon component is imported and registered.`),e}const i=()=>{switch(this.size){case"small":return"small";case"medium":default:return"medium";case"large":return"large"}};if("string"==typeof t){const e=i();return o`<nr-icon name=${t} size=${s(e)}></nr-icon>`}const{name:n,type:r="solid",size:a,color:d,alt:c}=t,h=a||i();return o`<nr-icon
393
+ name=${n}
394
+ type=${r}
395
+ alt=${c||""}
396
+ size=${s(h)}
307
397
  color=${d||""}
308
- ></nr-icon>`}handleClick(t){this.disabled?t.preventDefault():(this.rippleController.handleRippleClick(t),this.linkController.isLinkType()&&this.linkController.handleLinkNavigation(t),this.dispatchEventWithMetadata("button-clicked",{type:this.type,disabled:this.disabled,loading:this.loading,href:this.href||null}))}handleKeydown(t){this.keyboardController.handleKeydown(t)}getResolvedLeftIcon(){var t,e;return this.iconLeft?this.iconLeft:(null===(t=this.icons)||void 0===t?void 0:t.left)?this.icons.left:(null===(e=this.icon)||void 0===e?void 0:e.length)>0?this.icon[0]:void 0}getResolvedRightIcon(){var t,e;return this.iconRight?this.iconRight:(null===(t=this.icons)||void 0===t?void 0:t.right)?this.icons.right:2===(null===(e=this.icon)||void 0===e?void 0:e.length)?this.icon[1]:void 0}render(){const t=this.linkController.getElementTag(),o=this.getCommonAttributes(),s=this.linkController.getLinkAttributes(),n=this.getResolvedLeftIcon(),r=this.getResolvedRightIcon(),a=i`
398
+ ></nr-icon>`}handleClick(t){if(this.disabled||this.loading)return t.preventDefault(),void t.stopImmediatePropagation();this.rippleController.handleRippleClick(t),this.linkController.isLinkType()&&this.linkController.handleLinkNavigation(t),this.dispatchEventWithMetadata("button-clicked",{type:this.type,disabled:this.disabled,loading:this.loading,href:this.href||null})}handleKeydown(t){this.keyboardController.handleKeydown(t)}getResolvedLeftIcon(){var t,e;return this.iconLeft?this.iconLeft:(null===(t=this.icons)||void 0===t?void 0:t.left)?this.icons.left:(null===(e=this.icon)||void 0===e?void 0:e.length)>0?this.icon[0]:void 0}getResolvedRightIcon(){var t,e;return this.iconRight?this.iconRight:(null===(t=this.icons)||void 0===t?void 0:t.right)?this.icons.right:2===(null===(e=this.icon)||void 0===e?void 0:e.length)?this.icon[1]:void 0}render(){const t=this.linkController.getElementTag(),i=this.getCommonAttributes(),n=this.linkController.getLinkAttributes(),r=this.getResolvedLeftIcon(),s=this.getResolvedRightIcon(),a=o`<span part="spinner" class="button-spinner" aria-hidden="true"></span>`,d=o`
309
399
  <span part="container" class="button-container">
310
- ${n?this.renderIcon(n):e}
400
+ ${this.loading?a:r?this.renderIcon(r):e}
311
401
  <slot></slot>
312
- ${r?this.renderIcon(r):e}
402
+ ${!this.loading&&s?this.renderIcon(s):e}
313
403
  </span>
314
- `;return"a"===t?i`
404
+ `;return"a"===t?o`
315
405
  <a
316
406
  part="button"
317
- href="${s.href}"
318
- target="${s.target||e}"
319
- rel="${s.rel||e}"
320
- role="${s.role}"
321
- data-type="${o["data-type"]}"
322
- data-shape="${o["data-shape"]}"
323
- data-size="${o["data-size"]}"
324
- data-state="${o["data-state"]}"
325
- data-block="${o["data-block"]}"
326
- class="${o.class}"
407
+ href="${n.href}"
408
+ target="${n.target||e}"
409
+ rel="${n.rel||e}"
410
+ role="${n.role}"
411
+ data-type="${i["data-type"]}"
412
+ data-shape="${i["data-shape"]}"
413
+ data-size="${i["data-size"]}"
414
+ data-state="${i["data-state"]}"
415
+ data-block="${i["data-block"]}"
416
+ class="${i.class}"
327
417
  aria-disabled="${this.disabled}"
328
418
  aria-label="${this.buttonAriaLabel||e}"
329
419
  aria-describedby="${this.ariaDescribedBy||e}"
@@ -331,20 +421,21 @@ const f=t=>{class e extends t{constructor(){super(...arguments),this.t=null}crea
331
421
  @click="${this.handleClick}"
332
422
  @keydown="${this.handleKeydown}"
333
423
  >
334
- ${a}
424
+ ${d}
335
425
  </a>
336
- `:i`
426
+ `:o`
337
427
  <button
338
428
  part="button"
339
- ?disabled="${this.disabled}"
429
+ ?disabled="${this.disabled||this.loading}"
430
+ aria-busy="${this.loading?"true":"false"}"
340
431
  type="${this.htmlType||"button"}"
341
- role="${s.role}"
342
- data-type="${o["data-type"]}"
343
- data-shape="${o["data-shape"]}"
344
- data-size="${o["data-size"]}"
345
- data-state="${o["data-state"]}"
346
- data-block="${o["data-block"]}"
347
- class="${o.class}"
432
+ role="${n.role}"
433
+ data-type="${i["data-type"]}"
434
+ data-shape="${i["data-shape"]}"
435
+ data-size="${i["data-size"]}"
436
+ data-state="${i["data-state"]}"
437
+ data-block="${i["data-block"]}"
438
+ class="${i.class}"
348
439
  aria-disabled="${this.disabled}"
349
440
  aria-label="${this.buttonAriaLabel||e}"
350
441
  aria-describedby="${this.ariaDescribedBy||e}"
@@ -352,6 +443,6 @@ const f=t=>{class e extends t{constructor(){super(...arguments),this.t=null}crea
352
443
  @click="${this.handleClick}"
353
444
  @keydown="${this.handleKeydown}"
354
445
  >
355
- ${a}
446
+ ${d}
356
447
  </button>
357
- `}};x.styles=d,x.useShadowDom=!0,$([s({type:Boolean})],x.prototype,"disabled",void 0),$([s({type:Boolean})],x.prototype,"loading",void 0),$([s({type:String})],x.prototype,"size",void 0),$([s({type:String,reflect:!0})],x.prototype,"type",void 0),$([s({type:String})],x.prototype,"shape",void 0),$([s({type:Boolean})],x.prototype,"block",void 0),$([s({type:Boolean})],x.prototype,"dashed",void 0),$([s({type:Array})],x.prototype,"icon",void 0),$([s({type:Object})],x.prototype,"iconLeft",void 0),$([s({type:Object})],x.prototype,"iconRight",void 0),$([s({type:Object})],x.prototype,"icons",void 0),$([s({reflect:!0})],x.prototype,"iconPosition",void 0),$([s({type:String})],x.prototype,"href",void 0),$([s({type:String})],x.prototype,"target",void 0),$([s({type:Boolean})],x.prototype,"ripple",void 0),$([s({type:String})],x.prototype,"buttonAriaLabel",void 0),$([s({type:String})],x.prototype,"ariaDescribedBy",void 0),$([s({type:String})],x.prototype,"htmlType",void 0),x=$([n("nr-button")],x);export{x as NrButtonElement};
448
+ `}};$.styles=d,$.useShadowDom=!0,x([n({type:Boolean})],$.prototype,"disabled",void 0),x([n({type:Boolean})],$.prototype,"loading",void 0),x([n({type:String})],$.prototype,"size",void 0),x([n({type:String,reflect:!0})],$.prototype,"type",void 0),x([n({type:String})],$.prototype,"shape",void 0),x([n({type:Boolean})],$.prototype,"block",void 0),x([n({type:Boolean})],$.prototype,"dashed",void 0),x([n({type:Array})],$.prototype,"icon",void 0),x([n({type:Object})],$.prototype,"iconLeft",void 0),x([n({type:Object})],$.prototype,"iconRight",void 0),x([n({type:Object})],$.prototype,"icons",void 0),x([n({reflect:!0})],$.prototype,"iconPosition",void 0),x([n({type:String})],$.prototype,"href",void 0),x([n({type:String})],$.prototype,"target",void 0),x([n({type:Boolean})],$.prototype,"ripple",void 0),x([n({type:String})],$.prototype,"buttonAriaLabel",void 0),x([n({type:String})],$.prototype,"ariaDescribedBy",void 0),x([n({type:String})],$.prototype,"htmlType",void 0),$=x([r("nr-button")],$);export{$ as NrButtonElement};
@@ -141,8 +141,9 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
141
141
  ></nr-icon>`;
142
142
  }
143
143
  handleClick(event) {
144
- if (this.disabled) {
144
+ if (this.disabled || this.loading) {
145
145
  event.preventDefault();
146
+ event.stopImmediatePropagation();
146
147
  return;
147
148
  }
148
149
  this.rippleController.handleRippleClick(event);
@@ -193,11 +194,12 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
193
194
  const linkAttributes = this.linkController.getLinkAttributes();
194
195
  const leftIcon = this.getResolvedLeftIcon();
195
196
  const rightIcon = this.getResolvedRightIcon();
197
+ const spinner = html `<span part="spinner" class="button-spinner" aria-hidden="true"></span>`;
196
198
  const content = html `
197
199
  <span part="container" class="button-container">
198
- ${leftIcon ? this.renderIcon(leftIcon) : nothing}
200
+ ${this.loading ? spinner : (leftIcon ? this.renderIcon(leftIcon) : nothing)}
199
201
  <slot></slot>
200
- ${rightIcon ? this.renderIcon(rightIcon) : nothing}
202
+ ${!this.loading && rightIcon ? this.renderIcon(rightIcon) : nothing}
201
203
  </span>
202
204
  `;
203
205
  if (elementTag === 'a') {
@@ -228,7 +230,8 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
228
230
  return html `
229
231
  <button
230
232
  part="button"
231
- ?disabled="${this.disabled}"
233
+ ?disabled="${this.disabled || this.loading}"
234
+ aria-busy="${this.loading ? 'true' : 'false'}"
232
235
  type="${(this.htmlType || 'button')}"
233
236
  role="${linkAttributes.role}"
234
237
  data-type="${commonAttributes['data-type']}"
@@ -212,7 +212,26 @@ export const buttonStyles = css `
212
212
  /* ======== Loading ======== */
213
213
  :host([loading]) button {
214
214
  cursor: not-allowed;
215
- opacity: 0.5;
215
+ opacity: 0.7;
216
+ }
217
+
218
+ .button-spinner {
219
+ display: inline-block;
220
+ width: 1em;
221
+ height: 1em;
222
+ border: 2px solid currentColor;
223
+ border-right-color: transparent;
224
+ border-radius: 50%;
225
+ animation: nr-button-spin 0.75s linear infinite;
226
+ flex-shrink: 0;
227
+ box-sizing: border-box;
228
+ }
229
+
230
+ :host([size="small"]) .button-spinner { width: 0.875em; height: 0.875em; border-width: 2px; }
231
+ :host([size="large"]) .button-spinner { width: 1.125em; height: 1.125em; border-width: 2px; }
232
+
233
+ @keyframes nr-button-spin {
234
+ to { transform: rotate(360deg); }
216
235
  }
217
236
 
218
237
  /* ======== Shape: Round ======== */
@@ -237,9 +256,80 @@ export const buttonStyles = css `
237
256
  height: 44px;
238
257
  }
239
258
 
240
- /* ======== Dashed ======== */
259
+ /* ======== Dashed ========
260
+ * Dashed turns any type into an outlined style so the dashed pattern
261
+ * is visible against a transparent background (filled variants otherwise
262
+ * hide the border because border-color matches background-color).
263
+ */
241
264
  button.button-dashed {
242
265
  border-style: dashed;
266
+ border-width: 1px;
267
+ }
268
+
269
+ :host([type="primary"]) button.button-dashed {
270
+ background-color: transparent;
271
+ border-color: #7c3aed;
272
+ color: #7c3aed;
273
+ }
274
+ :host([type="primary"]) button.button-dashed nr-icon {
275
+ color: #7c3aed !important;
276
+ }
277
+ :host([type="primary"]) button.button-dashed:hover:not(:disabled) {
278
+ background-color: rgba(124, 58, 237, 0.08);
279
+ border-color: #6d28d9;
280
+ color: #6d28d9;
281
+ }
282
+ :host([type="primary"]) button.button-dashed:active:not(:disabled) {
283
+ background-color: rgba(124, 58, 237, 0.15);
284
+ filter: none;
285
+ }
286
+
287
+ :host([type="secondary"]) button.button-dashed {
288
+ background-color: transparent;
289
+ border-color: #0f1419;
290
+ color: #0f1419;
291
+ }
292
+ :host([type="secondary"]) button.button-dashed:hover:not(:disabled) {
293
+ background-color: rgba(15, 20, 25, 0.06);
294
+ border-color: #272c30;
295
+ color: #272c30;
296
+ }
297
+ :host([type="secondary"]) button.button-dashed:active:not(:disabled) {
298
+ background-color: rgba(15, 20, 25, 0.12);
299
+ }
300
+
301
+ :host([type="default"]) button.button-dashed {
302
+ background-color: #fff;
303
+ border-color: #8c8c8c;
304
+ color: #536471;
305
+ }
306
+ :host([type="default"]) button.button-dashed:hover:not(:disabled) {
307
+ border-color: #7c3aed;
308
+ color: #7c3aed;
309
+ background-color: #fff;
310
+ }
311
+
312
+ :host([type="ghost"]) button.button-dashed {
313
+ background-color: transparent;
314
+ border-color: #7c3aed;
315
+ color: #7c3aed;
316
+ }
317
+
318
+ :host([type="danger"]) button.button-dashed {
319
+ background-color: transparent;
320
+ border-color: #dc2626;
321
+ color: #dc2626;
322
+ }
323
+ :host([type="danger"]) button.button-dashed nr-icon {
324
+ color: #dc2626 !important;
325
+ }
326
+ :host([type="danger"]) button.button-dashed:hover:not(:disabled) {
327
+ background-color: rgba(220, 38, 38, 0.08);
328
+ filter: none;
329
+ }
330
+ :host([type="danger"]) button.button-dashed:active:not(:disabled) {
331
+ background-color: rgba(220, 38, 38, 0.15);
332
+ filter: none;
243
333
  }
244
334
 
245
335
  /* ======== Ripple ======== */
@@ -34,6 +34,8 @@ export declare abstract class BaseCanvasElement extends BaseCanvasElement_base i
34
34
  showPalette: boolean;
35
35
  canvasId: string;
36
36
  collaborative: boolean;
37
+ userId: string;
38
+ namespace: string;
37
39
  get undoProvider(): UndoProvider | null;
38
40
  set undoProvider(provider: UndoProvider | null);
39
41
  viewport: CanvasViewport;
@@ -170,6 +172,12 @@ export declare abstract class BaseCanvasElement extends BaseCanvasElement_base i
170
172
  protected renderEmptyState(): typeof nothing | import("lit-html").TemplateResult;
171
173
  protected renderMarqueeBox(): import("lit-html").TemplateResult<1>;
172
174
  protected renderRemoteCursors(): typeof nothing | import("lit-html").TemplateResult<1>[];
175
+ /**
176
+ * Render the "{user} is editing" pills above every node that a remote user
177
+ * currently holds a lock on. Meant to be rendered inside the viewport-
178
+ * transformed nodes layer so coordinates stay in canvas space.
179
+ */
180
+ protected renderNodeLockOverlays(): typeof nothing | import("lit-html").TemplateResult<1>[];
173
181
  protected handlePanToUser(userId: string): void;
174
182
  protected renderPresenceBar(): typeof nothing | import("lit-html").TemplateResult<1>;
175
183
  protected renderConfigPanel(): typeof nothing | import("lit-html").TemplateResult;
@@ -30,7 +30,7 @@ import { ChatbotCoreController } from '../chatbot/core/chatbot-core.controller.j
30
30
  // Controllers
31
31
  import { ViewportController, SelectionController, ConnectionController, KeyboardController, DragController, ConfigController, MarqueeController, ClipboardController, UndoController, FrameController, CollaborationController, TouchController, } from './controllers/index.js';
32
32
  // Templates
33
- import { renderToolbarTemplate, renderZoomControlsTemplate, renderContextMenuTemplate, renderEmptyStateTemplate, renderConfigPanelTemplate, renderEdgesTemplate, renderRemoteCursorsTemplate, renderPresenceBarTemplate, renderChatbotPanelTemplate, } from './templates/index.js';
33
+ import { renderToolbarTemplate, renderZoomControlsTemplate, renderContextMenuTemplate, renderEmptyStateTemplate, renderConfigPanelTemplate, renderEdgesTemplate, renderRemoteCursorsTemplate, renderPresenceBarTemplate, renderChatbotPanelTemplate, renderLockOverlayTemplate, } from './templates/index.js';
34
34
  import { renderExpandedFrameTemplate } from './templates/frame.template.js';
35
35
  // Constants
36
36
  import { FRAME_DEFAULT_WIDTH, FRAME_DEFAULT_HEIGHT, FRAME_DEFAULT_LABEL, NOTE_MIN_WIDTH, NOTE_MIN_HEIGHT, VIEWPORT_ADD_NODE_OFFSET_X, VIEWPORT_ADD_NODE_OFFSET_Y, } from './canvas.constants.js';
@@ -78,6 +78,8 @@ export class BaseCanvasElement extends NuralyUIBaseMixin(LitElement) {
78
78
  this.showPalette = false;
79
79
  this.canvasId = '';
80
80
  this.collaborative = false;
81
+ this.userId = '';
82
+ this.namespace = '';
81
83
  // ==================== State ====================
82
84
  this.viewport = { zoom: 1, panX: 0, panY: 0 };
83
85
  this.mode = CanvasMode.SELECT;
@@ -314,8 +316,8 @@ export class BaseCanvasElement extends NuralyUIBaseMixin(LitElement) {
314
316
  globalThis.addEventListener('mousemove', this.handleGlobalMouseMove);
315
317
  yield this.updateComplete;
316
318
  this.viewportController.updateTransform();
317
- if (this.collaborative && this.canvasId) {
318
- this.collaborationController.connect(this.canvasId, this.getCanvasType());
319
+ if (this.collaborative && this.canvasId && this.namespace && this.userId) {
320
+ this.collaborationController.connect(this.canvasId, this.namespace, this.userId);
319
321
  }
320
322
  this.onConnected();
321
323
  });
@@ -328,9 +330,51 @@ export class BaseCanvasElement extends NuralyUIBaseMixin(LitElement) {
328
330
  }
329
331
  willUpdate(changedProperties) {
330
332
  super.willUpdate(changedProperties);
333
+ // Collaboration props (collaborative/canvasId/namespace/userId) often
334
+ // arrive after connectedCallback — the host page sets them once the
335
+ // workflow has loaded. (Re)try the connection whenever any of them
336
+ // change so we don't silently stay offline.
337
+ if (changedProperties.has('collaborative') ||
338
+ changedProperties.has('canvasId') ||
339
+ changedProperties.has('namespace') ||
340
+ changedProperties.has('userId')) {
341
+ console.log('[collab] willUpdate collab props', {
342
+ collaborative: this.collaborative,
343
+ canvasId: this.canvasId,
344
+ namespace: this.namespace,
345
+ userId: this.userId,
346
+ changed: {
347
+ collaborative: changedProperties.has('collaborative'),
348
+ canvasId: changedProperties.has('canvasId'),
349
+ namespace: changedProperties.has('namespace'),
350
+ userId: changedProperties.has('userId'),
351
+ },
352
+ });
353
+ if (this.collaborative && this.canvasId && this.namespace && this.userId) {
354
+ this.collaborationController.connect(this.canvasId, this.namespace, this.userId);
355
+ }
356
+ }
331
357
  if (this.collaborative && changedProperties.has('selectedNodeIds')) {
332
358
  this.collaborationController.broadcastSelectionChange(Array.from(this.selectedNodeIds));
333
359
  }
360
+ if (this.collaborative && changedProperties.has('configuredNode')) {
361
+ const prev = changedProperties.get('configuredNode');
362
+ let next = this.configuredNode;
363
+ console.log('[collab] configuredNode change', { prevId: prev === null || prev === void 0 ? void 0 : prev.id, nextId: next === null || next === void 0 ? void 0 : next.id });
364
+ // Reject opening a node that is currently held by a remote user.
365
+ if (next && this.collaborationController.getRemoteLock(next.id)) {
366
+ this.configuredNode = prev !== null && prev !== void 0 ? prev : null;
367
+ next = this.configuredNode;
368
+ }
369
+ // Release stale lock when the focused node changes or the panel closes.
370
+ if (prev && (!next || prev.id !== next.id)) {
371
+ this.collaborationController.releaseLock(prev.id);
372
+ }
373
+ // Acquire on open or on switch. Re-acquiring the same id is a refresh.
374
+ if (next && (!prev || prev.id !== next.id)) {
375
+ this.collaborationController.acquireLock(next.id);
376
+ }
377
+ }
334
378
  }
335
379
  // ==================== CanvasHost Interface ====================
336
380
  setWorkflow(workflow) {
@@ -718,6 +762,28 @@ export class BaseCanvasElement extends NuralyUIBaseMixin(LitElement) {
718
762
  viewport: this.viewport,
719
763
  });
720
764
  }
765
+ /**
766
+ * Render the "{user} is editing" pills above every node that a remote user
767
+ * currently holds a lock on. Meant to be rendered inside the viewport-
768
+ * transformed nodes layer so coordinates stay in canvas space.
769
+ */
770
+ renderNodeLockOverlays() {
771
+ if (!this.collaborative)
772
+ return nothing;
773
+ const locks = this.collaborationController.getState().lockedNodes;
774
+ if (locks.size === 0)
775
+ return nothing;
776
+ const entries = [];
777
+ for (const [nodeId, lock] of locks) {
778
+ if (lock.userId === this.userId)
779
+ continue;
780
+ const node = this.workflow.nodes.find(n => n.id === nodeId);
781
+ if (!node)
782
+ continue;
783
+ entries.push({ nodeId, x: node.position.x, y: node.position.y, lock });
784
+ }
785
+ return renderLockOverlayTemplate(entries);
786
+ }
721
787
  handlePanToUser(userId) {
722
788
  const cursors = this.collaborationController.getCursors();
723
789
  const cursor = cursors.find(c => c.userId === userId);
@@ -791,6 +857,12 @@ __decorate([
791
857
  __decorate([
792
858
  property({ type: Boolean, attribute: 'collaborative' })
793
859
  ], BaseCanvasElement.prototype, "collaborative", void 0);
860
+ __decorate([
861
+ property({ type: String, attribute: 'user-id' })
862
+ ], BaseCanvasElement.prototype, "userId", void 0);
863
+ __decorate([
864
+ property({ type: String, attribute: 'namespace' })
865
+ ], BaseCanvasElement.prototype, "namespace", void 0);
794
866
  __decorate([
795
867
  property({ attribute: false })
796
868
  ], BaseCanvasElement.prototype, "undoProvider", null);