Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5487dbf
[benc/input-number-v2-take-3] Align input-number options type with nu…
benchristel Jun 10, 2026
20bbee9
[benc/input-number-v2-take-3] Update getInputNumberPublicWidgetOptions
benchristel Jun 10, 2026
728fa23
[benc/input-number-v2-take-3] Use v1 options in scoring tests
benchristel Jun 10, 2026
7f66ef7
[benc/input-number-v2-take-3] Delete InputNumber component; replace w…
benchristel Jun 10, 2026
258f958
[benc/input-number-v2-take-3] Move IN->NI conversion functions into p…
benchristel Jun 10, 2026
b7b7826
[benc/input-number-v2-take-3] Fix lint
benchristel Jun 10, 2026
07b6d30
[benc/input-number-v2-take-3] Remove input-number editor code
benchristel Jun 10, 2026
064e563
[benc/input-number-v2-take-3] Knip
benchristel Jun 10, 2026
6231ad3
[benc/input-number-v2-take-3] Update pnpm-lock.yaml
benchristel Jun 11, 2026
fa61e4f
[benc/input-number-v2-take-3] docs(changeset): The InputNumber widget…
benchristel Jun 11, 2026
91e4651
[benc/input-number-v2-take-3] docs(changeset): Removes the experiment…
benchristel Jun 11, 2026
3a5c114
[benc/input-number-v2-take-3] Delete v0 types
benchristel Jun 11, 2026
4dc3bb1
[benc/input-number-v2-take-3] Make InputNumber types alias NumericInp…
benchristel Jun 11, 2026
ac40ed3
[benc/input-number-v2-take-3] Remove TODO
benchristel Jun 11, 2026
28f6b75
[benc/input-number-v2-take-3] Use generators to abbreviate tests
benchristel Jun 11, 2026
dc7e98a
[benc/input-number-v2-take-3] Fold input-number case into numeric-input
benchristel Jun 11, 2026
0821496
[benc/input-number-v2-take-3] Use generators again
benchristel Jun 11, 2026
bb1a872
[benc/input-number-v2-take-3] Use numeric-input code for public widge…
benchristel Jun 11, 2026
8634617
[benc/input-number-v2-take-3] Use PerseusNumericInputRubric type
benchristel Jun 11, 2026
22eedbb
[benc/input-number-v2-take-3] Use generators
benchristel Jun 11, 2026
8d1d0a9
[benc/input-number-v2-take-3] Delete scoring code
benchristel Jun 11, 2026
9f4974b
[benc/input-number-v2-take-3] Fix answerless types
benchristel Jun 11, 2026
fe6a95e
[benc/input-number-v2-take-3] Ensure generated input-number widgets h…
benchristel Jun 11, 2026
07d6f6e
[benc/input-number-v2-take-3] Add test coverage for version number in…
benchristel Jun 11, 2026
0f4791e
[benc/input-number-v2-take-3] Remove non-actionable TODO
benchristel Jun 11, 2026
2f62c39
[benc/input-number-v2-take-3] Delete unused test data file
benchristel Jun 11, 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
42 changes: 41 additions & 1 deletion packages/perseus-core/src/data-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2238,7 +2238,8 @@ export type PerseusInputNumberAnswerType =
| "pi";

