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
4 changes: 2 additions & 2 deletions src/lib/useT.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useLabelStore } from '../store/labelStore';
import { locales } from '../locales';
import { locales, type Translations } from '../locales';

export function useT() {
export function useT(): Translations {
const locale = useLabelStore((s) => s.locale);
return locales[locale];
}
1 change: 1 addition & 0 deletions src/lib/zplParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export function parseZPL(zpl: string, dpmm = 8): ParsedZPL {
height: bcHeight,
moduleWidth: byModuleWidth,
printInterpretation: bcInterp,
checkDigit: false, // EAN-13 has no user-controlled check digit (^BE auto-appends).
rotation: bcRotation,
} satisfies Ean13Props,
posType,
Expand Down
5 changes: 5 additions & 0 deletions src/locales/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ export const locales = {

export type LocaleCode = keyof typeof locales;

/** Shape of a single locale dictionary, derived from the registered locales.
* Use this when a non-React module needs the translation type without
* pulling in the useT hook. */
export type Translations = (typeof locales)[LocaleCode];

export const localeNames: Record<LocaleCode, string> = {
en: 'English',
de: 'Deutsch',
Expand Down
9 changes: 6 additions & 3 deletions src/registry/barcode1d.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ObjectTypeDefinition, ObjectGroup, LabelObjectBase } from '../types/ObjectType';
import { useT } from '../lib/useT';
import type { Translations } from '../locales';
import { inputCls, labelCls } from '../components/Properties/styles';
import { fieldPos, fdField } from './zplHelpers';
import { commitHeightTransform } from './transformHelpers';
Expand All @@ -24,8 +25,10 @@ interface Barcode1DConfig {
hasCheckDigit: boolean;
/** Build the ZPL barcode command (e.g. `^BUN,100,Y,N,N`). */
zplCommand: (p: Barcode1DProps) => string;
/** Locale key under `t.registry[localeKey]`. Must match en.ts shape. */
localeKey: string;
/** Per-symbology locale block selector — TS verifies the returned shape
* conforms to BarcodeLocale at every call site, so a missing or renamed
* `t.registry.<key>` is a compile error rather than a runtime undefined. */
locale: (t: Translations) => BarcodeLocale;
group: ObjectGroup;
/**
* Explicit wide-to-narrow ratio for the ^BY command.
Expand Down Expand Up @@ -90,7 +93,7 @@ export function createBarcode1D(config: Barcode1DConfig): ObjectTypeDefinition<B

PropertiesPanel: ({ obj, onChange }) => {
const t = useT();
const loc = (t.registry as unknown as Record<string, BarcodeLocale>)[config.localeKey] ?? {} as BarcodeLocale;
const loc = config.locale(t);
const p = obj.props;
return (
<div className="flex flex-col gap-3">
Expand Down
2 changes: 1 addition & 1 deletion src/registry/codabar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const codabar = createBarcode1D({
icon: "CBA",
defaultContent: "A12345A",
hasCheckDigit: true,
localeKey: "codabar",
locale: (t) => t.registry.codabar,
group: 'code-1d',
contentSpec: { charset: '0-9A-Da-d\\-$:/.+' },
zplCommand: (p) => {
Expand Down
2 changes: 1 addition & 1 deletion src/registry/code11.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const code11 = createBarcode1D({
icon: "C11",
defaultContent: "12345",
hasCheckDigit: true,
localeKey: "code11",
locale: (t) => t.registry.code11,
group: 'code-1d',
contentSpec: { charset: '0-9\\-' },
zplCommand: (p) => {
Expand Down
105 changes: 10 additions & 95 deletions src/registry/code128.tsx
Original file line number Diff line number Diff line change
@@ -1,101 +1,16 @@
import type { ObjectTypeDefinition } from '../types/ObjectType';
import { useT } from '../lib/useT';
import { inputCls, labelCls } from '../components/Properties/styles';
import { fieldPos, fdField } from './zplHelpers';
import { commitHeightTransform } from './transformHelpers';
import { type ZplRotation } from './rotation';
import { RotationSelect } from '../components/Properties/RotationSelect';
import { NumberInput } from '../components/Properties/NumberInput';
import { createBarcode1D } from './barcode1d';
export type { Barcode1DProps as Code128Props } from './barcode1d';

export interface Code128Props {
content: string;
height: number;
moduleWidth: number;
printInterpretation: boolean;
checkDigit: boolean;
rotation: ZplRotation;
}

export const code128: ObjectTypeDefinition<Code128Props> = {
export const code128 = createBarcode1D({
label: 'Code 128',
icon: '|||',
group: 'code-1d' as const,
defaultProps: {
content: '12345678',
height: 100,
moduleWidth: 2,
printInterpretation: true,
checkDigit: false,
rotation: 'N',
},
defaultSize: { width: 300, height: 120 },

commitTransform: commitHeightTransform,

toZPL: (obj) => {
const p = obj.props;
defaultContent: '12345678',
hasCheckDigit: true,
locale: (t) => t.registry.code128,
group: 'code-1d',
zplCommand: (p) => {
const interp = p.printInterpretation ? 'Y' : 'N';
const check = p.checkDigit ? 'Y' : 'N';
return [
`^BY${p.moduleWidth}`,
fieldPos(obj),
`^BC${p.rotation},${p.height},${interp},N,${check}`,
fdField(p.content),
].filter(Boolean).join('');
},

PropertiesPanel: ({ obj, onChange }) => {
const t = useT();
const p = obj.props;
return (
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-1">
<label className={labelCls}>{t.registry.code128.content}</label>
<input
className={inputCls}
value={p.content}
onChange={(e) => onChange({ content: e.target.value })}
/>
</div>

<NumberInput
label={t.registry.code128.height}
value={p.height}
min={1}
onChange={(height) => onChange({ height })}
/>

<NumberInput
label={t.registry.code128.moduleWidth}
value={p.moduleWidth}
min={1}
max={10}
onChange={(moduleWidth) => onChange({ moduleWidth })}
/>

<div className="flex flex-col gap-2">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
className="accent-accent"
checked={p.printInterpretation}
onChange={(e) => onChange({ printInterpretation: e.target.checked })}
/>
<span className={labelCls}>{t.registry.code128.printInterpretation}</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
className="accent-accent"
checked={p.checkDigit}
onChange={(e) => onChange({ checkDigit: e.target.checked })}
/>
<span className={labelCls}>{t.registry.code128.checkDigit}</span>
</label>
</div>

<RotationSelect value={p.rotation} onChange={(rotation) => onChange({ rotation })} />
</div>
);
return `^BC${p.rotation},${p.height},${interp},N,${check}`;
},
};
});
106 changes: 11 additions & 95 deletions src/registry/code39.tsx
Original file line number Diff line number Diff line change
@@ -1,104 +1,20 @@
import type { ObjectTypeDefinition } from '../types/ObjectType';
import { useT } from '../lib/useT';
import { inputCls, labelCls } from '../components/Properties/styles';
import { fieldPos, fdField } from './zplHelpers';
import { commitHeightTransform } from './transformHelpers';
import { filterContent, type ContentSpec } from './contentSpec';
import { type ZplRotation } from './rotation';
import { RotationSelect } from '../components/Properties/RotationSelect';
import { NumberInput } from '../components/Properties/NumberInput';
import { createBarcode1D } from './barcode1d';
import type { ContentSpec } from './contentSpec';
export type { Barcode1DProps as Code39Props } from './barcode1d';

const code39Spec: ContentSpec = { charset: '0-9A-Za-z\\-. $/+%' };

export interface Code39Props {
content: string;
height: number;
moduleWidth: number;
printInterpretation: boolean;
checkDigit: boolean;
rotation: ZplRotation;
}

export const code39: ObjectTypeDefinition<Code39Props> = {
export const code39 = createBarcode1D({
label: 'Code 39',
icon: '|·|',
defaultContent: 'CODE39',
hasCheckDigit: true,
locale: (t) => t.registry.code39,
group: 'code-1d',
defaultProps: {
content: 'CODE39',
height: 100,
moduleWidth: 2,
printInterpretation: true,
checkDigit: false,
rotation: 'N',
},
defaultSize: { width: 300, height: 120 },

commitTransform: commitHeightTransform,

toZPL: (obj) => {
const p = obj.props;
contentSpec: code39Spec,
zplCommand: (p) => {
const interp = p.printInterpretation ? 'Y' : 'N';
const check = p.checkDigit ? 'Y' : 'N';
return [
`^BY${p.moduleWidth}`,
fieldPos(obj),
`^B3${p.rotation},${check},${p.height},${interp},N`,
fdField(p.content),
].filter(Boolean).join('');
},

PropertiesPanel: ({ obj, onChange }) => {
const t = useT();
const p = obj.props;
return (
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-1">
<label className={labelCls}>{t.registry.code39.content}</label>
<input
className={inputCls}
value={p.content}
onChange={(e) => onChange({ content: filterContent(e.target.value, code39Spec) })}
/>
</div>

<NumberInput
label={t.registry.code39.height}
value={p.height}
min={1}
onChange={(height) => onChange({ height })}
/>

<NumberInput
label={t.registry.code39.moduleWidth}
value={p.moduleWidth}
min={1}
max={10}
onChange={(moduleWidth) => onChange({ moduleWidth })}
/>

<div className="flex flex-col gap-2">
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
className="accent-accent"
checked={p.printInterpretation}
onChange={(e) => onChange({ printInterpretation: e.target.checked })}
/>
<span className={labelCls}>{t.registry.code39.printInterpretation}</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input
type="checkbox"
className="accent-accent"
checked={p.checkDigit}
onChange={(e) => onChange({ checkDigit: e.target.checked })}
/>
<span className={labelCls}>{t.registry.code39.checkDigit}</span>
</label>
</div>

<RotationSelect value={p.rotation} onChange={(rotation) => onChange({ rotation })} />
</div>
);
return `^B3${p.rotation},${check},${p.height},${interp},N`;
},
};
});
2 changes: 1 addition & 1 deletion src/registry/code93.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const code93 = createBarcode1D({
icon: '|93|',
defaultContent: 'CODE93',
hasCheckDigit: true,
localeKey: 'code93',
locale: (t) => t.registry.code93,
group: 'code-1d',
zplCommand: (p) => {
const interp = p.printInterpretation ? 'Y' : 'N';
Expand Down
Loading