Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
05f0642
Add a product registry and check every product name against it
eugenia-scandit Oct 13, 2026
b5f5cd7
feat: add ProductChooser ("Choose this if / not for" + framework matrix)
eugenia-scandit Aug 5, 2026
b520cdb
fix: exclude unavailable frameworks (version n/a) from ProductChooser…
eugenia-scandit Aug 5, 2026
944508c
feat(ProductChooser): link the referenced product in each 'consider a…
eugenia-scandit Aug 7, 2026
d38a07d
Feed the ProductChooser from the product registry
eugenia-scandit Oct 13, 2026
333d9c7
Address review: placement, contrast, list semantics, versions
eugenia-scandit Oct 14, 2026
e500b5e
Fix .NET links, version labels and frozen-version detection
eugenia-scandit Oct 14, 2026
abfd0cc
Typecheck the registry plugin; render the chooser on current docs only
eugenia-scandit Oct 14, 2026
d759916
Add the chooser to the Kotlin Multiplatform overviews
eugenia-scandit Oct 14, 2026
b1d7728
Accept chooser entries for sdk products only
eugenia-scandit Oct 14, 2026
f6084c4
Name the sequence product MatrixScan Sequence
eugenia-scandit Oct 14, 2026
b286372
Document the chooser file and accept it before its first entry
eugenia-scandit Oct 15, 2026
b733832
Merge remote-tracking branch 'origin/feat/product-registry' into docs…
eugenia-scandit Oct 15, 2026
124fa24
Test the chooser's links; hide alternatives a framework lacks
eugenia-scandit Oct 15, 2026
be49732
Read the chooser file the same way on js-yaml 4 and 5
eugenia-scandit Oct 15, 2026
cbe80db
Merge commit 'be49732d8b' into docs/product-chooser
eugenia-scandit Oct 15, 2026
0f6af2c
Strip a byte-order mark before parsing the registry files
eugenia-scandit Oct 15, 2026
78ef970
Merge remote-tracking branch 'origin/feat/product-registry' into docs…
eugenia-scandit Oct 15, 2026
183c36a
Parse the chooser file through the verifier; test the alternatives fi…
eugenia-scandit Oct 15, 2026
21ac92c
Merge main into docs/product-chooser
eugenia-scandit Oct 23, 2026
2037e72
Say which component uses isSupportedVersion after the merge
eugenia-scandit Oct 23, 2026
0ca83bd
Merge main into docs/product-chooser
eugenia-scandit Oct 23, 2026
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
10 changes: 10 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ jobs:
- name: Verify product registry
run: yarn verify:registry

# The chooser renders nothing until it has approved text, so a build
# never reaches its link code; this pins the links it will build.
- name: Test Product Chooser links
run: yarn test:product-chooser

# The build transpiles TypeScript without checking types, so a type
# error in a component or plugin only fails here.
- name: Typecheck
run: yarn typecheck

# Pins where the 404 page sends a broken link into the C API reference.
- name: Test C API 404 fallback
run: yarn test:not-found
Expand Down
8 changes: 7 additions & 1 deletion docs/partials/intro/_about-matrixscan-ar.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import ProductChooser from '@site/src/components/ProductChooser';

MatrixScan AR enables you to build applications and workflows involving augmented reality overlays to highlight barcodes and display additional information over them.

<ReactPlayer playing controls width='800' url="/img/batch-scanning/MatrixScanCheck.mp4" />

MatrixScan is powered by the `BarcodeAr` functionality of the Scandit Smart Data Capture SDK. It can be used to add the following customizabe UI elements to your workflows:
MatrixScan AR is powered by the `BarcodeAr` functionality of the Scandit Smart Data Capture SDK.

<ProductChooser />
Comment thread
eugenia-scandit marked this conversation as resolved.

MatrixScan AR can be used to add the following customizable UI elements to your workflows:

## Highlights

Expand Down
4 changes: 4 additions & 0 deletions docs/partials/intro/_about-matrixscan-count.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import ProductChooser from '@site/src/components/ProductChooser';

