Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions src/registry/aztec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@ import type { ObjectTypeDefinition } from "../types/ObjectType";
import { useT } from "../lib/useT";
import { inputCls, labelCls } from "../components/Properties/styles";
import { fieldPos, fdField } from "./zplHelpers";
import { commitUniformScaleTransform } from "./transformHelpers";
import { type ZplRotation } from "./rotation";
import { RotationSelect } from "../components/Properties/RotationSelect";
import { NumberInput } from "../components/Properties/NumberInput";

const MAGNIFICATION_MIN = 1;
const MAGNIFICATION_MAX = 10;
const EC_LEVEL_MIN = 0;
// NumberInput can't express the discontinuous AztecProps domain — use the
// highest valid value (Rune = 300) as the upper bound.
const EC_LEVEL_MAX = 300;

export interface AztecProps {
content: string;
magnification: number; // 1–10, module size in dots
magnification: number; // module size in dots
ecLevel: number; // 0=default, 1-99=error correction %, 101-104=compact, 201-232=full, 300=rune
rotation: ZplRotation;
}
Expand All @@ -25,6 +33,8 @@ export const aztec: ObjectTypeDefinition<AztecProps> = {
},
defaultSize: { width: 200, height: 200 },

commitTransform: commitUniformScaleTransform('magnification', MAGNIFICATION_MIN, MAGNIFICATION_MAX),

