diff --git a/package-lock.json b/package-lock.json
index 800c76414..4ea58ffa7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"packages/*"
],
"devDependencies": {
- "@blockly/zoom-to-fit": "^13.0.0",
+ "@blockly/zoom-to-fit": "^13.2.0",
"@node-projects/base-custom-webcomponent": ">=0.27.8",
"@node-projects/css-parser": "^5.0.0",
"@node-projects/lean-he-esm": "^3.3.0",
@@ -22,7 +22,7 @@
"@types/jquery.fancytree": "0.0.11",
"@types/node": "^22.8.6",
"ace-builds": "^1.36.3",
- "blockly": "^13.0.0",
+ "blockly": "^13.2.1",
"codemirror": "^6.0.1",
"codemirror5": "npm:codemirror@^5.0.0",
"css-tree": "^3.0.0",
@@ -566,12 +566,12 @@
"license": "MIT"
},
"node_modules/@blockly/zoom-to-fit": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/@blockly/zoom-to-fit/-/zoom-to-fit-13.1.0.tgz",
- "integrity": "sha512-ch5C4Z+53kLujocgbyTAb4FZQptaQPJV2nSHlmpoP0O2C7ABRB14IR9/25FEMx4SZBkKv9N4cN/AFTipZvwPKw==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@blockly/zoom-to-fit/-/zoom-to-fit-13.2.0.tgz",
+ "integrity": "sha512-iAhmQONUm/MW5SBtzGOaiH3VLp/RjJL6+YxR73sh80K3+6GITv65bqn2XBXLLMW7H/5vmnwNU2EPp2V8CvVd5w==",
"license": "Apache-2.0",
"peerDependencies": {
- "blockly": "^13.1.0"
+ "blockly": "^13.2.0"
}
},
"node_modules/@braintree/sanitize-url": {
@@ -2733,15 +2733,15 @@
}
},
"node_modules/blockly": {
- "version": "13.1.1",
- "resolved": "https://registry.npmjs.org/blockly/-/blockly-13.1.1.tgz",
- "integrity": "sha512-0h3YDzlGclLKaZi9VHxyPjRJ9OFV6vw2+TMcolLZO1ZlgfY1Q79qDlGpH2nUYnTNiEVuJu9K6u6NHxqiPeRYOA==",
+ "version": "13.2.1",
+ "resolved": "https://registry.npmjs.org/blockly/-/blockly-13.2.1.tgz",
+ "integrity": "sha512-iOa37H0ks5Zup2G1zZyviLX9E5WzWh3h0Zs8Nta2cPKmnAGHjZ6wrp3VqLTaquTJReJKPwaJZ39K7AD24rT4lg==",
"license": "Apache-2.0",
"engines": {
"node": ">=22"
},
"peerDependencies": {
- "jsdom": "^27.4.0"
+ "jsdom": ">=27.4.0 <30.0.0"
}
},
"node_modules/brace-expansion": {
@@ -7111,7 +7111,7 @@
},
"packages/web-component-designer": {
"name": "@node-projects/web-component-designer",
- "version": "0.2.30",
+ "version": "0.2.31",
"license": "MIT",
"dependencies": {
"@node-projects/base-custom-webcomponent": ">=0.27.8"
@@ -7202,16 +7202,6 @@
"@node-projects/web-component-designer": ">=0.1.278"
}
},
- "packages/web-component-designer-liveblocks": {
- "name": "@node-projects/web-component-designer-liveblocks",
- "version": "0.1.0",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@liveblocks/client": "^1.9.7",
- "@node-projects/web-component-designer": ">=0.1.1"
- }
- },
"packages/web-component-designer-mermaid": {
"name": "@node-projects/web-component-designer-mermaid",
"version": "0.1.1",
@@ -7222,17 +7212,6 @@
"mermaid": "^11.12.0"
}
},
- "packages/web-component-designer-miniatureview-html2canvas": {
- "name": "@node-projects/web-component-designer-miniatureview-html2canvas",
- "version": "0.1.3",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@node-projects/base-custom-webcomponent": ">=0.27.8",
- "@node-projects/web-component-designer": ">=0.1.224",
- "html2canvas": "*"
- }
- },
"packages/web-component-designer-stylesheetservice-css-parser": {
"name": "@node-projects/web-component-designer-stylesheetservice-css-parser",
"version": "0.1.5",
@@ -7242,43 +7221,12 @@
"@node-projects/web-component-designer": ">=0.1.224"
}
},
- "packages/web-component-designer-stylesheetservice-css-tools": {
- "name": "@node-projects/web-component-designer-stylesheetservice-css-tools",
- "version": "0.1.11",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@node-projects/css-parser": "^5.0.0",
- "@node-projects/web-component-designer": ">=0.1.224"
- }
- },
- "packages/web-component-designer-stylesheetservice-css-tree": {
- "name": "@node-projects/web-component-designer-stylesheetservice-css-tree",
- "version": "0.1.4",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@node-projects/web-component-designer": ">=0.1.224",
- "css-tree": ">=3.0.0"
- }
- },
- "packages/web-component-designer-texteditextension-stylo": {
- "name": "@node-projects/web-component-designer-texteditextension-stylo",
- "version": "0.1.4",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@node-projects/base-custom-webcomponent": ">=0.19.0",
- "@node-projects/web-component-designer": ">=0.1.1",
- "@papyrs/stylo": ">=0.0.45"
- }
- },
"packages/web-component-designer-visualization-addons": {
"name": "@node-projects/web-component-designer-visualization-addons",
- "version": "0.1.149",
+ "version": "0.1.152",
"license": "MIT",
"dependencies": {
- "@blockly/zoom-to-fit": ">=13.0.0",
+ "@blockly/zoom-to-fit": ">=13.2.0",
"@node-projects/base-custom-webcomponent": ">=0.27.8",
"@node-projects/css-parser": "^5.2.0",
"@node-projects/propertygrid.webcomponent": ">=1.2.3",
@@ -7286,25 +7234,13 @@
"@node-projects/web-component-designer": ">=0.1.224",
"@node-projects/web-component-designer-codeview-monaco": ">=0.1.32",
"@node-projects/web-component-designer-widgets-wunderbaum": ">=0.1.29",
- "blockly": ">=13.0.0",
+ "blockly": ">=13.2.1",
"long": ">=5.2.3"
},
"devDependencies": {
"esbuild": "^0.25.10"
}
},
- "packages/web-component-designer-widgets-fancytree": {
- "name": "@node-projects/web-component-designer-widgets-fancytree",
- "version": "0.1.16",
- "extraneous": true,
- "license": "MIT",
- "dependencies": {
- "@node-projects/base-custom-webcomponent": ">=0.27.8",
- "@node-projects/web-component-designer": ">=0.1.224",
- "jquery": "^3.7.1",
- "jquery.fancytree": "^2.38.3"
- }
- },
"packages/web-component-designer-widgets-wunderbaum": {
"name": "@node-projects/web-component-designer-widgets-wunderbaum",
"version": "0.2.1",
@@ -7317,7 +7253,7 @@
},
"packages/web-component-designer-zpl": {
"name": "@node-projects/web-component-designer-zpl",
- "version": "0.3.0",
+ "version": "0.3.2",
"license": "MIT",
"dependencies": {
"@bwip-js/browser": "4.11.2",
diff --git a/packages/web-component-designer-widgets-wunderbaum/src/Constants.ts b/packages/web-component-designer-widgets-wunderbaum/src/Constants.ts
index 9ca19392c..937ef1487 100644
--- a/packages/web-component-designer-widgets-wunderbaum/src/Constants.ts
+++ b/packages/web-component-designer-widgets-wunderbaum/src/Constants.ts
@@ -1,2 +1,30 @@
-let imporUrl = new URL((import.meta.url));
-export var assetsPath = imporUrl.origin + imporUrl.pathname.split('/').slice(0, -1).join('/') + '/../assets/';
\ No newline at end of file
+/** Used when the module URL cannot locate the assets and the host configured
+ * nothing. Document relative, so it follows a . */
+const fallbackAssetsPath = 'assets/web-component-designer-widgets-wunderbaum/';
+
+function resolveAssetsPath(): string {
+ const configured = (globalThis as { wunderbaumWidgetsAssetsPath?: string }).wunderbaumWidgetsAssetsPath;
+ if (configured)
+ return configured.endsWith('/') ? configured : configured + '/';
+
+ // Bundlers that do not rewrite import.meta.url replace it with the build
+ // machine's file:// path, whose origin is the string "null". Only a URL the
+ // browser can actually fetch locates the assets next to this module.
+ try {
+ const imporUrl = new URL((import.meta.url));
+ if (imporUrl.protocol === 'http:' || imporUrl.protocol === 'https:')
+ return imporUrl.origin + imporUrl.pathname.split('/').slice(0, -1).join('/') + '/../assets/';
+ } catch {
+ // import.meta.url unavailable or unparsable, fall through
+ }
+
+ return fallbackAssetsPath;
+}
+
+export var assetsPath = resolveAssetsPath();
+
+/** Overrides where these widgets load their icons from. Prefer setting
+ * globalThis.wunderbaumWidgetsAssetsPath before importing them. */
+export function setAssetsPath(path: string) {
+ assetsPath = path.endsWith('/') ? path : path + '/';
+}
\ No newline at end of file
diff --git a/packages/web-component-designer-zpl/src/Constants.ts b/packages/web-component-designer-zpl/src/Constants.ts
new file mode 100644
index 000000000..4976a44fa
--- /dev/null
+++ b/packages/web-component-designer-zpl/src/Constants.ts
@@ -0,0 +1,40 @@
+/** Used when the module URL cannot locate the package files and the host
+ * configured nothing. Document relative, so it follows a . */
+const fallbackBasePath = 'assets/web-component-designer-zpl/';
+
+function resolveBasePath(): string {
+ const configured = (globalThis as { webComponentDesignerZplBasePath?: string }).webComponentDesignerZplBasePath;
+ if (configured)
+ return configured.endsWith('/') ? configured : configured + '/';
+
+ // Bundlers that do not rewrite import.meta.url replace it with the build
+ // machine's file:// path, which the browser cannot fetch. Only a real URL
+ // locates widgets/elements.json and assets/fonts next to this module.
+ try {
+ const moduleUrl = new URL(import.meta.url);
+ if (moduleUrl.protocol === 'http:' || moduleUrl.protocol === 'https:')
+ return moduleUrl.origin + moduleUrl.pathname.split('/').slice(0, -1).join('/') + '/';
+ } catch {
+ // import.meta.url unavailable or unparsable, fall through
+ }
+
+ return fallbackBasePath;
+}
+
+/** Directory holding this package's runtime files: widgets/elements.json and
+ * assets/fonts. Both must be published by the host application. */
+export var zplBasePath = resolveBasePath();
+
+/** Overrides where the ZPL add-on loads its element definitions and printer
+ * fonts from. Prefer setting globalThis.webComponentDesignerZplBasePath before
+ * importing the add-on, so nothing reads the value before it is configured. */
+export function setZplBasePath(path: string) {
+ zplBasePath = path.endsWith('/') ? path : path + '/';
+}
+
+/** Resolves a package relative file against the configured base path, so a
+ * document relative default still produces an absolute URL. */
+export function zplPackageUrl(relativePath: string): URL {
+ const base = typeof document === 'undefined' ? undefined : document.baseURI;
+ return new URL(zplBasePath + relativePath, base);
+}
diff --git a/packages/web-component-designer-zpl/src/fonts/zplFonts.ts b/packages/web-component-designer-zpl/src/fonts/zplFonts.ts
index 48ca4b5db..afcd0b57f 100644
--- a/packages/web-component-designer-zpl/src/fonts/zplFonts.ts
+++ b/packages/web-component-designer-zpl/src/fonts/zplFonts.ts
@@ -1,3 +1,5 @@
+import { zplPackageUrl } from '../Constants.js';
+
export type ZplFontName = '0' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H';
export interface ZplDeviceFontMetrics {
@@ -78,7 +80,7 @@ export async function loadZplFonts(document: Document): Promise {
['ZplOCRA', 'OCRA.ttf']
] as const;
loading = Promise.all(sources.map(async ([family, file]) => {
- const url = new URL(`../assets/fonts/${file}`, import.meta.url);
+ const url = zplPackageUrl(`assets/fonts/${file}`);
const face = new FontFace(family, `url(${url})`);
await face.load();
document.fonts.add(face);
diff --git a/packages/web-component-designer-zpl/src/index.ts b/packages/web-component-designer-zpl/src/index.ts
index 8d96789f1..25157510b 100644
--- a/packages/web-component-designer-zpl/src/index.ts
+++ b/packages/web-component-designer-zpl/src/index.ts
@@ -23,4 +23,5 @@ export * from "./barcodes/barcodeRegistry.js";
export * from "./barcodes/bwipRenderer.js";
export * from "./fonts/zplFonts.js";
export * from "./setupZplServiceContainer.js";
-export * from "./zplHelper.js";
+export * from "./zplHelper.js";
+export * from "./Constants.js";
diff --git a/packages/web-component-designer-zpl/src/setupZplServiceContainer.ts b/packages/web-component-designer-zpl/src/setupZplServiceContainer.ts
index 46e7c76c1..e847a0d4c 100644
--- a/packages/web-component-designer-zpl/src/setupZplServiceContainer.ts
+++ b/packages/web-component-designer-zpl/src/setupZplServiceContainer.ts
@@ -1,4 +1,5 @@
import { DefaultPropertyEditorTypesService, DefaultEditorTypeService, ExtensionType, DefaultModelCommandService, DefaultHtmlParserService, JsonFileElementsService, ServiceContainer, PositionExtensionProvider, GrayOutExtensionProvider, AltToEnterContainerExtensionProvider, NamedTools, PointerTool, RectangleSelectorTool, ZoomTool, PanTool, MagicWandSelectorTool, ZMoveContextMenu, CopyPasteContextMenu, MultipleItemsSelectedContextMenu, ItemsBelowContextMenu, ElementDragTitleExtensionProvider, PointerToolButtonProvider, SeperatorToolProvider, SelectorToolButtonProvider, ZoomToolButtonProvider, HighlightElementExtensionProvider, IDesignerCanvas, SelectionService, UndoService, GrayOutDragOverContainerExtensionProvider, ElementAtPointService, SnaplinesProviderService, DefaultInstanceService, PropertyGroupsService, DesignItemDocumentPositionService, DragDropService, BaseCustomWebComponentPropertiesService, TransformToolButtonProvider, DesignItemService, DeletionService, ResizeExtensionProvider } from '@node-projects/web-component-designer';
+import { zplPackageUrl } from './Constants.js';
import { ZplLayoutPlacementService } from './services/ZplLayoutPlacementService.js';
import { ZplParserService } from './services/ZplParserService.js';
import { ZplImageDrop } from './services/ZplImageDrop.js';
@@ -100,7 +101,7 @@ export function createZplDesignerServiceContainer() {
serviceContainer.config.demoViewWidget = ZplDemoView;
- serviceContainer.register('elementsService', new JsonFileElementsService('zpl', new URL("./widgets/elements.json", import.meta.url)));
+ serviceContainer.register('elementsService', new JsonFileElementsService('zpl', zplPackageUrl('widgets/elements.json')));
serviceContainer.register('elementsService', new ZplBarcodeElementsService());
return serviceContainer;
diff --git a/packages/web-component-designer/src/Constants.ts b/packages/web-component-designer/src/Constants.ts
index 2bbba417c..034f9eb15 100644
--- a/packages/web-component-designer/src/Constants.ts
+++ b/packages/web-component-designer/src/Constants.ts
@@ -2,5 +2,36 @@ export const dragDropFormatNameElementDefinition = 'text/json/elementdefintion';
export const dragDropFormatNameBindingObject = 'text/json/bindingobject';
export const dragDropFormatNamePropertyGrid = 'text/json/propertydrop';
-let imporUrl = new URL((import.meta.url));
-export var assetsPath = imporUrl.origin + imporUrl.pathname.split('/').slice(0, -1).join('/') + '/../assets/';
\ No newline at end of file
+/** Used when the module URL cannot locate the assets and the host configured
+ * nothing. Document relative, so it follows a . */
+const fallbackAssetsPath = 'assets/web-component-designer/';
+
+function resolveAssetsPath(): string {
+ const configured = (globalThis as { webComponentDesignerAssetsPath?: string }).webComponentDesignerAssetsPath;
+ if (configured)
+ return configured.endsWith('/') ? configured : configured + '/';
+
+ // Bundlers that do not rewrite import.meta.url replace it with the build
+ // machine's file:// path, whose origin is the string "null". Only a URL the
+ // browser can actually fetch locates the assets next to this module.
+ try {
+ const imporUrl = new URL((import.meta.url));
+ if (imporUrl.protocol === 'http:' || imporUrl.protocol === 'https:')
+ return imporUrl.origin + imporUrl.pathname.split('/').slice(0, -1).join('/') + '/../assets/';
+ } catch {
+ // import.meta.url unavailable or unparsable, fall through
+ }
+
+ return fallbackAssetsPath;
+}
+
+export var assetsPath = resolveAssetsPath();
+
+/** Overrides where the designer loads its icons from.
+ *
+ * Prefer setting globalThis.webComponentDesignerAssetsPath before importing the
+ * designer: widgets such as SelectionToolPopup bake assetsPath into a static
+ * template while their module evaluates, and never observe a later change. */
+export function setAssetsPath(path: string) {
+ assetsPath = path.endsWith('/') ? path : path + '/';
+}
\ No newline at end of file
diff --git a/packages/web-component-designer/src/elements/documentContainer.ts b/packages/web-component-designer/src/elements/documentContainer.ts
index c84b7bd7a..ec2a5aa6e 100644
--- a/packages/web-component-designer/src/elements/documentContainer.ts
+++ b/packages/web-component-designer/src/elements/documentContainer.ts
@@ -240,8 +240,8 @@ export class DocumentContainer extends BaseCustomWebComponentLazyAppend implemen
this.designerView.instanceServiceContainer.collaborationService.disconnect();
this.designerView.instanceServiceContainer.collaborationService.detachTransport();
}
- this.codeView.dispose();
- this.demoView.dispose();
+ this.codeView?.dispose();
+ this.demoView?.dispose();
}
executeCommand(command: IUiCommand) {
diff --git a/packages/web-component-designer/src/elements/services/ServiceContainer.ts b/packages/web-component-designer/src/elements/services/ServiceContainer.ts
index 86f72387b..6c910a527 100644
--- a/packages/web-component-designer/src/elements/services/ServiceContainer.ts
+++ b/packages/web-component-designer/src/elements/services/ServiceContainer.ts
@@ -107,7 +107,8 @@ export class ServiceContainer extends BaseServiceContainer {
readonly config: {
codeViewWidget: new (...args: any[]) => ICodeView & HTMLElement;
- demoViewWidget: new (...args: any[]) => IDemoView & HTMLElement;
+ /** Null removes the preview tab, which DocumentContainer already checks for. */
+ demoViewWidget: (new (...args: any[]) => IDemoView & HTMLElement) | null;
openBindingsEditor?: (property: IProperty, designItems: IDesignItem[], binding: IBinding, bindingTarget: BindingTarget) => Promise
} = {
codeViewWidget: CodeViewSimple,