MatrixScan Count is our pre-built scan and count solution for counting and receiving multiple items at once. It fits on top of any smartphone application, providing an intuitive user interface for simple, fast and ergonomic scanning. MatrixScan Count enables the accurate scanning and counting of multiple items at once via smart devices, speeding counting workflows by up to 10 times. The solution is designed to boost worker productivity, reduce human error and maintain accurate stock levels.

MatrixScan Count bundles multiple scanning features together and addresses many common challenges associated with scanning on smart devices. It is designed to be easily integrated into any application, and can be customized to fit your specific needs.

<ProductChooser />

## UI Overview

MatrixScan Count includes pre-built and pre-tested user interface (UI) elements and interactions in workflows. These UI elements are intentionally minimalistic, meant to be overlayed on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
4 changes: 4 additions & 0 deletions docs/partials/intro/_about-matrixscan-find.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import ProductChooser from '@site/src/components/ProductChooser';

MatrixScan Find is our pre-built UI that uses augmented reality overlays to highlight items that match predefined criteria. This is distinct from MatrixScan AR that is fully customizable, MatrixScan Find enables you to add a search and find experience with augmented reality to an existing native app with just a few lines of code.

<ReactPlayer playing controls width='800' url="/img/batch-scanning/MatrixScanFind.mp4" />

MatrixScan Find bundles multiple scanning features together and addresses many common challenges associated with scanning on smart devices. It is designed to be easily integrated into any application, and can be customized to fit your specific needs.

<ProductChooser />

## UI Overview

MatrixScan Find includes pre-built and pre-tested user interface (UI) elements and interactions in workflows. These UI elements are intentionally minimalistic, meant to be overlayed on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
3 changes: 3 additions & 0 deletions docs/partials/intro/_about-matrixscan-pick.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import ProductChooser from '@site/src/components/ProductChooser';
import Link from '@docusaurus/Link';
import ApiLink from '@site/src/components/ApiLink';

MatrixScan Pick is a pre-built UI that uses augmented reality overlays to highlight specific items that need to be picked. Whereas MatrixScan AR is fully customizable, MatrixScan Pick is a pre-built solution that allows you to add a scan and pick experience with augmented reality to an existing native app, with just a few lines of code.

MatrixScan Pick is implemented through functionality provided by <ApiLink framework={props.framework} page="barcode-capture/api/barcode-pick.html">BarcodePick</ApiLink>.

<ProductChooser />

## UI Overview

* MatrixScan Pick is inspired by the familiar paradigm of a camera, including a shutter button that the user operates in order start and pause the scanning view. The Finish button is used at any time to exit the workflow.
Expand Down
4 changes: 4 additions & 0 deletions docs/partials/intro/_about-matrixscan.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import ProductChooser from '@site/src/components/ProductChooser';

MatrixScan Batch enables you to build applications and workflows involving highlighting and/or interacting with multiple barcodes within the same frame.

<ReactPlayer playing controls width='800' url="/img/batch-scanning/MatrixScanBatch.mp4" />

MatrixScan Batch is powered by the `BarcodeBatch` functionality of the Scandit Smart Data Capture SDK.

<ProductChooser />

## Limitations

MatrixScan Batch does not support the following symbologies:
Expand Down
3 changes: 3 additions & 0 deletions docs/partials/intro/_about-sparkscan.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import ProductChooser from '@site/src/components/ProductChooser';
import Link from '@docusaurus/Link';

SparkScan is our pre-built smartphone scanning interface designed for high-performance barcode scanning. It fits on top of any smartphone application, providing an intuitive user interface for simple, fast and ergonomic scanning in scan-intensive workflows, such as inventory management in retail, or goods receiving in logistics.

SparkScan bundles multiple scanning features together and addresses many common challenges associated with scanning on smart devices. It is designed to be easily integrated into any application, and can be customized to fit your specific needs.

<ProductChooser />

## UI Overview

The UI elements in SparkScan are intentionally minimalistic, meant to be overlayed on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/matrixscan-ar/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About MatrixScan AR