toZPL: (obj) => {
const p = obj.props;
// ^B0 a,b,c,d,e,f,g = orientation, magnification, ecic, errorControl,
Expand Down Expand Up @@ -55,16 +65,16 @@ export const aztec: ObjectTypeDefinition<AztecProps> = {
<NumberInput
label={loc.magnification}
value={p.magnification}
min={1}
max={10}
min={MAGNIFICATION_MIN}
max={MAGNIFICATION_MAX}
onChange={(magnification) => onChange({ magnification })}
/>

<NumberInput
label={loc.ecLevel}
value={p.ecLevel}
min={0}
max={232}
min={EC_LEVEL_MIN}
max={EC_LEVEL_MAX}
onChange={(ecLevel) => onChange({ ecLevel })}
/>

Expand Down
15 changes: 8 additions & 7 deletions src/registry/datamatrix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import type { ObjectTypeDefinition } from '../types/ObjectType';
import { useT } from '../lib/useT';
import { inputCls, labelCls } from '../components/Properties/styles';
import { fieldPos, fdField } from './zplHelpers';
import { clamp } from './transformHelpers';
import { commitUniformScaleTransform } from './transformHelpers';
import { type ZplRotation } from './rotation';
import { RotationSelect } from '../components/Properties/RotationSelect';
import { NumberInput } from '../components/Properties/NumberInput';

const DIMENSION_MIN = 1;
const DIMENSION_MAX = 12;

export interface DataMatrixProps {
content: string;
dimension: number; // module size in dots (1–12)
dimension: number; // module size in dots
quality: 0 | 50 | 80 | 140 | 200; // 0 = auto
rotation: ZplRotation;
}
Expand All @@ -26,9 +29,7 @@ export const datamatrix: ObjectTypeDefinition<DataMatrixProps> = {
},
defaultSize: { width: 150, height: 150 },

commitTransform: (obj, { sx, sy }) => ({
dimension: clamp(1, 12, Math.round(obj.props.dimension * Math.min(sx, sy))),
}),
commitTransform: commitUniformScaleTransform('dimension', DIMENSION_MIN, DIMENSION_MAX),

toZPL: (obj) => {
const p = obj.props;
Expand Down Expand Up @@ -56,8 +57,8 @@ export const datamatrix: ObjectTypeDefinition<DataMatrixProps> = {
<NumberInput
label={t.registry.datamatrix.dimension}
value={p.dimension}
min={1}
max={12}
min={DIMENSION_MIN}
max={DIMENSION_MAX}
onChange={(dimension) => onChange({ dimension })}
/>

Expand Down
15 changes: 8 additions & 7 deletions src/registry/qrcode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import type { ObjectTypeDefinition } from '../types/ObjectType';
import { useT } from '../lib/useT';
import { inputCls, labelCls } from '../components/Properties/styles';
import { fieldPos, fdField } from './zplHelpers';
import { clamp } from './transformHelpers';
import { commitUniformScaleTransform } from './transformHelpers';
import { type ZplRotation } from './rotation';
import { RotationSelect } from '../components/Properties/RotationSelect';
import { NumberInput } from '../components/Properties/NumberInput';

const MAGNIFICATION_MIN = 1;
const MAGNIFICATION_MAX = 10;

export interface QrCodeProps {
content: string;
magnification: number; // 1–10, dot size per module
magnification: number; // dot size per module
errorCorrection: 'H' | 'Q' | 'M' | 'L';
rotation: ZplRotation;
}
Expand All @@ -26,9 +29,7 @@ export const qrcode: ObjectTypeDefinition<QrCodeProps> = {
},
defaultSize: { width: 200, height: 200 },

commitTransform: (obj, { sx, sy }) => ({
magnification: clamp(1, 10, Math.round(obj.props.magnification * Math.min(sx, sy))),
}),
commitTransform: commitUniformScaleTransform('magnification', MAGNIFICATION_MIN, MAGNIFICATION_MAX),

toZPL: (obj) => {
const p = obj.props;
Expand Down Expand Up @@ -67,8 +68,8 @@ export const qrcode: ObjectTypeDefinition<QrCodeProps> = {
<NumberInput
label={t.registry.qrcode.magnification}
value={p.magnification}
min={1}
max={10}
min={MAGNIFICATION_MIN}
max={MAGNIFICATION_MAX}
onChange={(magnification) => onChange({ magnification })}
/>

Expand Down
10 changes: 10 additions & 0 deletions src/registry/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,14 @@ describe('ObjectRegistry', () => {
expect(validGroups.has(def.group)).toBe(true);
}
});

// 2D codes are always resizable on the canvas — without commitTransform a
// drag-resize silently has no effect (this was the aztec regression).
// Every code-2d entry must declare a commit handler.
it('every code-2d type has a commitTransform handler', () => {
for (const [key, def] of Object.entries(ObjectRegistry)) {
if (def.group !== 'code-2d') continue;
expect(def.commitTransform, `${key} is missing commitTransform`).toBeDefined();
}
});
});
33 changes: 33 additions & 0 deletions src/registry/transformHelpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest';
import { commitUniformScaleTransform } from './transformHelpers';
import type { LabelObjectBase, TransformContext } from '../types/ObjectType';

const ctx = (sx: number, sy: number): TransformContext => ({
sx, sy, snap: (n) => n, nodeHeight: 0, anchor: null,
});

interface Sample { magnification: number }
const obj = (mag: number): LabelObjectBase & { props: Sample } => ({
id: 'id', type: 'sample', x: 0, y: 0, rotation: 0, props: { magnification: mag },
});

describe('commitUniformScaleTransform', () => {
const handler = commitUniformScaleTransform('magnification', 1, 10);

it('scales by min(sx, sy) so non-uniform drags stay inside the box', () => {
expect(handler(obj(4), ctx(2, 1.5))).toEqual({ magnification: 6 });
expect(handler(obj(4), ctx(1.5, 2))).toEqual({ magnification: 6 });
});

it('rounds to integer module sizes', () => {
expect(handler(obj(3), ctx(1.4, 1.4))).toEqual({ magnification: 4 });
});

it('clamps to the configured maximum', () => {
expect(handler(obj(8), ctx(3, 3))).toEqual({ magnification: 10 });
});

it('clamps to the configured minimum (collapsing drags)', () => {
expect(handler(obj(4), ctx(0, 0))).toEqual({ magnification: 1 });
});
});
16 changes: 16 additions & 0 deletions src/registry/transformHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ export function clamp(min: number, max: number, value: number): number {
return Math.max(min, Math.min(max, value));
}

/**
* Factory for commitTransform on uniformly-scaling 2D codes (QR, Aztec,
* DataMatrix): a single integer module-size prop scales by min(sx, sy)
* and clamps to [min, max]. The prop name and range vary per code, so they
* are closed over at registry-definition time.
*/
export function commitUniformScaleTransform<
K extends string,
P extends Record<K, number> = Record<K, number>,
>(propName: K, min: number, max: number) {
return (obj: LabelObjectBase & { props: P }, ctx: TransformContext): Partial<P> => {
const next = clamp(min, max, Math.round(obj.props[propName] * Math.min(ctx.sx, ctx.sy)));
return { [propName]: next } as Partial<P>;
};
}

interface WidthHeightProps {
width: number;
height: number;
Expand Down