From 72d48f74f0134c8bbe4f3bf31d65030a2d4fe64a Mon Sep 17 00:00:00 2001 From: u8array Date: Tue, 5 May 2026 22:11:11 +0200 Subject: [PATCH 1/4] fix: enable height resize for Code 128, Code 39 and EAN-13 --- src/registry/code128.tsx | 4 ++++ src/registry/code39.tsx | 4 ++++ src/registry/ean13.tsx | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/registry/code128.tsx b/src/registry/code128.tsx index e029b72c..94ef0020 100644 --- a/src/registry/code128.tsx +++ b/src/registry/code128.tsx @@ -24,6 +24,10 @@ export const code128: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, + commitTransform: (obj, { sy, snap }) => ({ + height: Math.max(1, snap(Math.round(obj.props.height * sy))), + }), + toZPL: (obj) => { const p = obj.props; const interp = p.printInterpretation ? 'Y' : 'N'; diff --git a/src/registry/code39.tsx b/src/registry/code39.tsx index a689a05c..01599545 100644 --- a/src/registry/code39.tsx +++ b/src/registry/code39.tsx @@ -24,6 +24,10 @@ export const code39: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, + commitTransform: (obj, { sy, snap }) => ({ + height: Math.max(1, snap(Math.round(obj.props.height * sy))), + }), + toZPL: (obj) => { const p = obj.props; const interp = p.printInterpretation ? 'Y' : 'N'; diff --git a/src/registry/ean13.tsx b/src/registry/ean13.tsx index 42683bb9..e3ba7b4b 100644 --- a/src/registry/ean13.tsx +++ b/src/registry/ean13.tsx @@ -22,6 +22,10 @@ export const ean13: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, + commitTransform: (obj, { sy, snap }) => ({ + height: Math.max(1, snap(Math.round(obj.props.height * sy))), + }), + toZPL: (obj) => { const p = obj.props; const interp = p.printInterpretation ? 'Y' : 'N'; From 1b27d67bc21c600dd9cd315e1f8624d3f8099ef9 Mon Sep 17 00:00:00 2001 From: u8array Date: Tue, 5 May 2026 22:17:37 +0200 Subject: [PATCH 2/4] feat: declare heightLocked in object type definition for symbology-fixed barcodes --- src/components/Canvas/hooks/useKonvaTransformer.ts | 9 ++++++--- src/registry/barcode1d.tsx | 13 ++++++++++--- src/registry/gs1databar.tsx | 4 ++++ src/types/ObjectType.ts | 7 +++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/components/Canvas/hooks/useKonvaTransformer.ts b/src/components/Canvas/hooks/useKonvaTransformer.ts index e5b9ed91..d16183d9 100644 --- a/src/components/Canvas/hooks/useKonvaTransformer.ts +++ b/src/components/Canvas/hooks/useKonvaTransformer.ts @@ -190,12 +190,15 @@ export function useKonvaTransformer({ }, [selectedIds, selectedTypesKey, selectedSignature, stageRef, transformerRef]); const resizeEnabled = selectedIds.length <= 1; + const singleType = objects.find((o) => o.id === selectedIds[0])?.type ?? ""; const enabledAnchors: string[] | undefined = selectedIds.length > 1 ? [] - : BARCODE_1D_TYPES.has(objects.find((o) => o.id === selectedIds[0])?.type ?? "") - ? ["top-center", "bottom-center"] - : undefined; + : ObjectRegistry[singleType]?.heightLocked + ? [] + : BARCODE_1D_TYPES.has(singleType) + ? ["top-center", "bottom-center"] + : undefined; const isFreeResize = enabledAnchors === undefined; /** Reset all transform-time state. Idempotent; safe to call from any exit path. */ diff --git a/src/registry/barcode1d.tsx b/src/registry/barcode1d.tsx index b5d0a693..fbc12069 100644 --- a/src/registry/barcode1d.tsx +++ b/src/registry/barcode1d.tsx @@ -29,6 +29,8 @@ interface Barcode1DConfig { * here ensures Labelary uses the same ratio as the canvas rendering. */ byRatio?: number; + /** See {@link ObjectTypeDefinition.heightLocked}. */ + heightLocked?: boolean; } interface BarcodeLocale { @@ -53,10 +55,13 @@ export function createBarcode1D(config: Barcode1DConfig): ObjectTypeDefinition ({ - height: Math.max(1, snap(Math.round(obj.props.height * sy))), - }), + commitTransform: config.heightLocked + ? undefined + : (obj, { sy, snap }) => ({ + height: Math.max(1, snap(Math.round(obj.props.height * sy))), + }), toZPL: (obj: LabelObjectBase & { props: Barcode1DProps }) => { const p = obj.props; @@ -95,6 +100,8 @@ export function createBarcode1D(config: Barcode1DConfig): ObjectTypeDefinition onChange({ height: Number(e.target.value) })} /> diff --git a/src/registry/gs1databar.tsx b/src/registry/gs1databar.tsx index d69d276a..7f96553b 100644 --- a/src/registry/gs1databar.tsx +++ b/src/registry/gs1databar.tsx @@ -8,6 +8,10 @@ export const gs1databar = createBarcode1D({ hasCheckDigit: false, localeKey: "gs1databar", group: 'code-1d', + // GS1 Databar Omnidirectional has a symbology-fixed height; Zebra/Labelary + // ignore the ^BR height parameter for this variant. Disabling resize and the + // height input keeps the designer honest about what affects the print. + heightLocked: true, zplCommand: (p) => { // ^BR{orientation},{symbology},{magnification},{separator},{height},{segments} // symbology 1 = omnidirectional diff --git a/src/types/ObjectType.ts b/src/types/ObjectType.ts index 9149b665..ddbfb71b 100644 --- a/src/types/ObjectType.ts +++ b/src/types/ObjectType.ts @@ -57,6 +57,13 @@ export interface ObjectTypeDefinition

{ * back to the model's top-left convention. */ nodeOrigin?: 'center' | 'top-left'; + /** + * True if the rendered height is fixed by the symbology spec rather than the + * `height` prop (e.g. GS1 Databar Omnidirectional). The transformer disables + * its height anchors and the properties panel renders the height input as + * read-only — both reflect that the value cannot influence the print output. + */ + heightLocked?: boolean; toZPL: (obj: LabelObjectBase & { props: P }) => string; /** * Optional hook to enforce type-specific invariants on incoming changes From 0f41d862ba55f169e44795ba26c2134bff2c1aeb Mon Sep 17 00:00:00 2001 From: u8array Date: Tue, 5 May 2026 22:21:04 +0200 Subject: [PATCH 3/4] refactor: extract shared commitHeightTransform helper for 1D barcodes --- src/registry/barcode1d.tsx | 7 ++----- src/registry/code128.tsx | 5 ++--- src/registry/code39.tsx | 5 ++--- src/registry/ean13.tsx | 5 ++--- src/registry/transformHelpers.ts | 12 ++++++++++++ 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/registry/barcode1d.tsx b/src/registry/barcode1d.tsx index fbc12069..88fa809a 100644 --- a/src/registry/barcode1d.tsx +++ b/src/registry/barcode1d.tsx @@ -2,6 +2,7 @@ import type { ObjectTypeDefinition, ObjectGroup, LabelObjectBase } from '../type import { useT } from '../lib/useT'; import { inputCls, labelCls } from '../components/Properties/styles'; import { fieldPos } from './zplHelpers'; +import { commitHeightTransform } from './transformHelpers'; export interface Barcode1DProps { content: string; @@ -57,11 +58,7 @@ export function createBarcode1D(config: Barcode1DConfig): ObjectTypeDefinition ({ - height: Math.max(1, snap(Math.round(obj.props.height * sy))), - }), + commitTransform: config.heightLocked ? undefined : commitHeightTransform, toZPL: (obj: LabelObjectBase & { props: Barcode1DProps }) => { const p = obj.props; diff --git a/src/registry/code128.tsx b/src/registry/code128.tsx index 94ef0020..dd3a8dd8 100644 --- a/src/registry/code128.tsx +++ b/src/registry/code128.tsx @@ -2,6 +2,7 @@ import type { ObjectTypeDefinition } from '../types/ObjectType'; import { useT } from '../lib/useT'; import { inputCls, labelCls } from '../components/Properties/styles'; import { fieldPos } from './zplHelpers'; +import { commitHeightTransform } from './transformHelpers'; export interface Code128Props { content: string; @@ -24,9 +25,7 @@ export const code128: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, - commitTransform: (obj, { sy, snap }) => ({ - height: Math.max(1, snap(Math.round(obj.props.height * sy))), - }), + commitTransform: commitHeightTransform, toZPL: (obj) => { const p = obj.props; diff --git a/src/registry/code39.tsx b/src/registry/code39.tsx index 01599545..78461428 100644 --- a/src/registry/code39.tsx +++ b/src/registry/code39.tsx @@ -2,6 +2,7 @@ import type { ObjectTypeDefinition } from '../types/ObjectType'; import { useT } from '../lib/useT'; import { inputCls, labelCls } from '../components/Properties/styles'; import { fieldPos } from './zplHelpers'; +import { commitHeightTransform } from './transformHelpers'; export interface Code39Props { content: string; @@ -24,9 +25,7 @@ export const code39: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, - commitTransform: (obj, { sy, snap }) => ({ - height: Math.max(1, snap(Math.round(obj.props.height * sy))), - }), + commitTransform: commitHeightTransform, toZPL: (obj) => { const p = obj.props; diff --git a/src/registry/ean13.tsx b/src/registry/ean13.tsx index e3ba7b4b..cc0bd197 100644 --- a/src/registry/ean13.tsx +++ b/src/registry/ean13.tsx @@ -2,6 +2,7 @@ import type { ObjectTypeDefinition } from '../types/ObjectType'; import { useT } from '../lib/useT'; import { inputCls, labelCls } from '../components/Properties/styles'; import { fieldPos } from './zplHelpers'; +import { commitHeightTransform } from './transformHelpers'; export interface Ean13Props { content: string; // 12 digits — ZPL appends the check digit automatically @@ -22,9 +23,7 @@ export const ean13: ObjectTypeDefinition = { }, defaultSize: { width: 300, height: 120 }, - commitTransform: (obj, { sy, snap }) => ({ - height: Math.max(1, snap(Math.round(obj.props.height * sy))), - }), + commitTransform: commitHeightTransform, toZPL: (obj) => { const p = obj.props; diff --git a/src/registry/transformHelpers.ts b/src/registry/transformHelpers.ts index f862ed40..2b786c13 100644 --- a/src/registry/transformHelpers.ts +++ b/src/registry/transformHelpers.ts @@ -22,6 +22,18 @@ export function commitWidthHeightTransform

( } as Partial

; } +/** Shared commitTransform for 1D barcodes — only the bar height scales (width + * is determined by content + module width, not by the resize anchor). */ +export function commitHeightTransform

( + obj: LabelObjectBase & { props: P }, + ctx: TransformContext, +): Partial

{ + const { sy, snap } = ctx; + return { + height: Math.max(1, snap(Math.round(obj.props.height * sy))), + } as Partial

; +} + interface Stacked2DProps { rowHeight: number; moduleWidth: number; From 89c2a5e6b961807d42541e4b992fb8a56ba991ac Mon Sep 17 00:00:00 2001 From: u8array Date: Tue, 5 May 2026 22:26:38 +0200 Subject: [PATCH 4/4] perf: guard singleType lookup behind single-selection check --- src/components/Canvas/hooks/useKonvaTransformer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Canvas/hooks/useKonvaTransformer.ts b/src/components/Canvas/hooks/useKonvaTransformer.ts index d16183d9..3644277e 100644 --- a/src/components/Canvas/hooks/useKonvaTransformer.ts +++ b/src/components/Canvas/hooks/useKonvaTransformer.ts @@ -190,7 +190,10 @@ export function useKonvaTransformer({ }, [selectedIds, selectedTypesKey, selectedSignature, stageRef, transformerRef]); const resizeEnabled = selectedIds.length <= 1; - const singleType = objects.find((o) => o.id === selectedIds[0])?.type ?? ""; + const singleType = + selectedIds.length === 1 + ? objects.find((o) => o.id === selectedIds[0])?.type ?? "" + : ""; const enabledAnchors: string[] | undefined = selectedIds.length > 1 ? []