/** Options for the input-number widget (deprecated; prefer numeric-input). */
export type PerseusInputNumberWidgetOptions = {
// FIXME: delete
export type PerseusInputNumberWidgetOptionsV0 = {
answerType?: PerseusInputNumberAnswerType;
inexact?: boolean;
maxError?: number | string;
Expand All @@ -2248,6 +2249,45 @@ export type PerseusInputNumberWidgetOptions = {
value: string | number;
};

export type PerseusInputNumberAnswer = {
/** The expected answer. Null in answerless data. */
value: number | null;
status: "correct";
message: "";
/** The accepted answer forms. */
answerForms: MathFormat[];
strict: true;
/**
* The maximum difference between the answer key `value` and a correct
* response.
*/
maxError?: number | undefined;
/** Determines how unsimplified responses are handled */
simplify: PerseusNumericInputSimplify;
};

export type PerseusInputNumberWidgetOptions = {
answers: [PerseusInputNumberAnswer];
Comment thread
benchristel marked this conversation as resolved.
Outdated
/**
* Translatable Text; Text to describe this input. This will be shown to
* users using screenreaders.
*/
labelText?: string | undefined;
/**
* Use size "Normal" for all text boxes, unless there are multiple text
* boxes in one line and the answer area is too narrow to fit them.
* Options: "normal" or "small"
*/
size: "normal" | "small";
/**
* A coefficient style number allows the student to use - for -1 and an
* empty string to mean 1.
*/
coefficient: false;
/** Whether to right-align the text or not */
rightAlign?: boolean;
};

/** Options for the molecule-renderer widget. Renders a molecule via SMILES. */
export type PerseusMoleculeRendererWidgetOptions = {
widgetId: string;
Expand Down
17 changes: 17 additions & 0 deletions packages/perseus-core/src/data-schema.typetest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {describe, expect, it} from "tstyche";

import type {
PerseusInputNumberWidgetOptions,
PerseusNumericInputWidgetOptions,
} from "./data-schema";

describe("PerseusInputNumberWidgetOptions", () => {
it("is assignable to PerseusNumericInputWidgetOptions", () => {
// This test is needed because the PerseusInputNumberWidgetOptions now
// get passed to the NumericInput component. We are currently (May
// 2026) removing the deprecated InputNumber code in favor of using
// NumericInput everywhere, but we need to keep separate types for
// InputNumber to support legacy content.
expect<PerseusInputNumberWidgetOptions>().type.toBeAssignableTo<PerseusNumericInputWidgetOptions>();
});
});
4 changes: 1 addition & 3 deletions packages/perseus-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,6 @@ export {default as videoLogic} from "./widgets/video";
/** @hidden */
export type {VideoDefaultWidgetOptions} from "./widgets/video";

/** @hidden */
export {convertInputNumberOptionsToNumericInput} from "./widgets/input-number/to-numeric-input";

/** @hidden */
export {
applyDefaultsToWidgets,
Expand Down Expand Up @@ -371,6 +368,7 @@ export {
export {
generateInputNumberOptions,
generateInputNumberWidget,
generateInputNumberAnswer,
} from "./utils/generators/input-number-widget-generator";
/** @hidden */
export {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {describe, expect, it} from "@jest/globals";

import {success} from "../result";

import {number} from "./number";
import {singleton} from "./singleton";
import {ctx, parseFailureWith} from "./test-helpers";

describe("singleton", () => {
const singleNumber = singleton(number);

it("accepts a one-element array", () => {
expect(singleNumber([1], ctx())).toEqual(success([1]));
});

it("rejects an empty array", () => {
expect(singleNumber([], ctx())).toEqual(
parseFailureWith({expected: ["array of length 1"]}),
);
});

it("rejects a two-element array", () => {
expect(singleNumber([1, 2], ctx())).toEqual(
parseFailureWith({expected: ["array of length 1"]}),
);
});

it("rejects a non-array", () => {
expect(singleNumber(1, ctx())).toEqual(
parseFailureWith({expected: ["array"]}),
);
});

it("rejects an invalid element type", () => {
expect(singleNumber(["bad"], ctx())).toEqual(
parseFailureWith({expected: ["number"], path: [0]}),
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {isFailure} from "../result";

import type {Parser} from "../parser-types";

/**
* Parses a one-element tuple.
*/
export function singleton<T>(parseElement: Parser<T>): Parser<[T]> {
return (rawValue, ctx) => {
if (!Array.isArray(rawValue)) {
return ctx.failure("array", rawValue);
}
if (rawValue.length !== 1) {
return ctx.failure("array of length 1", rawValue);
}

const [rawElement] = rawValue;
const result = parseElement(rawElement, ctx.forSubtree(0));
if (isFailure(result)) {
return result;
}

return ctx.success([result.value]);
};
}
Loading
Loading