@valbuild/core 0.144.0 → 0.145.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/declarations/src/index.d.ts +8 -1
- package/dist/declarations/src/initSchema.d.ts +23 -1
- package/dist/declarations/src/render.d.ts +38 -5
- package/dist/declarations/src/schema/number.d.ts +45 -5
- package/dist/declarations/src/schema/numberRules.d.ts +27 -0
- package/dist/{index-aa16dd90.esm.js → index-307b907e.esm.js} +266 -32
- package/dist/{index-2d194c90.cjs.prod.js → index-93763025.cjs.prod.js} +266 -32
- package/dist/{index-8b22b2c1.cjs.dev.js → index-ee601322.cjs.dev.js} +266 -32
- package/dist/valbuild-core.cjs.dev.js +1 -1
- package/dist/valbuild-core.cjs.prod.js +1 -1
- package/dist/valbuild-core.esm.js +1 -1
- package/package.json +1 -1
- package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
- package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
- package/patch/dist/valbuild-core-patch.esm.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @valbuild/core
|
|
2
2
|
|
|
3
|
+
## 0.145.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#851](https://github.com/valbuild/val/pull/851) [`b6cb939`](https://github.com/valbuild/val/commit/b6cb9395d8bdcd5182e9c6ba84f5284930de2fa5) Thanks [@freekh](https://github.com/freekh)! - New `s.int()` for whole numbers, `.step()` on `s.int()` and `s.number()`, and a slider for both:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
s.object({
|
|
11
|
+
columns: s.int().min(1).max(6),
|
|
12
|
+
opacity: s
|
|
13
|
+
.int()
|
|
14
|
+
.min(0)
|
|
15
|
+
.max(100)
|
|
16
|
+
.step(5)
|
|
17
|
+
.render({ as: "slider", min: 0, max: 100 }),
|
|
18
|
+
lineHeight: s.number().render({ as: "slider", min: 1, max: 2, step: 0.1 }),
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- `.min()`, `.max()` and `.step()` are rules the validator checks. A step is counted from `min`, or from 0 when there is none.
|
|
23
|
+
- `.render({ as: "slider", min, max, step? })` is how the field is edited: a slider, with a box beside it for typing an exact value. `min` and `max` are required. The slider's step defaults to the schema's `.step()`, then to 1.
|
|
24
|
+
- The slider can only produce values the schema accepts. A slider outside `.min()`/`.max()`, with a step that is not a multiple of `.step()`, or with decimals on an `s.int()` throws where the schema is defined.
|
|
25
|
+
- A value outside the slider's range is still valid content. The field says it is out of the slider's reach and offers "Set to" the nearest stop. A value that breaks a rule offers "Round to" the nearest allowed value.
|
|
26
|
+
- Fixed: `.min(0)` and `.max(0)` on `s.number()` were ignored.
|
|
27
|
+
- A new item of a number schema starts at the nearest allowed value instead of `0`, so `s.int().min(1)` starts at 1.
|
|
28
|
+
|
|
3
29
|
## 0.144.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
|
@@ -58,6 +58,8 @@ export { type SerializedObjectSchema, ObjectSchema } from "./schema/object.js";
|
|
|
58
58
|
export { type SerializedRecordSchema, type MediaCollectionType, RecordSchema, } from "./schema/record.js";
|
|
59
59
|
export { type SerializedStringSchema, StringSchema } from "./schema/string.js";
|
|
60
60
|
export { type SerializedNumberSchema, NumberSchema } from "./schema/number.js";
|
|
61
|
+
import { nearestAllowedNumber, isOnStep, stepOrigin } from "./schema/numberRules.js";
|
|
62
|
+
export type { NumberRules } from "./schema/numberRules.js";
|
|
61
63
|
export { type SerializedBooleanSchema, BooleanSchema } from "./schema/boolean.js";
|
|
62
64
|
export { type SerializedImageSchema, ImageSchema } from "./schema/image.js";
|
|
63
65
|
export { type SerializedFileSchema, FileSchema } from "./schema/file.js";
|
|
@@ -89,7 +91,7 @@ export { type SerializedUnionSchema, type UnionSchema, type SerializedStringUnio
|
|
|
89
91
|
export { type SerializedLiteralSchema, LiteralSchema } from "./schema/literal.js";
|
|
90
92
|
export { deserializeSchema } from "./schema/deserialize.js";
|
|
91
93
|
export { type PreviewItem, type ItemPreviewInput, type RecordPreview, type ArrayPreview, type ReifiedPreview, type PreviewScope, previewScope, } from "./preview.js";
|
|
92
|
-
export { type InlineRender, type FieldRender, isInlineRender } from "./render.js";
|
|
94
|
+
export { type InlineRender, type FieldRender, type SliderRender, type NumberRender, isInlineRender, } from "./render.js";
|
|
93
95
|
export type { ValRouter, ExternalPageRouter, RouteValidationError, } from "./router.js";
|
|
94
96
|
export { parseNextJsRoutePattern, parseTanStackRoutePattern, tanStackSegmentsOfRoutePath, validateUrlAgainstPattern, } from "./router.js";
|
|
95
97
|
export { getSourcePathFromRoute, isPageRouter } from "./getSourcePathFromRoute.js";
|
|
@@ -173,6 +175,11 @@ declare const Internal: {
|
|
|
173
175
|
rejectScheme: typeof rejectScheme;
|
|
174
176
|
schemeOf: typeof schemeOf;
|
|
175
177
|
UNSAFE_URL_SCHEMES: readonly ["javascript", "data", "vbscript", "file", "blob"];
|
|
178
|
+
number: {
|
|
179
|
+
nearestAllowedNumber: typeof nearestAllowedNumber;
|
|
180
|
+
isOnStep: typeof isOnStep;
|
|
181
|
+
stepOrigin: typeof stepOrigin;
|
|
182
|
+
};
|
|
176
183
|
color: {
|
|
177
184
|
parseColor: typeof parseColor;
|
|
178
185
|
formatColor: typeof formatColor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { array } from "./schema/array.js";
|
|
2
|
-
import { number } from "./schema/number.js";
|
|
2
|
+
import { int, number } from "./schema/number.js";
|
|
3
3
|
import { object } from "./schema/object.js";
|
|
4
4
|
import { string } from "./schema/string.js";
|
|
5
5
|
import { boolean } from "./schema/boolean.js";
|
|
@@ -74,6 +74,28 @@ export type InitSchema = {
|
|
|
74
74
|
*
|
|
75
75
|
*/
|
|
76
76
|
readonly number: typeof number;
|
|
77
|
+
/**
|
|
78
|
+
* Define a whole number. The source is an ordinary `number`; `s.int()` adds
|
|
79
|
+
* the rule that it has no decimals.
|
|
80
|
+
*
|
|
81
|
+
* Takes `.min()`, `.max()` and `.step()` for what the value may be, and
|
|
82
|
+
* `.render({ as: "slider", min, max })` to edit it with a slider.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const schema = s.object({
|
|
86
|
+
* columns: s.int().min(1).max(6),
|
|
87
|
+
* opacity: s.int().min(0).max(100).step(5).render({
|
|
88
|
+
* as: "slider",
|
|
89
|
+
* min: 0,
|
|
90
|
+
* max: 100,
|
|
91
|
+
* }),
|
|
92
|
+
* });
|
|
93
|
+
* export default c.define("/example.val.ts", schema, {
|
|
94
|
+
* columns: 3,
|
|
95
|
+
* opacity: 40,
|
|
96
|
+
* });
|
|
97
|
+
*/
|
|
98
|
+
readonly int: typeof int;
|
|
77
99
|
/**
|
|
78
100
|
* Define one of several object shapes, told apart by a tag field.
|
|
79
101
|
*
|
|
@@ -27,11 +27,12 @@ import type { SerializedSchema } from "./schema/index.js";
|
|
|
27
27
|
*/
|
|
28
28
|
/**
|
|
29
29
|
* A RENDER is how a field is laid out in the editor, and it applies only when
|
|
30
|
-
* you are looking at the field.
|
|
31
|
-
* children, never by a child about itself: `s.array(item).render({ as: "inline" })`
|
|
32
|
-
* and `s.record(item).render({ as: "inline" })`.
|
|
33
|
-
*
|
|
34
|
-
* `KeyOfSchema.render`).
|
|
30
|
+
* you are looking at the field. On a list it is declared by the CONTAINER about
|
|
31
|
+
* its children, never by a child about itself: `s.array(item).render({ as: "inline" })`
|
|
32
|
+
* and `s.record(item).render({ as: "inline" })`. Two other schemas take a
|
|
33
|
+
* render, each meaning something of its own: `s.keyOf(...)` (see
|
|
34
|
+
* `KeyOfSchema.render`) and `s.number()` / `s.int()`, whose `{ as: "slider" }`
|
|
35
|
+
* is a different input for the same value (see {@link SliderRender}).
|
|
35
36
|
*
|
|
36
37
|
* Why the container: inline is a property of the LIST — "my items are edited in
|
|
37
38
|
* their rows" — and the item schema is the wrong place to say it. An item can be
|
|
@@ -89,6 +90,38 @@ export type InlineRender = {
|
|
|
89
90
|
* What `.render(...)` takes, and what the serialized schema carries verbatim.
|
|
90
91
|
*/
|
|
91
92
|
export type FieldRender = InlineRender;
|
|
93
|
+
/**
|
|
94
|
+
* `{ as: "slider", min, max }` on `s.int()` or `s.number()`: the value is
|
|
95
|
+
* edited with a slider from `min` to `max`, next to a box that takes a typed
|
|
96
|
+
* value.
|
|
97
|
+
*
|
|
98
|
+
* `min` and `max` are REQUIRED, because a slider without ends is not a slider.
|
|
99
|
+
* They are the slider's own and are not validation: a value outside them is
|
|
100
|
+
* still valid content (if the schema allows it), and the field says it is out
|
|
101
|
+
* of the slider's reach and offers to bring it back. What the schema accepts is
|
|
102
|
+
* `.min()`, `.max()` and `.step()` on the schema itself.
|
|
103
|
+
*
|
|
104
|
+
* The one rule tying the two together: **the slider may only produce values
|
|
105
|
+
* the schema accepts.** So its range has to lie inside the schema's, its step
|
|
106
|
+
* has to be a multiple of the schema's step and its `min` on the schema's grid,
|
|
107
|
+
* and on `s.int()` all of them have to be whole numbers. A schema that breaks
|
|
108
|
+
* that throws where it is defined — see `NumberSchema`.
|
|
109
|
+
*
|
|
110
|
+
* `step` defaults to the schema's `.step()`, and to 1 when there is none.
|
|
111
|
+
*
|
|
112
|
+
* Unlike `inline` this is about the field itself — no list reads it, and
|
|
113
|
+
* {@link isInlineRender} answers `false` for it.
|
|
114
|
+
*/
|
|
115
|
+
export type SliderRender = {
|
|
116
|
+
as: "slider";
|
|
117
|
+
min: number;
|
|
118
|
+
max: number;
|
|
119
|
+
step?: number;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* What `s.number().render(...)` and `s.int().render(...)` take.
|
|
123
|
+
*/
|
|
124
|
+
export type NumberRender = SliderRender;
|
|
92
125
|
/**
|
|
93
126
|
* Does this CONTAINER edit its items inside their list rows, rather than behind
|
|
94
127
|
* clickable preview rows that navigate to them?
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
|
|
2
2
|
import { ItemPreviewInput, PreviewItem } from "../preview.js";
|
|
3
|
+
import { NumberRender } from "../render.js";
|
|
3
4
|
import { SourcePath } from "../val/index.js";
|
|
4
5
|
import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { NumberRules } from "./numberRules.js";
|
|
7
|
+
/**
|
|
8
|
+
* What the value has to be. `integer` is what makes a number schema an
|
|
9
|
+
* `s.int()`: the source is a number either way, so an int is a number schema
|
|
10
|
+
* with one more rule rather than a schema type of its own (which every walk
|
|
11
|
+
* over a schema would have had to learn).
|
|
12
|
+
*/
|
|
13
|
+
type NumberOptions = NumberRules;
|
|
9
14
|
export type SerializedNumberSchema = {
|
|
10
15
|
type: "number";
|
|
11
16
|
/** Set when this schema declares a `preview`. The closure itself cannot serialize. */
|
|
12
17
|
preview?: true;
|
|
13
18
|
options?: NumberOptions;
|
|
19
|
+
/** How the field is edited. Static config — see `render.ts`. */
|
|
20
|
+
render?: NumberRender;
|
|
14
21
|
opt: boolean;
|
|
15
22
|
customValidate?: boolean;
|
|
16
23
|
readonly?: boolean;
|
|
@@ -25,7 +32,8 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
|
|
|
25
32
|
private readonly isHidden;
|
|
26
33
|
private readonly description?;
|
|
27
34
|
private readonly previewInput;
|
|
28
|
-
|
|
35
|
+
private readonly renderInput;
|
|
36
|
+
constructor(options?: NumberOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null, renderInput?: NumberRender | null);
|
|
29
37
|
/**
|
|
30
38
|
* Describe this field.
|
|
31
39
|
*
|
|
@@ -86,6 +94,37 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
|
|
|
86
94
|
* export default c.define("/example.val.ts", schema, 3);
|
|
87
95
|
*/
|
|
88
96
|
min(min: number): NumberSchema<Src>;
|
|
97
|
+
/**
|
|
98
|
+
* Validate that the number is on a grid of `step`: one of `min`, `min + step`,
|
|
99
|
+
* `min + 2 * step` and so on, counted from 0 when there is no `.min()`.
|
|
100
|
+
*
|
|
101
|
+
* A slider rendered on this field moves in the same steps unless its render
|
|
102
|
+
* says otherwise (and then its step has to be a multiple of this one).
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const schema = s.int().min(0).max(100).step(5);
|
|
106
|
+
* export default c.define("/example.val.ts", schema, 40);
|
|
107
|
+
*/
|
|
108
|
+
step(step: number): NumberSchema<Src>;
|
|
109
|
+
/**
|
|
110
|
+
* Choose how this field is edited. `{ as: "slider", min, max }` edits it with
|
|
111
|
+
* a slider from `min` to `max`, next to a box for typing an exact value.
|
|
112
|
+
*
|
|
113
|
+
* `min` and `max` are required — a slider without ends is not a slider — and
|
|
114
|
+
* they are the slider's, not validation: use `.min()` / `.max()` for what the
|
|
115
|
+
* value may be. The slider can only produce values this schema accepts, so
|
|
116
|
+
* its range must lie inside `.min()`/`.max()`, its `step` (which defaults to
|
|
117
|
+
* `.step()`, then 1) must be a multiple of `.step()`, and on `s.int()` all of
|
|
118
|
+
* them must be whole numbers. A schema that breaks this throws here.
|
|
119
|
+
*
|
|
120
|
+
* Static configuration, not a callback — see `render.ts`. A second
|
|
121
|
+
* `.render(...)` replaces the first.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* const schema = s.int().render({ as: "slider", min: 0, max: 100, step: 5 });
|
|
125
|
+
* export default c.define("/example.val.ts", schema, 40);
|
|
126
|
+
*/
|
|
127
|
+
render(input: NumberRender): NumberSchema<Src>;
|
|
89
128
|
protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
|
|
90
129
|
/**
|
|
91
130
|
* How this VALUE is shown where a preview of it is needed — a row in a
|
|
@@ -104,4 +143,5 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
|
|
|
104
143
|
protected executeSerialize(): SerializedSchema;
|
|
105
144
|
}
|
|
106
145
|
export declare const number: (options?: NumberOptions) => NumberSchema<number>;
|
|
146
|
+
export declare const int: () => NumberSchema<number>;
|
|
107
147
|
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a number schema accepts, in one place, so the validator and the
|
|
3
|
+
* Studio's "Round to …" / "Set to …" buttons cannot disagree about it.
|
|
4
|
+
*
|
|
5
|
+
* A button that offers a value the validator then rejects is worse than no
|
|
6
|
+
* button, which is exactly what two copies of this arithmetic would drift into.
|
|
7
|
+
*/
|
|
8
|
+
export type NumberRules = {
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Whole numbers only — `s.int()`. */
|
|
12
|
+
integer?: boolean;
|
|
13
|
+
/** Allowed values are `origin + n * step`, where the origin is `min` or 0. */
|
|
14
|
+
step?: number;
|
|
15
|
+
};
|
|
16
|
+
/** Where the step grid starts: the schema's `min`, or 0 when it has none. */
|
|
17
|
+
export declare function stepOrigin(rules: NumberRules): number;
|
|
18
|
+
/** Is `value` one of `origin + n * step`? */
|
|
19
|
+
export declare function isOnStep(value: number, origin: number, step: number): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The allowed value closest to `value`: inside `min`/`max`, on the step grid,
|
|
22
|
+
* and whole when the schema is an int.
|
|
23
|
+
*
|
|
24
|
+
* Returns `null` when the rules leave nothing to snap to — a `min` above
|
|
25
|
+
* `max`, or a range too narrow to hold a single step or a single whole number.
|
|
26
|
+
*/
|
|
27
|
+
export declare function nearestAllowedNumber(value: number, rules: NumberRules): number | null;
|