@brydio/manifest 0.1.0-alpha.59 → 0.1.0-alpha.61

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brydio/manifest",
3
- "version": "0.1.0-alpha.59",
3
+ "version": "0.1.0-alpha.61",
4
4
  "description": "The shape of a Brydio app's manifest, its collections' schemas, and the checks that say what is wrong with one.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,11 +10,15 @@
10
10
  "url": "https://github.com/nakel-ola/brydio-sdk",
11
11
  "directory": "packages/manifest"
12
12
  },
13
- "gitHead": "3645964c21307d88950b196e4fd389ad82e6a286",
13
+ "gitHead": "3b1b248522223b5b75fd9b5480c6cc7106dc6e87",
14
14
  "exports": {
15
15
  ".": {
16
16
  "types": "./src/index.d.ts",
17
17
  "default": "./src/index.js"
18
+ },
19
+ "./look": {
20
+ "types": "./src/look.d.ts",
21
+ "default": "./src/look.js"
18
22
  }
19
23
  },
20
24
  "files": [
package/src/bundle.d.ts CHANGED
@@ -11,11 +11,22 @@
11
11
  */
12
12
  /** 1 MB per version, every file counted, the manifest included. */
13
13
  export declare const BUNDLE_MAX_BYTES: number;
14
+ /**
15
+ * What a bundle with frame screens may carry beside its code (PB27): their
16
+ * pages, styles, images and media, 4 MB of them, on top of the 1 MB of code.
17
+ */
18
+ export declare const FRAME_ASSETS_MAX_BYTES: number;
14
19
  /** The manifest, at the root of every published bundle. Never stored, never hashed. */
15
20
  export declare const BUNDLE_MANIFEST = "app.json";
16
21
  export declare const BUNDLE_PATH_MAX_CHARS = 200;
17
22
  /** The files of one bundle, by path inside it. */
18
23
  export type BundleFiles = ReadonlyMap<string, Uint8Array>;
24
+ /** What a frame screen's page may load from its own bundle (PB27), by extension. No fonts. Brydio's list. */
25
+ export declare const FRAME_ASSET_TYPES: Readonly<Record<string, string>>;
26
+ /** Whether a file is a frame screen's asset rather than code. */
27
+ export declare const isFrameAsset: (path: string) => boolean;
28
+ /** The type a file is served with, or null for one the store never holds. Brydio's answer. */
29
+ export declare function contentTypeOf(path: string): string | null;
19
30
  /**
20
31
  * Whether a path can name a file inside a bundle: relative, forward slashes,
21
32
  * no empty, `.` or `..` segment, no hidden segment, plain printable ASCII.
@@ -54,6 +65,8 @@ export interface BundleProblem {
54
65
  * and words: every path first, then the manifest, then the code, then the size.
55
66
  */
56
67
  export declare function bundleProblem(files: BundleFiles): BundleProblem | null;
57
- /** Every file's bytes, the manifest included: what the cap is measured on. */
68
+ /** Every file's bytes, the manifest included. */
58
69
  export declare const bundleBytes: (files: BundleFiles) => number;
70
+ /** A frame screen's pages, styles, images and media, which have a cap of their own (PB27). */
71
+ export declare const frameAssetBytes: (files: BundleFiles) => number;
59
72
  export declare function sizeOf(bytes: number): string;
package/src/bundle.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { brandPathsOf } from "./requirements.js";
3
+ import { framePagesOf } from "./screen-kinds.js";
3
4
  /**
4
5
  * What a bundle may hold, and the fingerprint its code is served under
5
6
  * (contracts §11, A7-F02).
@@ -13,10 +14,41 @@ import { brandPathsOf } from "./requirements.js";
13
14
  */
14
15
  /** 1 MB per version, every file counted, the manifest included. */
15
16
  export const BUNDLE_MAX_BYTES = 1024 * 1024;
17
+ /**
18
+ * What a bundle with frame screens may carry beside its code (PB27): their
19
+ * pages, styles, images and media, 4 MB of them, on top of the 1 MB of code.
20
+ */
21
+ export const FRAME_ASSETS_MAX_BYTES = 4 * 1024 * 1024;
16
22
  /** The manifest, at the root of every published bundle. Never stored, never hashed. */
17
23
  export const BUNDLE_MANIFEST = 'app.json';
18
24
  export const BUNDLE_PATH_MAX_CHARS = 200;
19
25
  const SCRIPT = /\.m?js$/;
26
+ /** What a frame screen's page may load from its own bundle (PB27), by extension. No fonts. Brydio's list. */
27
+ export const FRAME_ASSET_TYPES = {
28
+ html: 'text/plain; charset=utf-8',
29
+ css: 'text/css; charset=utf-8',
30
+ png: 'image/png',
31
+ jpg: 'image/jpeg',
32
+ jpeg: 'image/jpeg',
33
+ gif: 'image/gif',
34
+ webp: 'image/webp',
35
+ avif: 'image/avif',
36
+ svg: 'image/svg+xml',
37
+ mp4: 'video/mp4',
38
+ webm: 'video/webm',
39
+ mp3: 'audio/mpeg',
40
+ ogg: 'audio/ogg',
41
+ wav: 'audio/wav',
42
+ };
43
+ const extensionOf = (path) => /\.([a-z0-9]+)$/i.exec(path)?.[1]?.toLowerCase() ?? '';
44
+ /** Whether a file is a frame screen's asset rather than code. */
45
+ export const isFrameAsset = (path) => !SCRIPT.test(path) && Object.prototype.hasOwnProperty.call(FRAME_ASSET_TYPES, extensionOf(path));
46
+ /** The type a file is served with, or null for one the store never holds. Brydio's answer. */
47
+ export function contentTypeOf(path) {
48
+ if (SCRIPT.test(path))
49
+ return 'text/javascript; charset=utf-8';
50
+ return isFrameAsset(path) ? FRAME_ASSET_TYPES[extensionOf(path)] : null;
51
+ }
20
52
  /**
21
53
  * Whether a path can name a file inside a bundle: relative, forward slashes,
22
54
  * no empty, `.` or `..` segment, no hidden segment, plain printable ASCII.
@@ -79,16 +111,24 @@ export function bundleHash(files) {
79
111
  */
80
112
  export function bundleProblem(files) {
81
113
  const brand = brandOf(files);
114
+ const pages = framePagesOf(manifestIn(files));
115
+ const framed = pages.size > 0;
82
116
  for (const path of files.keys()) {
83
117
  if (!isBundlePath(path)) {
84
118
  return { code: 'bundle_path_invalid', message: `"${JSON.stringify(path).slice(1, -1)}" is not a path a bundle can hold.`, file: path };
85
119
  }
86
120
  if (path !== BUNDLE_MANIFEST && !brand.has(path) && !SCRIPT.test(path)) {
87
- return {
88
- code: 'bundle_file_not_code',
89
- message: `"${path}" is not a script. A bundle holds only .js files and ${BUNDLE_MANIFEST}.`,
90
- file: path,
91
- };
121
+ // A frame screen's page, styles, images and media (PB27); nothing else.
122
+ const asset = framed && isFrameAsset(path) && (!path.endsWith('.html') || pages.has(path));
123
+ if (!asset) {
124
+ return {
125
+ code: 'bundle_file_not_code',
126
+ message: framed
127
+ ? `"${path}" is not a script, a frame screen's page, a stylesheet, an image or media. A bundle holds only those and ${BUNDLE_MANIFEST}.`
128
+ : `"${path}" is not a script. A bundle holds only .js files and ${BUNDLE_MANIFEST}.`,
129
+ file: path,
130
+ };
131
+ }
92
132
  }
93
133
  }
94
134
  if (!files.has(BUNDLE_MANIFEST)) {
@@ -97,9 +137,21 @@ export function bundleProblem(files) {
97
137
  if (codeOf(files).size === 0) {
98
138
  return { code: 'bundle_empty', message: 'That bundle has no screens in it, only a manifest.' };
99
139
  }
100
- const total = bundleBytes(files);
140
+ const assets = [...files].filter(([path]) => isFrameAsset(path) && !brand.has(path));
141
+ const assetBytes = assets.reduce((sum, [, bytes]) => sum + bytes.length, 0);
142
+ if (assetBytes > FRAME_ASSETS_MAX_BYTES) {
143
+ const [largest] = [...assets].sort(([, a], [, b]) => b.length - a.length);
144
+ return {
145
+ code: 'bundle_too_large',
146
+ message: `The frame screens' pages, styles, images and media are ${sizeOf(assetBytes)}, over the ${sizeOf(FRAME_ASSETS_MAX_BYTES)} cap. ` +
147
+ `The largest is "${largest[0]}" at ${sizeOf(largest[1].length)}.`,
148
+ file: largest[0],
149
+ };
150
+ }
151
+ const counted = [...files].filter(([path]) => !(isFrameAsset(path) && !brand.has(path)));
152
+ const total = counted.reduce((sum, [, bytes]) => sum + bytes.length, 0);
101
153
  if (total > BUNDLE_MAX_BYTES) {
102
- const [largest] = [...files].sort(([, a], [, b]) => b.length - a.length);
154
+ const [largest] = [...counted].sort(([, a], [, b]) => b.length - a.length);
103
155
  return {
104
156
  code: 'bundle_too_large',
105
157
  message: `That bundle is ${sizeOf(total)}, over the ${sizeOf(BUNDLE_MAX_BYTES)} cap. ` +
@@ -109,8 +161,13 @@ export function bundleProblem(files) {
109
161
  }
110
162
  return null;
111
163
  }
112
- /** Every file's bytes, the manifest included: what the cap is measured on. */
164
+ /** Every file's bytes, the manifest included. */
113
165
  export const bundleBytes = (files) => [...files.values()].reduce((sum, bytes) => sum + bytes.length, 0);
166
+ /** A frame screen's pages, styles, images and media, which have a cap of their own (PB27). */
167
+ export const frameAssetBytes = (files) => {
168
+ const brand = brandOf(files);
169
+ return [...files].filter(([path]) => isFrameAsset(path) && !brand.has(path)).reduce((sum, [, bytes]) => sum + bytes.length, 0);
170
+ };
114
171
  export function sizeOf(bytes) {
115
172
  if (bytes < 1024)
116
173
  return `${bytes} bytes`;
@@ -0,0 +1,13 @@
1
+ import type { BundleFiles } from './bundle.js';
2
+ /**
3
+ * What a publish warns about in a frame screen's own files (PB27), and never
4
+ * refuses: a password field, and a font of its own. A copy of Brydio's
5
+ * `frameWarnings` (`apps/api/src/apps/publishing/frame-checks.ts`), in its
6
+ * words, so `brydio validate` says what the registry will.
7
+ */
8
+ export interface FrameWarning {
9
+ code: 'frame_password_field' | 'frame_font';
10
+ message: string;
11
+ at: string;
12
+ }
13
+ export declare function frameWarnings(manifest: Record<string, unknown>, files: BundleFiles): FrameWarning[];
@@ -0,0 +1,35 @@
1
+ import { framePagesOf } from "./screen-kinds.js";
2
+ const text = (bytes) => (bytes ? new TextDecoder().decode(bytes) : '');
3
+ const PASSWORD_IN_PAGE = /<input\b[^>]*\btype\s*=\s*["']?password\b/i;
4
+ const PASSWORD_IN_SCRIPT = /\btype\s*[:=]\s*["']password["']|setAttribute\(\s*["']type["']\s*,\s*["']password["']\)/;
5
+ const FONT_FACE = /@font-face\b/i;
6
+ export function frameWarnings(manifest, files) {
7
+ const pages = framePagesOf(manifest);
8
+ const screens = (manifest.screens ?? {});
9
+ const warnings = [];
10
+ for (const [screen, declared] of Object.entries(screens)) {
11
+ const entry = declared?.entry;
12
+ if (typeof entry !== 'string' || !pages.has(entry))
13
+ continue;
14
+ const folder = entry.includes('/') ? entry.slice(0, entry.lastIndexOf('/') + 1) : '';
15
+ const scripts = [...files.keys()].filter(path => path !== entry && path.startsWith(folder) && !path.slice(folder.length).includes('/') && /\.m?js$/.test(path));
16
+ const password = PASSWORD_IN_PAGE.test(text(files.get(entry))) ? entry : scripts.find(path => PASSWORD_IN_SCRIPT.test(text(files.get(path))));
17
+ if (password) {
18
+ warnings.push({
19
+ code: 'frame_password_field',
20
+ at: password,
21
+ message: `The "${screen}" frame screen has a password field (${password}). An app never asks for a Brydio password or sign-in; a reviewer will ask why it is there.`,
22
+ });
23
+ }
24
+ }
25
+ for (const path of [...files.keys()].filter(one => one.endsWith('.css') || pages.has(one))) {
26
+ if (FONT_FACE.test(text(files.get(path)))) {
27
+ warnings.push({
28
+ code: 'frame_font',
29
+ at: path,
30
+ message: `${path} declares a font of its own. A frame screen loads no fonts; every app uses Brydio's own, so this one is never shown.`,
31
+ });
32
+ }
33
+ }
34
+ return warnings;
35
+ }
package/src/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export { APP_NAME_FORMAT, MANIFEST_LIMITS, SEMVER_FORMAT, baseManifestSchema, brandImagesSchema } from './base.js';
7
7
  export { BRAND_FIELDS, BRAND_LIMITS, brandFilePath, brandPathsOf, brandProblems, brandShapeOf, isBrandPath, pngVerdict, svgColours, toolsProblem, type BrandField, type RequirementCode, type RequirementFiles, type RequirementProblem, } from './requirements.js';
8
- export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, bundleBytes, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, type BundleFiles, type BundleProblem, type BundleProblemCode, } from './bundle.js';
8
+ export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, FRAME_ASSETS_MAX_BYTES, FRAME_ASSET_TYPES, bundleBytes, contentTypeOf, frameAssetBytes, isFrameAsset, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, type BundleFiles, type BundleProblem, type BundleProblemCode, } from './bundle.js';
9
9
  export { COLOUR_TOKENS, coeditedFields, FIELD_LIMITS, RESERVED_FIELDS, describeType, isCoedited, isSearchable, isSortable, isStructured, parseFieldType, structuredFields, valueProblem, valueSchema, FieldTypeInvalid, type DocumentOf, type FieldKind, type FieldType, type FieldValue, type FieldsOf, } from './field-types.js';
10
10
  export { appManifestSchema, appToolPrefix, collectionOf, crossAppTool, collectionsOf, dataProblems, effectivePlacementKey, HOME_CARD_SIZES, labelOf, manifestExtensionsSchema, newAppManifestSchema, SIZED_PLACEMENT_KINDS, MAX_APP_SECRETS, MAX_SECRET_CHARS, PLACEMENT_KEY, SECRET_NAME, storedExtensionsSchema, type AppManifestWithData, type CollectionSpec, type DataProblem, type DataProblemCode, type DataProblemOptions, type HomeCardSize, type ManifestExtensions, type SecretSpec, } from './schema.js';
11
11
  export { OPEN_LIMITS, OPEN_TYPES, choicesProblem, definitionOf, definitionTypeProblem, describeField, fieldTypeOf, hasChoices, isPlainOpenType, keyFromName, keyProblem, missingRequired, moveValue, openSchemaProblems, openSpec, openValueProblem, type Moved, type OpenField, type OpenFieldChange, type OpenFieldValue, type OpenProblem, type OpenProblemCode, type OpenSchemaFlag, type OpenType, } from './open-schema.js';
@@ -20,3 +20,6 @@ export { compareVersions, sdkRefusal, type SdkSupport } from './sdk.js';
20
20
  export { TOOL_WRITES, generatedToolsOf, toolNames, type GeneratedTool, type ToolVerb } from './tools.js';
21
21
  export { validateManifest, validateManifestText, type ManifestProblem, type ManifestProblemCode, type ManifestValidation, } from './validate.js';
22
22
  export { defineManifest, type ManifestShape, type ScreenNameOf, type WithDeclaredScreens } from './define.js';
23
+ export { themeProblems, themeWarnings, themeOf, styleRefusal, colourRefusal, type AppTheme, type ColourPair, type LookProblem, type LookProblemCode, type LookWarningCode, } from './look.js';
24
+ export { SCREEN_KINDS, framePagesOf, screenKindOf, screensOfKind, type ScreenKind } from './screen-kinds.js';
25
+ export { frameWarnings, type FrameWarning } from './frame-checks.js';
package/src/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export { APP_NAME_FORMAT, MANIFEST_LIMITS, SEMVER_FORMAT, baseManifestSchema, brandImagesSchema } from "./base.js";
7
7
  export { BRAND_FIELDS, BRAND_LIMITS, brandFilePath, brandPathsOf, brandProblems, brandShapeOf, isBrandPath, pngVerdict, svgColours, toolsProblem, } from "./requirements.js";
8
- export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, bundleBytes, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, } from "./bundle.js";
8
+ export { BUNDLE_MANIFEST, BUNDLE_MAX_BYTES, BUNDLE_PATH_MAX_CHARS, FRAME_ASSETS_MAX_BYTES, FRAME_ASSET_TYPES, bundleBytes, contentTypeOf, frameAssetBytes, isFrameAsset, bundleHash, brandOf, bundleProblem, codeOf, isBundlePath, isScriptPath, sizeOf, } from "./bundle.js";
9
9
  export { COLOUR_TOKENS, coeditedFields, FIELD_LIMITS, RESERVED_FIELDS, describeType, isCoedited, isSearchable, isSortable, isStructured, parseFieldType, structuredFields, valueProblem, valueSchema, FieldTypeInvalid, } from "./field-types.js";
10
10
  export { appManifestSchema, appToolPrefix, collectionOf, crossAppTool, collectionsOf, dataProblems, effectivePlacementKey, HOME_CARD_SIZES, labelOf, manifestExtensionsSchema, newAppManifestSchema, SIZED_PLACEMENT_KINDS, MAX_APP_SECRETS, MAX_SECRET_CHARS, PLACEMENT_KEY, SECRET_NAME, storedExtensionsSchema, } from "./schema.js";
11
11
  export { OPEN_LIMITS, OPEN_TYPES, choicesProblem, definitionOf, definitionTypeProblem, describeField, fieldTypeOf, hasChoices, isPlainOpenType, keyFromName, keyProblem, missingRequired, moveValue, openSchemaProblems, openSpec, openValueProblem, } from "./open-schema.js";
@@ -20,3 +20,8 @@ export { compareVersions, sdkRefusal } from "./sdk.js";
20
20
  export { TOOL_WRITES, generatedToolsOf, toolNames } from "./tools.js";
21
21
  export { validateManifest, validateManifestText, } from "./validate.js";
22
22
  export { defineManifest } from "./define.js";
23
+ // PB21, PB22: the look rules, Brydio's one rule set, copied.
24
+ export { themeProblems, themeWarnings, themeOf, styleRefusal, colourRefusal, } from "./look.js";
25
+ // PB27: tree screens and frame screens.
26
+ export { SCREEN_KINDS, framePagesOf, screenKindOf, screensOfKind } from "./screen-kinds.js";
27
+ export { frameWarnings } from "./frame-checks.js";
package/src/look.d.ts ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * How an app may look: its theme (`tasks/app-publishing` PB21) and the
3
+ * `style` any element takes (PB22).
4
+ *
5
+ * A copy of Brydio's rule set, `apps/api/src/apps/manifest/app-look.ts`, which
6
+ * is the one source: a publish and the registry read it there, the host
7
+ * checks every node it draws with its own copy, and `brydio validate`, the
8
+ * catalogue's checks (`@brydio/ui/validate`) and the fake host read this
9
+ * one. `test/look.test.ts` holds
10
+ * this copy to Brydio's answers, sentence for sentence, whenever a Brydio
11
+ * checkout sits beside this repository, and to the recorded answers in
12
+ * `contracts/brydio.json` otherwise. It imports nothing.
13
+ */
14
+ /** A name an app gives one of its colours: `ocean`, read as `app.ocean`. */
15
+ export declare const APP_COLOUR_NAME: RegExp;
16
+ /** The most named colours a theme may hold. */
17
+ export declare const MAX_APP_COLOURS = 24;
18
+ /** A plain colour: `#rgb` or `#rrggbb`. */
19
+ export declare const HEX_COLOUR: RegExp;
20
+ /** WCAG AA for body text. */
21
+ export declare const TEXT_CONTRAST = 4.5;
22
+ /**
23
+ * Brydio's own colours an app may name in a style, each to the token it
24
+ * reads. They follow light and dark by themselves.
25
+ */
26
+ export declare const BRYDIO_COLOURS: Readonly<Record<string, string>>;
27
+ /**
28
+ * What a check reads a Brydio colour as, to judge contrast on a screenshot.
29
+ * Near enough to the tokens to judge by; never drawn.
30
+ */
31
+ export declare const BRYDIO_COLOUR_CHECK_VALUES: Readonly<Record<'light' | 'dark', Readonly<Record<string, string>>>>;
32
+ /** Where Brydio draws an app: the ground a screenshot check reads text against. */
33
+ export declare const GROUND: {
34
+ readonly light: "#ffffff";
35
+ readonly dark: "#212121";
36
+ };
37
+ /** A colour with a value for each theme. */
38
+ export interface ColourPair {
39
+ light: string;
40
+ dark: string;
41
+ }
42
+ export declare const THEME_DENSITIES: readonly ["compact", "normal", "roomy"];
43
+ export declare const THEME_ROUNDINGS: readonly ["none", "small", "normal", "large", "round"];
44
+ export type ThemeDensity = (typeof THEME_DENSITIES)[number];
45
+ export type ThemeRounding = (typeof THEME_ROUNDINGS)[number];
46
+ /** How much each density scales Brydio's spacing and control heights. */
47
+ export declare const DENSITY_SCALE: Readonly<Record<ThemeDensity, number>>;
48
+ /** How much each rounding scales Brydio's corner radii. */
49
+ export declare const ROUNDING_SCALE: Readonly<Record<ThemeRounding, number>>;
50
+ /** An app's theme, as the manifest gives it (PB21). */
51
+ export interface AppTheme {
52
+ /** What the `brand` tone becomes inside the app. */
53
+ accent?: ColourPair;
54
+ /** Named colours, read as `app.<name>`. */
55
+ colors?: Record<string, ColourPair>;
56
+ rounding?: ThemeRounding;
57
+ density?: ThemeDensity;
58
+ }
59
+ export type LookProblemCode = 'theme_invalid' | 'theme_font' | 'theme_colour_pair' | 'theme_colour_format' | 'theme_colour_name' | 'theme_colours_too_many' | 'theme_density' | 'theme_rounding';
60
+ export type LookWarningCode = 'theme_contrast_low';
61
+ /** One thing wrong with a theme, named down to the field. */
62
+ export interface LookProblem {
63
+ code: LookProblemCode | LookWarningCode;
64
+ message: string;
65
+ /** Inside the manifest: `theme.colors.ocean.dark`. */
66
+ path: string;
67
+ }
68
+ /** Everything a publish refuses about a theme. Empty when it is fine. */
69
+ export declare function themeProblems(theme: unknown): LookProblem[];
70
+ /**
71
+ * What a publish warns about a theme, and never refuses: a colour whose best
72
+ * text, white or near-black, falls below WCAG AA on it.
73
+ */
74
+ export declare function themeWarnings(theme: unknown): LookProblem[];
75
+ /** The theme as code reads it after `themeProblems` found nothing. */
76
+ export declare function themeOf(manifest: unknown): AppTheme | null;
77
+ /** `#abc` → `[170, 187, 204]`, or null. */
78
+ export declare function rgbOf(hex: string): [number, number, number] | null;
79
+ /** WCAG contrast between two plain colours; 1 when either isn't one. */
80
+ export declare function contrastOf(a: string, b: string): number;
81
+ /** The text colour that reads best on a fill: white or near-black. */
82
+ export declare function onColour(fill: string): string;
83
+ /** How long a style may be, so a node can't carry a stylesheet. */
84
+ export declare const STYLE_MAX_KEYS = 48;
85
+ export declare const STYLE_MAX_BYTES: number;
86
+ /** The furthest a length may reach, in pixels. */
87
+ export declare const LENGTH_MAX = 10000;
88
+ /** Brydio's spacing steps an app may name: `space.4`. */
89
+ export declare const SPACE_MAX = 16;
90
+ /** The highest layer inside an app's area. The area starts its own, so this is all an app needs. */
91
+ export declare const Z_INDEX_MAX = 10;
92
+ export declare const BRYDIO_RADII: readonly ["xs", "sm", "md", "lg", "xl", "2xl", "3xl"];
93
+ export declare const BRYDIO_SHADOWS: readonly ["xs", "sm", "md", "lg"];
94
+ export declare const TRANSITIONS: readonly ["none", "fast", "base", "slow"];
95
+ type Rule = {
96
+ kind: 'size';
97
+ } | {
98
+ kind: 'space';
99
+ negative: boolean;
100
+ sides: boolean;
101
+ } | {
102
+ kind: 'offset';
103
+ } | {
104
+ kind: 'colour';
105
+ } | {
106
+ kind: 'enum';
107
+ values: readonly string[];
108
+ } | {
109
+ kind: 'number';
110
+ min: number;
111
+ max: number;
112
+ integer?: boolean;
113
+ } | {
114
+ kind: 'border-width';
115
+ } | {
116
+ kind: 'radius';
117
+ } | {
118
+ kind: 'shadow';
119
+ } | {
120
+ kind: 'font-size';
121
+ } | {
122
+ kind: 'font-weight';
123
+ } | {
124
+ kind: 'line-height';
125
+ } | {
126
+ kind: 'flex';
127
+ } | {
128
+ kind: 'tracks';
129
+ } | {
130
+ kind: 'grid-line';
131
+ } | {
132
+ kind: 'position';
133
+ } | {
134
+ kind: 'z-index';
135
+ } | {
136
+ kind: 'image';
137
+ } | {
138
+ kind: 'transition';
139
+ };
140
+ /** Every property a style may set (PB22), and what it takes. Nothing else is drawn. */
141
+ export declare const STYLE_PROPERTIES: Readonly<Record<string, Rule>>;
142
+ /** Properties people reach for that are refused on purpose, with the rule that refuses them. */
143
+ export declare const STYLE_REFUSED: Readonly<Record<string, string>>;
144
+ /**
145
+ * Why a colour can't be drawn, or null. A colour is one of Brydio's
146
+ * (`brydio.text`), one of the app's (`app.ocean`), `transparent`,
147
+ * `currentColor`, or a plain pair `{ light, dark }`. `colours`, when given,
148
+ * are the app's own names, so a name it never declared is refused too.
149
+ */
150
+ export declare function colourRefusal(value: unknown, colours?: ReadonlySet<string>): string | null;
151
+ /**
152
+ * Why a node's `style` can't be drawn, or null when it can (PB22). The
153
+ * sentence names the property and the rule: "style position can’t be fixed
154
+ * or sticky: …".
155
+ */
156
+ export declare function styleRefusal(style: unknown, colours?: ReadonlySet<string>): string | null;
157
+ /** The app colour names a theme declares, for `colourRefusal`. */
158
+ export declare function colourNamesOf(theme: AppTheme | null | undefined): Set<string>;
159
+ /** The app colour a tone names (`app.ocean` → `ocean`), or null when it names a Brydio tone. */
160
+ export declare const appColourOfTone: (tone: unknown) => string | null;
161
+ export type Mode = 'light' | 'dark';
162
+ /**
163
+ * The plain colour a value is in this mode, for a check: an app colour or a
164
+ * pair to its hex, a Brydio colour to the value checks read it as, otherwise
165
+ * null.
166
+ */
167
+ export declare function checkColourOf(value: unknown, mode: Mode, theme: AppTheme | null | undefined): string | null;
168
+ /** The CSS a colour is drawn with in this mode. */
169
+ export declare function cssColourOf(value: unknown, mode: Mode): string | null;
170
+ /**
171
+ * A checked style as CSS declarations, for this mode. Only what passed
172
+ * `styleRefusal` is ever given here; anything it can't read is left out.
173
+ * `backgroundImage` is the host's to draw, since only it can read the file.
174
+ */
175
+ export declare function styleToCss(style: Record<string, unknown>, mode: Mode): Record<string, string>;
176
+ /**
177
+ * The CSS variables an app's area carries for its theme in this mode: its
178
+ * colours as `--app-color-<name>`, the accent as Brydio's brand tokens (so
179
+ * the `brand` tone is the app's), and the rounding and density as scales of
180
+ * Brydio's own radii and spacing.
181
+ */
182
+ export declare function themeVariables(theme: AppTheme | null | undefined, mode: Mode): Record<string, string>;
183
+ /**
184
+ * Whether a setting may name one of the app's colours as well as its own
185
+ * values (PB21): a `tone` that offers Brydio's `brand`.
186
+ */
187
+ export declare const takesAppColour: (name: string, values: readonly string[]) => boolean;
188
+ /** What a tone that names an app colour is told when it isn't one. */
189
+ export declare const appColourSaid = "or one of the app\u2019s colours (app.<name>)";
190
+ /**
191
+ * Why a `bry-canvas`'s shapes can't be drawn, or null (PB24). Their shape is
192
+ * the catalogue's to check; this is their colours, which are names only —
193
+ * Brydio's or the app's — so a canvas follows light and dark.
194
+ */
195
+ export declare function canvasRefusal(ops: unknown, colours?: ReadonlySet<string>): string | null;
196
+ export {};