MatrixScan AR is Scandit's most advanced and flexible API for building custom augmented-reality workflows that scan and track multiple barcodes at once. It is a superset of [MatrixScan Batch](../matrixscan/intro.md): it tracks the same set of barcodes across frames, but adds a prebuilt AR view with configurable highlights, tap-driven annotations, torch/zoom/camera-switch controls, and audio/haptic feedback.
Expand All @@ -19,6 +21,8 @@ MatrixScan AR is implemented through two elements, both in the `com.kmp.datacapt
- `BarcodeAr`—the data capture mode driving scan-and-track recognition. Unlike most other modes, `BarcodeAr` is not a `DataCaptureMode`: it attaches itself to a `DataCaptureContext` when constructed via `BarcodeAr.forContext(...)`, so you never call `addMode()`/`removeMode()` for it.
- `BarcodeArView`—the prebuilt AR UI that renders highlights and annotations over tracked barcodes and hosts the camera preview.

<ProductChooser />

## Highlights

Used to enable the user to identify the scanned barcode. They are shown on top of the respective barcode and displayed as soon as the barcode is scanned.
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/matrixscan-count/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About MatrixScan Count

MatrixScan Count is our pre-built scan and count solution for counting and receiving multiple items at once. It fits on top of any Kotlin Multiplatform application, providing an intuitive user interface for simple, fast and ergonomic scanning. MatrixScan Count enables the accurate scanning and counting of multiple items at once via smart devices, speeding up counting workflows considerably. The solution is designed to boost worker productivity, reduce human error and maintain accurate stock levels.
Expand All @@ -16,6 +18,8 @@ MatrixScan Count bundles multiple scanning features together and addresses many

On Kotlin Multiplatform, MatrixScan Count is exposed through the `BarcodeCount` data capture mode and the `BarcodeCountView` built-in UI, both of which are shared between Android and iOS.

<ProductChooser />

## UI Overview

MatrixScan Count includes pre-built and pre-tested user interface (UI) elements and interactions. These UI elements are intentionally minimalistic, meant to be overlaid on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/matrixscan-find/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About MatrixScan Find

MatrixScan Find is our pre-built UI that uses augmented reality overlays to highlight items that match predefined criteria. It enables you to add a search-and-find experience with augmented reality to an existing Kotlin Multiplatform app with just a few lines of code.
Expand All @@ -18,6 +20,8 @@ MatrixScan Find bundles multiple scanning features together and addresses many c

On Kotlin Multiplatform, MatrixScan Find is exposed through the `BarcodeFind` data capture mode and the `BarcodeFindView` built-in UI, both of which are shared between Android and iOS.

<ProductChooser />

## UI Overview

MatrixScan Find includes pre-built and pre-tested user interface (UI) elements and interactions. These UI elements are intentionally minimalistic, meant to be overlaid on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/matrixscan-pick/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About MatrixScan Pick

MatrixScan Pick is a pre-built UI that uses augmented reality overlays to highlight specific items that need to be picked. Whereas MatrixScan AR is fully customizable, MatrixScan Pick is a pre-built solution that allows you to add a scan and pick experience with augmented reality to an existing app, with just a few lines of code.

MatrixScan Pick is implemented through functionality provided by `BarcodePick`.

<ProductChooser />

## UI Overview

- MatrixScan Pick is inspired by the familiar paradigm of a camera, including a shutter button that the user operates to start and pause the scanning view. The Finish button is used at any time to exit the workflow.
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/matrixscan/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About MatrixScan Batch

MatrixScan Batch is Scandit's low-level API for scanning and tracking multiple barcodes at once, without augmented-reality overlays. It is implemented through the `BarcodeBatch` data capture mode, in the `com.kmp.datacapture.barcode.batch` package of the `barcode` module.
Expand All @@ -20,6 +22,8 @@ Typical use cases include:
- Receiving and put-away workflows
- Any scenario where you need to recognize and track several barcodes in the camera's field of view at the same time, without guiding the user through a check-off flow

<ProductChooser />

## How It Works

`BarcodeBatch` tracks barcodes across frames, assigning each one a stable tracking identifier via [`TrackedBarcode`](./get-started.md#track-the-results). You can either:
Expand Down
4 changes: 4 additions & 0 deletions docs/sdks/kmp/sparkscan/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ keywords:
- kmp
---

import ProductChooser from '@site/src/components/ProductChooser';

# About SparkScan

SparkScan is our pre-built smartphone scanning interface designed for high-performance barcode scanning. It fits on top of any smartphone application, providing an intuitive user interface for simple, fast and ergonomic scanning in scan-intensive workflows, such as inventory management in retail, or goods receiving in logistics.

SparkScan bundles multiple scanning features together and addresses many common challenges associated with scanning on smart devices. It is designed to be easily integrated into any application, and can be customized to fit your specific needs.

<ProductChooser />
Comment thread
eugenia-scandit marked this conversation as resolved.

## UI Overview

The UI elements in SparkScan are intentionally minimalistic, meant to be overlaid on any application without the need to adapt the existing app while offering the best user experience.
Expand Down
4 changes: 4 additions & 0 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { version } from "react";
import remarkHideComments from "./src/plugins/remark-hide-comments";
import remarkOffloadPreviewMedia from "./src/plugins/remark-offload-preview-media";
import stripPreviewMediaPlugin from "./src/plugins/plugin-strip-preview-media";
import productRegistryPlugin from "./src/plugins/plugin-product-registry";
import { UNRELEASED_FRAMEWORK_SLUGS } from "./src/constants/unreleasedFrameworks";
import { ROUTED_FRAMEWORKS } from "./src/constants/frameworks";
dotenv.config(); // Load environment variables from .env file
Expand Down Expand Up @@ -1364,6 +1365,9 @@ const config: Config = {
},
],
...(isPreviewBuild ? [stripPreviewMediaPlugin] : []),
// The product registry and approved Product Chooser text, as global data
// for components (usePluginData("product-registry")).
productRegistryPlugin,
// Publish the exact tag set the built widget filters on, so the search-tag
// gate can check a real build artifact instead of re-deriving the same
// assumption from this file and agreeing with itself.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"test:api-link": "node scripts/test-api-link.cjs",
"verify:registry": "node scripts/verify-registry.cjs",
"test:registry": "node scripts/test-registry.cjs",
"test:product-chooser": "node scripts/test-product-chooser.cjs",
"test:not-found": "node scripts/test-not-found.cjs",
"test:docs-gate": "node scripts/test-docs-gate.cjs",
"verify:api-reference-seo": "node scripts/verify-api-reference-seo.cjs",
Expand Down
125 changes: 125 additions & 0 deletions scripts/test-product-chooser.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env node
"use strict";
/**
* Tests for the Product Chooser's links and the alternatives it shows
* (src/components/ProductChooser/links.ts).
*
* The chooser renders nothing until content/registry/product-chooser.yml has
* an approved entry, so a build does not reach this code yet. These cases pin
* what it links to: the doc paths the docs plugin publishes carry the base
* URL, and a preview build serves the site under /data-capture-documentation/
* pr-preview/pr-N/, so the prefix cut from the pathname must line up with them.
*
* Transpiles the TypeScript source with the repo's own `typescript`, so it
* runs on the Node version CI uses, which cannot load .ts files.
*
* Usage: node scripts/test-product-chooser.cjs
*/

const assert = require("assert");
const path = require("path");
const fs = require("fs");
const { createRequire } = require("module");
const ts = require("typescript");

function loadTs(file) {
const { outputText } = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 },
fileName: file,
});
const mod = { exports: {} };
// `require` relative to the loaded file, not to this script.
new Function("module", "exports", "require", outputText)(mod, mod.exports, createRequire(file));
return mod.exports;
}

let passed = 0;
function test(name, fn) {
try {
fn();
passed++;
} catch (e) {
console.error(`✗ ${name}\n ${e.message}`);
process.exitCode = 1;
}
}

const { docsPrefix, overviewUrl, visibleAlternatives } = loadTs(path.join(__dirname, "../src/components/ProductChooser/links.ts"));

const PREVIEW = "/data-capture-documentation/pr-preview/pr-1";
// Doc paths as the docs plugin publishes them, base URL included. Some with a
// trailing slash and some without, as both occur.
const docs = (base) =>
[
"/sdks/ios/sparkscan/intro/",
"/sdks/ios/matrixscan/intro",
"/sdks/ios/barcode-capture/get-started/",
"/sdks/ios/barcode-generator/",
"/sdks/kmp/matrixscan/intro/",
"/sdks/net/ios/matrixscan/intro/",
"/hosted/express/overview/",
].map((p) => ({ path: `${base}${p}` }));
const sdk = (folder) => ({ kind: "sdk", folder });
const hosted = (folder) => ({ kind: "hosted", folder });

test("docsPrefix is everything before /sdks/", () => {
assert.strictEqual(docsPrefix("/sdks/ios/sparkscan/intro/"), "");
assert.strictEqual(docsPrefix(`${PREVIEW}/sdks/ios/sparkscan/intro/`), PREVIEW);
assert.strictEqual(docsPrefix("/next/sdks/ios/sparkscan/intro/"), "/next");
assert.strictEqual(docsPrefix("/hosted/express/overview/"), "");
});

for (const [label, base] of [["at the site root", ""], ["on a preview build", PREVIEW]]) {
const prefix = docsPrefix(`${base}/sdks/ios/sparkscan/intro/`);
test(`${label}: links to an intro, with or without a trailing slash`, () => {
assert.strictEqual(overviewUrl(docs(base), prefix, "ios", sdk("sparkscan")), `${base}/sdks/ios/sparkscan/intro/`);
assert.strictEqual(overviewUrl(docs(base), prefix, "ios", sdk("matrixscan")), `${base}/sdks/ios/matrixscan/intro/`);
});
test(`${label}: falls back to get-started, then to a flat page`, () => {
assert.strictEqual(
overviewUrl(docs(base), prefix, "ios", sdk("barcode-capture")),
`${base}/sdks/ios/barcode-capture/get-started/`,
);
assert.strictEqual(
overviewUrl(docs(base), prefix, "ios", sdk("barcode-generator")),
`${base}/sdks/ios/barcode-generator/`,
);
});
test(`${label}: no page on this framework gives null`, () => {
assert.strictEqual(overviewUrl(docs(base), prefix, "android", sdk("sparkscan")), null);
assert.strictEqual(overviewUrl(docs(base), prefix, "ios", sdk("smart-label-capture")), null);
});
test(`${label}: a hosted product links to its one overview`, () => {
assert.strictEqual(overviewUrl(docs(base), prefix, "ios", hosted("express")), `${base}/hosted/express/overview/`);
assert.strictEqual(overviewUrl(docs(base), prefix, "ios", hosted("id-bolt")), null);
});
test(`${label}: uses the route segment, not the slug`, () => {
assert.strictEqual(overviewUrl(docs(base), prefix, "kmp", sdk("matrixscan")), `${base}/sdks/kmp/matrixscan/intro/`);
assert.strictEqual(
overviewUrl(docs(base), prefix, "net/ios", sdk("matrixscan")),
`${base}/sdks/net/ios/matrixscan/intro/`,
);
assert.strictEqual(overviewUrl(docs(base), prefix, "net-ios", sdk("matrixscan")), null);
});
}

const notFor = [
{ when: "count many", use: "matrixscan-count" },
{ when: "hosted flow", use: "express" },
];
test("shows only the alternatives available on the framework, in order", () => {
const onWeb = (key) => key !== "matrixscan-count";
assert.deepStrictEqual(visibleAlternatives(notFor, onWeb), [notFor[1]]);
assert.deepStrictEqual(visibleAlternatives(notFor, () => true), notFor);
});
test("no available alternative leaves an empty list (one column)", () => {
assert.deepStrictEqual(visibleAlternatives(notFor, () => false), []);
assert.deepStrictEqual(visibleAlternatives([], () => true), []);
});
test("asks about each alternative's product key", () => {
const asked = [];
visibleAlternatives(notFor, (key) => (asked.push(key), true));
assert.deepStrictEqual(asked, ["matrixscan-count", "express"]);
});

console.log(`test-product-chooser: ${passed} passed${process.exitCode ? ", some FAILED" : ""}`);
Loading
Loading