Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- Comprehensive configuration and styling settings for various barcode types
- Download functionality for barcodes

## [1.0.0] - 2025-10-09

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@mendix/widget-plugin-component-kit": "workspace:*",
"@mendix/widget-plugin-platform": "workspace:*",
"@mendix/widget-plugin-test-utils": "workspace:*",
"cross-env": "^7.0.3"
"cross-env": "^7.0.3",
"eslint": "^9.37.0"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { hidePropertiesIn, Properties } from "@mendix/pluggable-widgets-tools";
import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools";
import { BarcodeGeneratorPreviewProps } from "../typings/BarcodeGeneratorProps";
import { validateAddonValue, validateBarcodeValue } from "./config/validation";

export type Problem = {
property?: string; // key of the property, at which the problem exists
Expand All @@ -12,14 +13,78 @@ export type Problem = {

export function getProperties(values: BarcodeGeneratorPreviewProps, defaultProperties: Properties): Properties {
if (values.codeFormat === "QRCode") {
hidePropertiesIn(defaultProperties, values, ["codeWidth", "codeHeight", "displayValue"]);
hidePropertiesIn(defaultProperties, values, ["codeWidth", "codeHeight", "displayValue", "codeMargin"]);
} else {
hidePropertiesIn(defaultProperties, values, ["qrSize"]);
hidePropertiesIn(defaultProperties, values, ["qrImage", "qrSize", "qrMargin", "qrLevel", "qrTitle"]);
}

if (values.codeFormat !== "QRCode" || !values.qrImage) {
hidePropertiesIn(defaultProperties, values, [
"qrImageSrc",
"qrImageCenter",
"qrImageWidth",
"qrImageHeight",
"qrImageX",
"qrImageY",
"qrImageOpacity",
"qrImageExcavate"
]);
}

if (values.codeFormat !== "CODE128" && values.customCodeFormat !== "CODE128") {
hidePropertyIn(defaultProperties, values, "enableEan128");
}

if (
values.codeFormat === "QRCode" ||
values.codeFormat === "CODE128" ||
(values.codeFormat === "Custom" &&
values.customCodeFormat !== "EAN13" &&
values.customCodeFormat !== "EAN8" &&
values.customCodeFormat !== "UPC")
) {
hidePropertyIn(defaultProperties, values, "enableFlat");
}

if (
values.codeFormat === "QRCode" ||
values.codeFormat === "CODE128" ||
(values.codeFormat === "Custom" && values.customCodeFormat !== "EAN13")
) {
hidePropertyIn(defaultProperties, values, "lastChar");
}

if (
values.codeFormat === "QRCode" ||
values.codeFormat === "CODE128" ||
(values.codeFormat === "Custom" && values.customCodeFormat !== "EAN13" && values.customCodeFormat !== "EAN8")
) {
hidePropertiesIn(defaultProperties, values, ["addonFormat", "addonValue", "addonSpacing"]);
}
if (
values.codeFormat === "QRCode" ||
values.codeFormat === "CODE128" ||
(values.codeFormat === "Custom" && values.addonFormat !== "EAN5" && values.addonFormat !== "EAN2")
) {
hidePropertiesIn(defaultProperties, values, ["addonValue", "addonSpacing"]);
}

if (
values.codeFormat === "QRCode" ||
values.codeFormat === "CODE128" ||
(values.codeFormat === "Custom" && values.customCodeFormat !== "CODE39")
) {
hidePropertyIn(defaultProperties, values, "enableMod43");
}

if (values.qrImageCenter) {
hidePropertiesIn(defaultProperties, values, ["qrImageX", "qrImageY"]);
}

if (values.codeFormat !== "Custom") {
hidePropertiesIn(defaultProperties, values, ["customCodeFormat"]);
}

return defaultProperties;
}

Expand Down Expand Up @@ -50,5 +115,42 @@ export function check(_values: BarcodeGeneratorPreviewProps): Problem[] {
});
}

return errors;
// Design-time validation for static barcode value(s)
const valueProblems = validateCodeValues(_values);
return errors.concat(valueProblems);
}

function getActiveFormat(values: BarcodeGeneratorPreviewProps): string {
if (values.codeFormat === "Custom") {
return values.customCodeFormat || "CODE128";
}

return values.codeFormat;
}

function validateCodeValues(values: BarcodeGeneratorPreviewProps): Problem[] {
const problems: Problem[] = [];
const val = values.codeValue ?? "";
const addon = values.addonValue ?? "";
const format = getActiveFormat(values);

// Only validate static (design-time) values — if empty, skip (user may bind dynamically)
if (!val) {
// still validate addon if present
} else {
const result = validateBarcodeValue(format, val);
if (!result.valid) {
const msg = result.message || "Invalid barcode value for selected format.";
problems.push({ property: "codeValue", severity: "warning", message: msg });
}
}

// Validate addon value if visible
const addonResult = validateAddonValue(values.addonFormat, addon);
if (!addonResult.valid) {
const msg = addonResult.message || "Invalid addon value.";
problems.push({ property: "addonValue", severity: "warning", message: msg });
}

return problems;
}
Original file line number Diff line number Diff line change
@@ -1,53 +1,32 @@
import JsBarcode from "jsbarcode";
import { QRCodeSVG } from "qrcode.react";
import { ReactElement, useEffect, useRef } from "react";
import { ReactElement } from "react";
import { BarcodeGeneratorContainerProps } from "../typings/BarcodeGeneratorProps";
import { barcodeConfig } from "./config/Barcode.config";
import { BarcodeContextProvider, useBarcodeConfig } from "./config/BarcodeContext";
import { QRCodeRenderer } from "./components/QRCode";
import { BarcodeRenderer } from "./components/Barcode";

import "./ui/BarcodeGenerator.scss";

export default function BarcodeGenerator({
codeValue,
codeWidth,
codeHeight,
codeFormat,
codeMargin,
displayValue,
qrSize,
tabIndex
}: BarcodeGeneratorContainerProps): ReactElement {
const svgRef = useRef<SVGSVGElement>(null);
function BarcodeContainer({ tabIndex }: { tabIndex?: number }): ReactElement {
const config = useBarcodeConfig();

const value = codeValue?.status === "available" ? codeValue.value : "";
const width = codeWidth ?? 128;
const height = codeHeight ?? 128;
const format = codeFormat ?? "CODE128";
const margin = codeMargin ?? 2;
const showValue = displayValue ?? false;
const size = qrSize ?? 128;
return (
<div className="barcode-generator" tabIndex={tabIndex}>
{config.isQRCode ? <QRCodeRenderer /> : <BarcodeRenderer />}
</div>
);
}

useEffect(() => {
if (format !== "QRCode" && svgRef.current && value) {
try {
JsBarcode(svgRef.current, value, {
format,
width,
height,
margin,
displayValue: showValue
});
} catch (error) {
console.error("Error generating barcode:", error);
}
}
}, [value, width, height, format, margin, showValue]);
export default function BarcodeGenerator(props: BarcodeGeneratorContainerProps): ReactElement {
const config = barcodeConfig(props);

if (!value) {
if (!config.value) {
return <span>No barcode value provided</span>;
}

return (
<div className="barcode-generator" tabIndex={tabIndex}>
{format === "QRCode" ? <QRCodeSVG value={value} size={size} /> : <svg ref={svgRef} />}
</div>
<BarcodeContextProvider config={config}>
<BarcodeContainer tabIndex={props.tabIndex} />
</BarcodeContextProvider>
);
}
Loading
Loading