@nxgt/material-core 0.12.0 → 0.13.1
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 +36 -0
- package/README.md +275 -24
- package/dist/backgrounds/activity.d.ts +11 -0
- package/dist/backgrounds/activity.d.ts.map +1 -0
- package/dist/backgrounds/build.d.ts +9 -0
- package/dist/backgrounds/build.d.ts.map +1 -0
- package/dist/backgrounds/id-prefix.d.ts +8 -0
- package/dist/backgrounds/id-prefix.d.ts.map +1 -0
- package/dist/backgrounds/index.d.ts +20 -0
- package/dist/backgrounds/index.d.ts.map +1 -0
- package/dist/backgrounds/index.js +467 -0
- package/dist/backgrounds/index.js.map +20 -0
- package/dist/backgrounds/noise.d.ts +7 -0
- package/dist/backgrounds/noise.d.ts.map +1 -0
- package/dist/backgrounds/presets/grain.d.ts +9 -0
- package/dist/backgrounds/presets/grain.d.ts.map +1 -0
- package/dist/backgrounds/presets.d.ts +16 -0
- package/dist/backgrounds/presets.d.ts.map +1 -0
- package/dist/backgrounds/primitives.d.ts +22 -0
- package/dist/backgrounds/primitives.d.ts.map +1 -0
- package/dist/backgrounds/rng.d.ts +12 -0
- package/dist/backgrounds/rng.d.ts.map +1 -0
- package/dist/backgrounds/scatter.d.ts +25 -0
- package/dist/backgrounds/scatter.d.ts.map +1 -0
- package/dist/backgrounds/scene.d.ts +21 -0
- package/dist/backgrounds/scene.d.ts.map +1 -0
- package/dist/backgrounds/tones.d.ts +4 -0
- package/dist/backgrounds/tones.d.ts.map +1 -0
- package/dist/backgrounds/types.d.ts +53 -0
- package/dist/backgrounds/types.d.ts.map +1 -0
- package/dist/chunks/index-mw5fa8qa.js +119 -0
- package/dist/chunks/index-mw5fa8qa.js.map +12 -0
- package/dist/csp/index.d.ts +10 -0
- package/dist/csp/index.d.ts.map +1 -0
- package/dist/csp/index.js +21 -0
- package/dist/csp/index.js.map +9 -0
- package/dist/csp/nonce.d.ts +35 -0
- package/dist/csp/nonce.d.ts.map +1 -0
- package/dist/csp/policy.d.ts +33 -0
- package/dist/csp/policy.d.ts.map +1 -0
- package/dist/csp/zod-jitless.d.ts +4 -0
- package/dist/csp/zod-jitless.d.ts.map +1 -0
- package/dist/lib/drawer-room.d.ts +8 -0
- package/dist/lib/drawer-room.d.ts.map +1 -0
- package/dist/lib/drawer-room.js +17 -0
- package/dist/lib/drawer-room.js.map +10 -0
- package/dist/lib/escape-forward.d.ts +14 -0
- package/dist/lib/escape-forward.d.ts.map +1 -1
- package/dist/lib/escape-forward.js +22 -2
- package/dist/lib/escape-forward.js.map +3 -3
- package/dist/pdf-viewer/index.d.ts +1 -0
- package/dist/pdf-viewer/index.d.ts.map +1 -1
- package/dist/pdf-viewer/index.js +77 -38
- package/dist/pdf-viewer/index.js.map +6 -5
- package/dist/pdf-viewer/pdf-pin-page.d.ts +9 -0
- package/dist/pdf-viewer/pdf-pin-page.d.ts.map +1 -1
- package/dist/pdf-viewer/pdf-reveal-hit.d.ts +7 -0
- package/dist/pdf-viewer/pdf-reveal-hit.d.ts.map +1 -0
- package/dist/pdf-viewer/pdf-scroll-spy.d.ts +21 -8
- package/dist/pdf-viewer/pdf-scroll-spy.d.ts.map +1 -1
- package/dist/states/copy.d.ts +46 -0
- package/dist/states/copy.d.ts.map +1 -0
- package/dist/states/describe-error.d.ts +18 -0
- package/dist/states/describe-error.d.ts.map +1 -0
- package/dist/states/illustrations.d.ts +24 -0
- package/dist/states/illustrations.d.ts.map +1 -0
- package/dist/states/index.d.ts +11 -0
- package/dist/states/index.d.ts.map +1 -0
- package/dist/states/index.js +253 -0
- package/dist/states/index.js.map +13 -0
- package/dist/states/kinds.d.ts +28 -0
- package/dist/states/kinds.d.ts.map +1 -0
- package/dist/vite/csp-dev-header.d.ts +11 -0
- package/dist/vite/csp-dev-header.d.ts.map +1 -0
- package/dist/vite/csp-hashes.d.ts +23 -0
- package/dist/vite/csp-hashes.d.ts.map +1 -0
- package/dist/vite/csp-header.d.ts +10 -0
- package/dist/vite/csp-header.d.ts.map +1 -0
- package/dist/vite/csp-plugin.d.ts +12 -0
- package/dist/vite/csp-plugin.d.ts.map +1 -0
- package/dist/vite/css-chain.d.ts +13 -0
- package/dist/vite/css-chain.d.ts.map +1 -0
- package/dist/vite/dependency-closure.d.ts +8 -0
- package/dist/vite/dependency-closure.d.ts.map +1 -0
- package/dist/vite/fonts-inter.d.ts +15 -0
- package/dist/vite/fonts-inter.d.ts.map +1 -0
- package/dist/vite/fonts-plugin.d.ts +12 -0
- package/dist/vite/fonts-plugin.d.ts.map +1 -0
- package/dist/vite/index.d.ts +17 -81
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +478 -2
- package/dist/vite/index.js.map +18 -4
- package/dist/vite/libraries.d.ts +13 -0
- package/dist/vite/libraries.d.ts.map +1 -0
- package/dist/vite/nxgt-material.d.ts +12 -0
- package/dist/vite/nxgt-material.d.ts.map +1 -0
- package/dist/vite/options.d.ts +56 -0
- package/dist/vite/options.d.ts.map +1 -0
- package/dist/vite/pdf-plugin.d.ts +19 -0
- package/dist/vite/pdf-plugin.d.ts.map +1 -0
- package/dist/vite/pdfkit-standard-fonts.d.ts +74 -0
- package/dist/vite/pdfkit-standard-fonts.d.ts.map +1 -0
- package/dist/vite/styles-plugin.d.ts +27 -0
- package/dist/vite/styles-plugin.d.ts.map +1 -0
- package/dist/vite/styles-scan.d.ts +14 -0
- package/dist/vite/styles-scan.d.ts.map +1 -0
- package/docs/README.md +4 -0
- package/docs/backgrounds.md +95 -0
- package/docs/roadmap.md +34 -23
- package/docs/states.md +85 -0
- package/docs/troubleshooting.md +174 -3
- package/package.json +34 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scatter.d.ts","sourceRoot":"","sources":["../../src/backgrounds/scatter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC5B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,mEAAmE;IACnE,CAAC,EAAE,MAAM,CAAC;CACV;AAED,MAAM,WAAW,cAAc;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACtB,IAAI,EAAE,MAAM,MAAM,EAClB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,EACC,KAAY,EACZ,MAAa,EACb,GAAU,EACV,GAAQ,EACR,MAAW,EACX,QAAa,GACb,GAAE,cAAmB,GACpB,YAAY,EAAE,CAehB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SceneNode, SceneTag } from './types';
|
|
2
|
+
export declare const SCENE_TAGS: readonly SceneTag[];
|
|
3
|
+
/**
|
|
4
|
+
* The attributes a scene may carry: geometry and presentation ones. Never
|
|
5
|
+
* `style` (it would reach the markup as a `style=` attribute, which a strict
|
|
6
|
+
* Content Security Policy blocks), an `on*` handler or an `href`. Colours come
|
|
7
|
+
* from classes, so none of the colour attributes is needed.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SCENE_ATTRIBUTES: readonly string[];
|
|
10
|
+
/**
|
|
11
|
+
* Throws when a scene holds anything but the allowed tags and attributes: a
|
|
12
|
+
* `style`, an `on*` handler, an `href`, a URL in a value, a `url(…)` that is
|
|
13
|
+
* not the local id of an element of the same scene, an id or class with
|
|
14
|
+
* unusual characters, a number that is not finite. With `idPrefix`, every id
|
|
15
|
+
* must start with `<idPrefix>-`. Builders are tested against it, and the
|
|
16
|
+
* libraries may call it in development.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertSafeScene(root: SceneNode, idPrefix?: string): void;
|
|
19
|
+
/** A scene element. */
|
|
20
|
+
export declare function el(tag: SceneTag, attrs?: SceneNode['attrs'], children?: readonly SceneNode[]): SceneNode;
|
|
21
|
+
//# sourceMappingURL=scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../../src/backgrounds/scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnD,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAmBzC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAiE5C,CAAC;AA4DH;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAWxE;AAED,uBAAuB;AACvB,wBAAgB,EAAE,CACjB,GAAG,EAAE,QAAQ,EACb,KAAK,GAAE,SAAS,CAAC,OAAO,CAAM,EAC9B,QAAQ,CAAC,EAAE,SAAS,SAAS,EAAE,GAC7B,SAAS,CAEX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tones.d.ts","sourceRoot":"","sources":["../../src/backgrounds/tones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEnE,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAWrD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,SAAS,mBAAmB,EAIhE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The 20 background presets. The ids are final; each one's look is not. */
|
|
2
|
+
export type BackgroundPreset = 'gradient' | 'mesh' | 'aurora' | 'spotlight' | 'bokeh' | 'grain' | 'isometric' | 'blueprint' | 'dots' | 'stripes' | 'low-poly' | 'topography' | 'waves' | 'shapes' | 'confetti-grid' | 'constellation' | 'halftone' | 'truchet' | 'floating' | 'scatter-icons';
|
|
3
|
+
/**
|
|
4
|
+
* The presets a library draws today: the ids that `BackgroundProps.preset`
|
|
5
|
+
* accepts. Widened by each preset slice; `BackgroundPreset` is the planned table.
|
|
6
|
+
*/
|
|
7
|
+
export type ShippedBackgroundPreset = 'gradient' | 'grain';
|
|
8
|
+
/** Which theme colours a background draws with. */
|
|
9
|
+
export type BackgroundTone = 'primary' | 'secondary' | 'tertiary' | 'neutral' | 'success' | 'warning' | 'error' | 'info' | 'mixed' | 'custom';
|
|
10
|
+
export type BackgroundIntensity = 'subtle' | 'default' | 'vivid';
|
|
11
|
+
/** The primitives a motif preset draws. */
|
|
12
|
+
export type MotifShape = 'circle' | 'ring' | 'square' | 'triangle' | 'plus' | 'line' | 'arc';
|
|
13
|
+
export type MotifDensity = 'low' | 'default' | 'high';
|
|
14
|
+
export type MotifSize = 'small' | 'mixed' | 'large';
|
|
15
|
+
export type ShapeFill = 'filled' | 'outline' | 'mixed';
|
|
16
|
+
export type OpacitySpread = 'uniform' | 'varied';
|
|
17
|
+
/** The controls of the motif presets. */
|
|
18
|
+
export interface MotifOptions {
|
|
19
|
+
shapes?: readonly MotifShape[];
|
|
20
|
+
density?: MotifDensity;
|
|
21
|
+
size?: MotifSize;
|
|
22
|
+
rotate?: boolean;
|
|
23
|
+
shapeFill?: ShapeFill;
|
|
24
|
+
opacitySpread?: OpacitySpread;
|
|
25
|
+
}
|
|
26
|
+
/** The tags a scene may hold: the SVG subset a background needs. */
|
|
27
|
+
export type SceneTag = 'svg' | 'g' | 'path' | 'circle' | 'rect' | 'ellipse' | 'line' | 'polygon' | 'defs' | 'pattern' | 'linearGradient' | 'radialGradient' | 'stop' | 'filter' | 'feTurbulence' | 'feColorMatrix' | 'feGaussianBlur' | 'mask';
|
|
28
|
+
/** One element of a scene: plain data, rendered by each library. */
|
|
29
|
+
export interface SceneNode {
|
|
30
|
+
tag: SceneTag;
|
|
31
|
+
attrs: Readonly<Record<string, string | number>>;
|
|
32
|
+
children?: readonly SceneNode[];
|
|
33
|
+
}
|
|
34
|
+
export interface PresetInfo {
|
|
35
|
+
id: BackgroundPreset;
|
|
36
|
+
family: 'light' | 'geometry' | 'motif';
|
|
37
|
+
/** How it is drawn: CSS alone, an SVG scene, or both. */
|
|
38
|
+
kind: 'css' | 'svg' | 'css+svg';
|
|
39
|
+
/** Whether `seed` changes its geometry. */
|
|
40
|
+
seeded: boolean;
|
|
41
|
+
/** The motif controls it reads. */
|
|
42
|
+
motifControls: readonly (keyof MotifOptions)[];
|
|
43
|
+
}
|
|
44
|
+
/** What a scene builder is given. */
|
|
45
|
+
export interface SceneOptions {
|
|
46
|
+
/** Prefix of every id in the scene, from {@link svgIdPrefix}. */
|
|
47
|
+
idPrefix: string;
|
|
48
|
+
seed?: number;
|
|
49
|
+
motif?: MotifOptions;
|
|
50
|
+
grain?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type SceneBuilder = (opts: SceneOptions) => SceneNode;
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/backgrounds/types.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GACzB,UAAU,GACV,MAAM,GACN,QAAQ,GACR,WAAW,GACX,OAAO,GACP,OAAO,GACP,WAAW,GACX,WAAW,GACX,MAAM,GACN,SAAS,GACT,UAAU,GACV,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,eAAe,GACf,eAAe,GACf,UAAU,GACV,SAAS,GACT,UAAU,GACV,eAAe,CAAC;AAEnB;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,OAAO,CAAC;AAE3D,mDAAmD;AACnD,MAAM,MAAM,cAAc,GACvB,SAAS,GACT,WAAW,GACX,UAAU,GACV,SAAS,GACT,SAAS,GACT,SAAS,GACT,OAAO,GACP,MAAM,GACN,OAAO,GACP,QAAQ,CAAC;AAEZ,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjE,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GACnB,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,UAAU,GACV,MAAM,GACN,MAAM,GACN,KAAK,CAAC;AAET,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AACtD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACpD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AACvD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEjD,yCAAyC;AACzC,MAAM,WAAW,YAAY;IAC5B,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,oEAAoE;AACpE,MAAM,MAAM,QAAQ,GACjB,KAAK,GACL,GAAG,GACH,MAAM,GACN,QAAQ,GACR,MAAM,GACN,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,SAAS,GACT,gBAAgB,GAChB,gBAAgB,GAChB,MAAM,GACN,QAAQ,GACR,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,MAAM,CAAC;AAEV,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,gBAAgB,CAAC;IACrB,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IACvC,yDAAyD;IACzD,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;IAChC,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAC;IAChB,mCAAmC;IACnC,aAAa,EAAE,SAAS,CAAC,MAAM,YAAY,CAAC,EAAE,CAAC;CAC/C;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC5B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,SAAS,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/csp/nonce.ts
|
|
2
|
+
var CSP_NONCE_PLACEHOLDER2 = "NXGT_CSP_NONCE";
|
|
3
|
+
var NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;
|
|
4
|
+
function assertCspNonce(nonce) {
|
|
5
|
+
if (!NONCE.test(nonce)) {
|
|
6
|
+
throw new Error(`Invalid CSP nonce: only A-Z, a-z, 0-9, "+", "/", "_", "=" and "-" are allowed, got ${JSON.stringify(nonce)}.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function assertNotPlaceholder(nonce, placeholder = CSP_NONCE_PLACEHOLDER2) {
|
|
10
|
+
if (nonce === placeholder || nonce === CSP_NONCE_PLACEHOLDER2) {
|
|
11
|
+
throw new Error(`The CSP nonce is the build placeholder "${nonce}", which is public: generate one per request with createCspNonce().`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function createCspNonce2(bytes = 16) {
|
|
15
|
+
if (!Number.isInteger(bytes) || bytes < 16) {
|
|
16
|
+
throw new Error(`A CSP nonce needs at least 16 random bytes (128 bits), got ${bytes}.`);
|
|
17
|
+
}
|
|
18
|
+
const random = globalThis.crypto.getRandomValues(new Uint8Array(bytes));
|
|
19
|
+
let binary = "";
|
|
20
|
+
for (const byte of random)
|
|
21
|
+
binary += String.fromCharCode(byte);
|
|
22
|
+
return btoa(binary);
|
|
23
|
+
}
|
|
24
|
+
function applyCspNonce2(html, nonce, placeholder = CSP_NONCE_PLACEHOLDER2) {
|
|
25
|
+
assertCspNonce(nonce);
|
|
26
|
+
assertNotPlaceholder(nonce, placeholder);
|
|
27
|
+
if (placeholder === "")
|
|
28
|
+
return html;
|
|
29
|
+
if (!html.includes(placeholder)) {
|
|
30
|
+
throw new Error(`applyCspNonce: the HTML holds no "${placeholder}" placeholder, so no nonce was applied. Build with nxgtMaterial({ csp: { mode: 'nonce' } }) and apply it to the full HTML page, or, with a custom csp.placeholder, pass it as the third argument: applyCspNonce(html, nonce, placeholder).`);
|
|
31
|
+
}
|
|
32
|
+
return html.split(placeholder).join(nonce);
|
|
33
|
+
}
|
|
34
|
+
async function cspHash2(source, algo = "sha256") {
|
|
35
|
+
const data = new TextEncoder().encode(source);
|
|
36
|
+
const digest = await globalThis.crypto.subtle.digest(algo === "sha384" ? "SHA-384" : "SHA-256", data);
|
|
37
|
+
let binary = "";
|
|
38
|
+
for (const byte of new Uint8Array(digest))
|
|
39
|
+
binary += String.fromCharCode(byte);
|
|
40
|
+
return `'${algo}-${btoa(binary)}'`;
|
|
41
|
+
}
|
|
42
|
+
// src/csp/policy.ts
|
|
43
|
+
function baseDirectives(nonce, styleHashes) {
|
|
44
|
+
const quoted = nonce ? `'nonce-${nonce}'` : undefined;
|
|
45
|
+
const styles = quoted ?? (styleHashes ? undefined : "'unsafe-inline'");
|
|
46
|
+
return {
|
|
47
|
+
"default-src": ["'self'"],
|
|
48
|
+
"script-src": quoted ? [quoted, "'strict-dynamic'"] : ["'self'"],
|
|
49
|
+
"style-src-elem": styles ? ["'self'", styles] : ["'self'"],
|
|
50
|
+
"style-src-attr": ["'unsafe-inline'"],
|
|
51
|
+
"font-src": ["'self'"],
|
|
52
|
+
"img-src": ["'self'", "data:", "blob:"],
|
|
53
|
+
"worker-src": ["'self'"],
|
|
54
|
+
"connect-src": ["'self'"],
|
|
55
|
+
"object-src": ["'none'"],
|
|
56
|
+
"base-uri": ["'self'"]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var DIRECTIVE_NAME = /^[a-z-]+$/;
|
|
60
|
+
var UNSAFE_SOURCE = /[;,\s\u0000-\u001f\u007f]/;
|
|
61
|
+
var HASH = /^'?sha(256|384|512)-[A-Za-z0-9+/]+={0,2}'?$/;
|
|
62
|
+
function quoteHash(hash) {
|
|
63
|
+
if (!HASH.test(hash)) {
|
|
64
|
+
throw new Error(`Invalid CSP hash ${JSON.stringify(hash)}: expected 'sha256-…', 'sha384-…' or 'sha512-…' (see cspHash).`);
|
|
65
|
+
}
|
|
66
|
+
return hash.startsWith("'") ? hash : `'${hash}'`;
|
|
67
|
+
}
|
|
68
|
+
function merge(directives, extra) {
|
|
69
|
+
for (const [name, sources] of Object.entries(extra)) {
|
|
70
|
+
if (!DIRECTIVE_NAME.test(name)) {
|
|
71
|
+
throw new Error(`Invalid CSP directive name ${JSON.stringify(name)}: only a-z and "-" are allowed.`);
|
|
72
|
+
}
|
|
73
|
+
const bad = sources?.find((source) => UNSAFE_SOURCE.test(source));
|
|
74
|
+
if (bad !== undefined) {
|
|
75
|
+
throw new Error(`Invalid CSP source ${JSON.stringify(bad)} in "${name}": a source holds no ";", ",", whitespace or control character.`);
|
|
76
|
+
}
|
|
77
|
+
if (sources === null || sources.length === 0) {
|
|
78
|
+
delete directives[name];
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const current = directives[name] ?? [];
|
|
82
|
+
directives[name] = [
|
|
83
|
+
...current,
|
|
84
|
+
...sources.filter((s) => !current.includes(s))
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function serialise(directives) {
|
|
89
|
+
return Object.entries(directives).map(([name, sources]) => [name, ...sources].join(" ")).join("; ");
|
|
90
|
+
}
|
|
91
|
+
function cspPolicy2(options = {}) {
|
|
92
|
+
if (options.nonce !== undefined) {
|
|
93
|
+
assertCspNonce(options.nonce);
|
|
94
|
+
assertNotPlaceholder(options.nonce);
|
|
95
|
+
}
|
|
96
|
+
const { script = [], style = [] } = options.hashes ?? {};
|
|
97
|
+
const directives = baseDirectives(options.nonce, style.length > 0);
|
|
98
|
+
if (script.length)
|
|
99
|
+
merge(directives, { "script-src": script.map(quoteHash) });
|
|
100
|
+
if (style.length)
|
|
101
|
+
merge(directives, { "style-src-elem": style.map(quoteHash) });
|
|
102
|
+
if (options.dev)
|
|
103
|
+
merge(directives, { "connect-src": ["ws:", "wss:"] });
|
|
104
|
+
if (options.directives)
|
|
105
|
+
merge(directives, options.directives);
|
|
106
|
+
return { directives, header: serialise(directives) };
|
|
107
|
+
}
|
|
108
|
+
// src/csp/zod-jitless.ts
|
|
109
|
+
var ZOD_JITLESS_SCRIPT2 = "(globalThis.__zod_globalConfig??={}).jitless=true;";
|
|
110
|
+
function zodJitlessTag2(nonce) {
|
|
111
|
+
if (nonce === undefined)
|
|
112
|
+
return `<script>${ZOD_JITLESS_SCRIPT2}</script>`;
|
|
113
|
+
assertCspNonce(nonce);
|
|
114
|
+
return `<script nonce="${nonce}">${ZOD_JITLESS_SCRIPT2}</script>`;
|
|
115
|
+
}
|
|
116
|
+
export { CSP_NONCE_PLACEHOLDER2, assertCspNonce, createCspNonce2, applyCspNonce2, cspHash2, cspPolicy2, ZOD_JITLESS_SCRIPT2, zodJitlessTag2 };
|
|
117
|
+
|
|
118
|
+
//# debugId=7B5071576EED302064756E2164756E21
|
|
119
|
+
//# sourceMappingURL=index-mw5fa8qa.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/csp/nonce.ts", "../src/csp/policy.ts", "../src/csp/zod-jitless.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * The per-request nonce of a Content Security Policy, for the server and the\n * build. Unlike `../lib/csp-nonce.ts` (which reads the page in a browser),\n * nothing here keeps state or touches the DOM: only `globalThis.crypto`,\n * `btoa` and string operations, so it runs on Node, Bun, Deno, workers and\n * browsers.\n */\n\n/**\n * What a build writes where the nonce goes, for the server to replace per\n * request (`applyCspNonce`). Its characters are valid inside `'nonce-…'`.\n */\nexport const CSP_NONCE_PLACEHOLDER = 'NXGT_CSP_NONCE';\n\n/** Base64 and base64url: what a nonce may be made of. */\nconst NONCE = /^[A-Za-z0-9+/_-]+={0,2}$/;\n\n/** Throws unless `nonce` is safe in a header and an attribute. */\nexport function assertCspNonce(nonce: string): void {\n\tif (!NONCE.test(nonce)) {\n\t\tthrow new Error(\n\t\t\t`Invalid CSP nonce: only A-Z, a-z, 0-9, \"+\", \"/\", \"_\", \"=\" and \"-\" are allowed, got ${JSON.stringify(nonce)}.`,\n\t\t);\n\t}\n}\n\n/** The placeholder is public: serving it as a nonce voids the policy. */\nexport function assertNotPlaceholder(\n\tnonce: string,\n\tplaceholder: string = CSP_NONCE_PLACEHOLDER,\n): void {\n\tif (nonce === placeholder || nonce === CSP_NONCE_PLACEHOLDER) {\n\t\tthrow new Error(\n\t\t\t`The CSP nonce is the build placeholder \"${nonce}\", which is public: generate one per request with createCspNonce().`,\n\t\t);\n\t}\n}\n\n/**\n * A fresh random nonce (base64, `bytes` random bytes, 16 by default). A CSP\n * nonce needs at least 128 bits, so fewer than 16 bytes throws.\n */\nexport function createCspNonce(bytes = 16): string {\n\tif (!Number.isInteger(bytes) || bytes < 16) {\n\t\tthrow new Error(\n\t\t\t`A CSP nonce needs at least 16 random bytes (128 bits), got ${bytes}.`,\n\t\t);\n\t}\n\tconst random = globalThis.crypto.getRandomValues(new Uint8Array(bytes));\n\tlet binary = '';\n\tfor (const byte of random) binary += String.fromCharCode(byte);\n\treturn btoa(binary);\n}\n\n/**\n * Replaces every `placeholder` in `html` with `nonce`. Throws when the nonce\n * holds a character outside the base64 alphabet (`\"`, `<`, a space…): it would\n * break out of the attribute it lands in; and when `html` holds no\n * placeholder (a hash-mode build, or a custom `csp.placeholder` not passed as\n * the third argument): the page's scripts would carry no nonce and be blocked.\n */\nexport function applyCspNonce(\n\thtml: string,\n\tnonce: string,\n\tplaceholder: string = CSP_NONCE_PLACEHOLDER,\n): string {\n\tassertCspNonce(nonce);\n\tassertNotPlaceholder(nonce, placeholder);\n\tif (placeholder === '') return html;\n\tif (!html.includes(placeholder)) {\n\t\tthrow new Error(\n\t\t\t`applyCspNonce: the HTML holds no \"${placeholder}\" placeholder, so no nonce was applied. Build with nxgtMaterial({ csp: { mode: 'nonce' } }) and apply it to the full HTML page, or, with a custom csp.placeholder, pass it as the third argument: applyCspNonce(html, nonce, placeholder).`,\n\t\t);\n\t}\n\treturn html.split(placeholder).join(nonce);\n}\n\n/**\n * The CSP source of an inline script or style: `'sha256-…'` (quotes included,\n * ready for `script-src` / `style-src`), over the exact text between the tags.\n */\nexport async function cspHash(\n\tsource: string,\n\talgo: 'sha256' | 'sha384' = 'sha256',\n): Promise<string> {\n\tconst data = new TextEncoder().encode(source);\n\tconst digest = await globalThis.crypto.subtle.digest(\n\t\talgo === 'sha384' ? 'SHA-384' : 'SHA-256',\n\t\tdata,\n\t);\n\tlet binary = '';\n\tfor (const byte of new Uint8Array(digest))\n\t\tbinary += String.fromCharCode(byte);\n\treturn `'${algo}-${btoa(binary)}'`;\n}\n",
|
|
6
|
+
"/**\n * The Content Security Policy the libraries run under (the one in the CSP\n * guide), as data and as a header value. Pure strings: server and build safe.\n */\nimport { assertCspNonce, assertNotPlaceholder } from './nonce';\n\n/** Directive name to its sources. */\nexport type CspDirectives = Record<string, string[]>;\n\nexport type CspPolicyOptions = {\n\t/**\n\t * This request's nonce. Absent: no `'nonce-…'` and no `'strict-dynamic'`\n\t * (scripts fall back to `'self'` and their hashes; style elements to\n\t * `'self' 'unsafe-inline'`, unless `hashes.style` is given).\n\t */\n\tnonce?: string;\n\t/** Adds `ws:` and `wss:` to `connect-src` (the dev server's HMR socket). */\n\tdev?: boolean;\n\t/**\n\t * Hashes of inline scripts and styles (`cspHash`), appended to `script-src`\n\t * and `style-src-elem`. Quotes are added when missing. A style hash\n\t * replaces the no-nonce `'unsafe-inline'` (a browser ignores it next to a\n\t * hash), so every `<style>` created at runtime is then blocked.\n\t */\n\thashes?: { script?: string[]; style?: string[] };\n\t/**\n\t * Merged per directive: the sources are appended to the default ones. A\n\t * directive set to `null` or `[]` is dropped.\n\t */\n\tdirectives?: Record<string, string[] | null>;\n};\n\n/**\n * Without a nonce, style elements take `'unsafe-inline'`: the components\n * create `<style>` elements at runtime, which no build can hash. Scripts stay\n * strict. Style hashes, when given, take its place (it is void beside them).\n */\nfunction baseDirectives(\n\tnonce: string | undefined,\n\tstyleHashes: boolean,\n): CspDirectives {\n\tconst quoted = nonce ? `'nonce-${nonce}'` : undefined;\n\tconst styles = quoted ?? (styleHashes ? undefined : \"'unsafe-inline'\");\n\treturn {\n\t\t'default-src': [\"'self'\"],\n\t\t'script-src': quoted ? [quoted, \"'strict-dynamic'\"] : [\"'self'\"],\n\t\t'style-src-elem': styles ? [\"'self'\", styles] : [\"'self'\"],\n\t\t'style-src-attr': [\"'unsafe-inline'\"],\n\t\t'font-src': [\"'self'\"],\n\t\t'img-src': [\"'self'\", 'data:', 'blob:'],\n\t\t'worker-src': [\"'self'\"],\n\t\t'connect-src': [\"'self'\"],\n\t\t'object-src': [\"'none'\"],\n\t\t'base-uri': [\"'self'\"],\n\t};\n}\n\nconst DIRECTIVE_NAME = /^[a-z-]+$/;\n// biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting them is the point\nconst UNSAFE_SOURCE = /[;,\\s\\u0000-\\u001f\\u007f]/;\nconst HASH = /^'?sha(256|384|512)-[A-Za-z0-9+/]+={0,2}'?$/;\n\n/** A hash source with its quotes; throws on anything that is not a hash. */\nfunction quoteHash(hash: string): string {\n\tif (!HASH.test(hash)) {\n\t\tthrow new Error(\n\t\t\t`Invalid CSP hash ${JSON.stringify(hash)}: expected 'sha256-…', 'sha384-…' or 'sha512-…' (see cspHash).`,\n\t\t);\n\t}\n\treturn hash.startsWith(\"'\") ? hash : `'${hash}'`;\n}\n\nfunction merge(\n\tdirectives: CspDirectives,\n\textra: Record<string, string[] | null>,\n): void {\n\tfor (const [name, sources] of Object.entries(extra)) {\n\t\tif (!DIRECTIVE_NAME.test(name)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid CSP directive name ${JSON.stringify(name)}: only a-z and \"-\" are allowed.`,\n\t\t\t);\n\t\t}\n\t\tconst bad = sources?.find((source) => UNSAFE_SOURCE.test(source));\n\t\tif (bad !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid CSP source ${JSON.stringify(bad)} in \"${name}\": a source holds no \";\", \",\", whitespace or control character.`,\n\t\t\t);\n\t\t}\n\t\tif (sources === null || sources.length === 0) {\n\t\t\tdelete directives[name];\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = directives[name] ?? [];\n\t\tdirectives[name] = [\n\t\t\t...current,\n\t\t\t...sources.filter((s) => !current.includes(s)),\n\t\t];\n\t}\n}\n\n/** `name source source`, joined by `; ` in the directives' order. */\nfunction serialise(directives: CspDirectives): string {\n\treturn Object.entries(directives)\n\t\t.map(([name, sources]) => [name, ...sources].join(' '))\n\t\t.join('; ');\n}\n\n/** The policy and its header value (`Content-Security-Policy: <header>`). */\nexport function cspPolicy(options: CspPolicyOptions = {}): {\n\tdirectives: CspDirectives;\n\theader: string;\n} {\n\tif (options.nonce !== undefined) {\n\t\tassertCspNonce(options.nonce);\n\t\tassertNotPlaceholder(options.nonce);\n\t}\n\tconst { script = [], style = [] } = options.hashes ?? {};\n\tconst directives = baseDirectives(options.nonce, style.length > 0);\n\tif (script.length) merge(directives, { 'script-src': script.map(quoteHash) });\n\tif (style.length)\n\t\tmerge(directives, { 'style-src-elem': style.map(quoteHash) });\n\tif (options.dev) merge(directives, { 'connect-src': ['ws:', 'wss:'] });\n\tif (options.directives) merge(directives, options.directives);\n\treturn { directives, header: serialise(directives) };\n}\n",
|
|
7
|
+
"/**\n * zod's `jitless` mode, set before any schema is built, for a page whose CSP\n * has no `'unsafe-eval'`: zod 4.4 and later keep their configuration on\n * `globalThis.__zod_globalConfig`, and skip the `new Function` probe when\n * `jitless` is set. An inline script cannot `import 'zod'`, so it writes the\n * global itself. Pinned by a contract test in each library\n * (`zod-jitless-script.test.ts`) against the zod it runs on.\n */\nimport { assertCspNonce } from './nonce';\n\nexport const ZOD_JITLESS_SCRIPT =\n\t'(globalThis.__zod_globalConfig??={}).jitless=true;';\n\n/** `<script nonce=\"…\">…</script>`; no `nonce` attribute without a nonce. */\nexport function zodJitlessTag(nonce?: string): string {\n\tif (nonce === undefined) return `<script>${ZOD_JITLESS_SCRIPT}</script>`;\n\tassertCspNonce(nonce);\n\treturn `<script nonce=\"${nonce}\">${ZOD_JITLESS_SCRIPT}</script>`;\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "7B5071576EED302064756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Content Security Policy helpers for the server and the build: a fresh
|
|
3
|
+
* nonce per request, the policy header, the nonce placeholder a build leaves
|
|
4
|
+
* for the server to fill, and zod's jitless switch. Nothing reads a DOM; the
|
|
5
|
+
* browser's side (reading the page's nonce) is `../lib/csp-nonce.ts`.
|
|
6
|
+
*/
|
|
7
|
+
export { applyCspNonce, CSP_NONCE_PLACEHOLDER, createCspNonce, cspHash, } from './nonce';
|
|
8
|
+
export { type CspDirectives, type CspPolicyOptions, cspPolicy, } from './policy';
|
|
9
|
+
export { ZOD_JITLESS_SCRIPT, zodJitlessTag } from './zod-jitless';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/csp/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,OAAO,GACP,MAAM,SAAS,CAAC;AACjB,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,SAAS,GACT,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CSP_NONCE_PLACEHOLDER2,
|
|
3
|
+
createCspNonce2,
|
|
4
|
+
applyCspNonce2,
|
|
5
|
+
cspHash2,
|
|
6
|
+
cspPolicy2,
|
|
7
|
+
ZOD_JITLESS_SCRIPT2,
|
|
8
|
+
zodJitlessTag2
|
|
9
|
+
} from "../chunks/index-mw5fa8qa.js";
|
|
10
|
+
export {
|
|
11
|
+
CSP_NONCE_PLACEHOLDER2 as CSP_NONCE_PLACEHOLDER,
|
|
12
|
+
ZOD_JITLESS_SCRIPT2 as ZOD_JITLESS_SCRIPT,
|
|
13
|
+
applyCspNonce2 as applyCspNonce,
|
|
14
|
+
createCspNonce2 as createCspNonce,
|
|
15
|
+
cspHash2 as cspHash,
|
|
16
|
+
cspPolicy2 as cspPolicy,
|
|
17
|
+
zodJitlessTag2 as zodJitlessTag
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//# debugId=5AE55BFB6130247D64756E2164756E21
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-request nonce of a Content Security Policy, for the server and the
|
|
3
|
+
* build. Unlike `../lib/csp-nonce.ts` (which reads the page in a browser),
|
|
4
|
+
* nothing here keeps state or touches the DOM: only `globalThis.crypto`,
|
|
5
|
+
* `btoa` and string operations, so it runs on Node, Bun, Deno, workers and
|
|
6
|
+
* browsers.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* What a build writes where the nonce goes, for the server to replace per
|
|
10
|
+
* request (`applyCspNonce`). Its characters are valid inside `'nonce-…'`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const CSP_NONCE_PLACEHOLDER = "NXGT_CSP_NONCE";
|
|
13
|
+
/** Throws unless `nonce` is safe in a header and an attribute. */
|
|
14
|
+
export declare function assertCspNonce(nonce: string): void;
|
|
15
|
+
/** The placeholder is public: serving it as a nonce voids the policy. */
|
|
16
|
+
export declare function assertNotPlaceholder(nonce: string, placeholder?: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* A fresh random nonce (base64, `bytes` random bytes, 16 by default). A CSP
|
|
19
|
+
* nonce needs at least 128 bits, so fewer than 16 bytes throws.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createCspNonce(bytes?: number): string;
|
|
22
|
+
/**
|
|
23
|
+
* Replaces every `placeholder` in `html` with `nonce`. Throws when the nonce
|
|
24
|
+
* holds a character outside the base64 alphabet (`"`, `<`, a space…): it would
|
|
25
|
+
* break out of the attribute it lands in; and when `html` holds no
|
|
26
|
+
* placeholder (a hash-mode build, or a custom `csp.placeholder` not passed as
|
|
27
|
+
* the third argument): the page's scripts would carry no nonce and be blocked.
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyCspNonce(html: string, nonce: string, placeholder?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* The CSP source of an inline script or style: `'sha256-…'` (quotes included,
|
|
32
|
+
* ready for `script-src` / `style-src`), over the exact text between the tags.
|
|
33
|
+
*/
|
|
34
|
+
export declare function cspHash(source: string, algo?: 'sha256' | 'sha384'): Promise<string>;
|
|
35
|
+
//# sourceMappingURL=nonce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nonce.d.ts","sourceRoot":"","sources":["../../src/csp/nonce.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAKtD,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAMlD;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,MAAM,EACb,WAAW,GAAE,MAA8B,GACzC,IAAI,CAMN;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAK,GAAG,MAAM,CAUjD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,GAAE,MAA8B,GACzC,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,QAAQ,GAAG,QAAmB,GAClC,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Directive name to its sources. */
|
|
2
|
+
export type CspDirectives = Record<string, string[]>;
|
|
3
|
+
export type CspPolicyOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* This request's nonce. Absent: no `'nonce-…'` and no `'strict-dynamic'`
|
|
6
|
+
* (scripts fall back to `'self'` and their hashes; style elements to
|
|
7
|
+
* `'self' 'unsafe-inline'`, unless `hashes.style` is given).
|
|
8
|
+
*/
|
|
9
|
+
nonce?: string;
|
|
10
|
+
/** Adds `ws:` and `wss:` to `connect-src` (the dev server's HMR socket). */
|
|
11
|
+
dev?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Hashes of inline scripts and styles (`cspHash`), appended to `script-src`
|
|
14
|
+
* and `style-src-elem`. Quotes are added when missing. A style hash
|
|
15
|
+
* replaces the no-nonce `'unsafe-inline'` (a browser ignores it next to a
|
|
16
|
+
* hash), so every `<style>` created at runtime is then blocked.
|
|
17
|
+
*/
|
|
18
|
+
hashes?: {
|
|
19
|
+
script?: string[];
|
|
20
|
+
style?: string[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Merged per directive: the sources are appended to the default ones. A
|
|
24
|
+
* directive set to `null` or `[]` is dropped.
|
|
25
|
+
*/
|
|
26
|
+
directives?: Record<string, string[] | null>;
|
|
27
|
+
};
|
|
28
|
+
/** The policy and its header value (`Content-Security-Policy: <header>`). */
|
|
29
|
+
export declare function cspPolicy(options?: CspPolicyOptions): {
|
|
30
|
+
directives: CspDirectives;
|
|
31
|
+
header: string;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/csp/policy.ts"],"names":[],"mappings":"AAMA,qCAAqC;AACrC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAErD,MAAM,MAAM,gBAAgB,GAAG;IAC9B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;CAC7C,CAAC;AA6EF,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG;IAC1D,UAAU,EAAE,aAAa,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CACf,CAaA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const ZOD_JITLESS_SCRIPT = "(globalThis.__zod_globalConfig??={}).jitless=true;";
|
|
2
|
+
/** `<script nonce="…">…</script>`; no `nonce` attribute without a nonce. */
|
|
3
|
+
export declare function zodJitlessTag(nonce?: string): string;
|
|
4
|
+
//# sourceMappingURL=zod-jitless.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-jitless.d.ts","sourceRoot":"","sources":["../../src/csp/zod-jitless.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,kBAAkB,uDACsB,CAAC;AAEtD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpD"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inside a Drawer, the room in px between `top` (where the list starts) and
|
|
3
|
+
* the Drawer's footer, or its bottom edge without one: the height a floating
|
|
4
|
+
* list may take without covering the footer or the controls. `null` when
|
|
5
|
+
* `element` is not in a Drawer: the list keeps its own height.
|
|
6
|
+
*/
|
|
7
|
+
export declare function drawerRoom(element: Element | null | undefined, top: number): number | null;
|
|
8
|
+
//# sourceMappingURL=drawer-room.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawer-room.d.ts","sourceRoot":"","sources":["../../src/lib/drawer-room.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,EACnC,GAAG,EAAE,MAAM,GACT,MAAM,GAAG,IAAI,CAUf"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/lib/drawer-room.ts
|
|
2
|
+
var LEAST_ROOM = 80;
|
|
3
|
+
var GAP = 8;
|
|
4
|
+
function drawerRoom(element, top) {
|
|
5
|
+
const drawer = element?.closest('[data-slot="drawer-content"]');
|
|
6
|
+
if (!drawer)
|
|
7
|
+
return null;
|
|
8
|
+
const footer = drawer.querySelector('[data-slot="drawer-footer"]');
|
|
9
|
+
const limit = Math.min(footer?.getBoundingClientRect().top ?? Number.POSITIVE_INFINITY, drawer.getBoundingClientRect().bottom, window.innerHeight);
|
|
10
|
+
return Math.max(Math.floor(limit - top - GAP), LEAST_ROOM);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
drawerRoom
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//# debugId=B705D898EAE4D48464756E2164756E21
|
|
17
|
+
//# sourceMappingURL=drawer-room.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/drawer-room.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/** The least height a capped list keeps, so it stays usable. */\nconst LEAST_ROOM = 80;\n/** The gap left between the list and the footer. */\nconst GAP = 8;\n\n/**\n * Inside a Drawer, the room in px between `top` (where the list starts) and\n * the Drawer's footer, or its bottom edge without one: the height a floating\n * list may take without covering the footer or the controls. `null` when\n * `element` is not in a Drawer: the list keeps its own height.\n */\nexport function drawerRoom(\n\telement: Element | null | undefined,\n\ttop: number,\n): number | null {\n\tconst drawer = element?.closest('[data-slot=\"drawer-content\"]');\n\tif (!drawer) return null;\n\tconst footer = drawer.querySelector('[data-slot=\"drawer-footer\"]');\n\tconst limit = Math.min(\n\t\tfooter?.getBoundingClientRect().top ?? Number.POSITIVE_INFINITY,\n\t\tdrawer.getBoundingClientRect().bottom,\n\t\twindow.innerHeight,\n\t);\n\treturn Math.max(Math.floor(limit - top - GAP), LEAST_ROOM);\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AACA,IAAM,aAAa;AAEnB,IAAM,MAAM;AAQL,SAAS,UAAU,CACzB,SACA,KACgB;AAAA,EAChB,MAAM,SAAS,SAAS,QAAQ,8BAA8B;AAAA,EAC9D,IAAI,CAAC;AAAA,IAAQ,OAAO;AAAA,EACpB,MAAM,SAAS,OAAO,cAAc,6BAA6B;AAAA,EACjE,MAAM,QAAQ,KAAK,IAClB,QAAQ,sBAAsB,EAAE,OAAO,OAAO,mBAC9C,OAAO,sBAAsB,EAAE,QAC/B,OAAO,WACR;AAAA,EACA,OAAO,KAAK,IAAI,KAAK,MAAM,QAAQ,MAAM,GAAG,GAAG,UAAU;AAAA;",
|
|
8
|
+
"debugId": "B705D898EAE4D48464756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -17,4 +17,18 @@
|
|
|
17
17
|
* it did.
|
|
18
18
|
*/
|
|
19
19
|
export declare function forwardEscape(content: HTMLElement | null | undefined, event: KeyboardEvent): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Escape pressed in a field whose list is open: the list's, not the layer's.
|
|
22
|
+
* A Base UI combobox closes its list from a handler of its own on the input,
|
|
23
|
+
* but a Radix / reka overlay listens for Escape on the document first and
|
|
24
|
+
* closes itself. Called from the content's `onEscapeKeyDown` (before the
|
|
25
|
+
* caller's own handler, which then sees the default prevented), it prevents
|
|
26
|
+
* the default (the overlay stays open) and returns whether it did; the list
|
|
27
|
+
* still closes on the input's own handler.
|
|
28
|
+
*
|
|
29
|
+
* The target is read from the event's composed path, and tested by
|
|
30
|
+
* `nodeType` rather than `instanceof Element`, so a field in an iframe or a
|
|
31
|
+
* shadow root counts too.
|
|
32
|
+
*/
|
|
33
|
+
export declare function keepListEscape(event: KeyboardEvent): boolean;
|
|
20
34
|
//# sourceMappingURL=escape-forward.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"escape-forward.d.ts","sourceRoot":"","sources":["../../src/lib/escape-forward.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA4BH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACvC,KAAK,EAAE,aAAa,GAClB,OAAO,CA6BT"}
|
|
1
|
+
{"version":3,"file":"escape-forward.d.ts","sourceRoot":"","sources":["../../src/lib/escape-forward.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA4BH,wBAAgB,aAAa,CAC5B,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,EACvC,KAAK,EAAE,aAAa,GAClB,OAAO,CA6BT;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAW5D"}
|
|
@@ -42,9 +42,29 @@ function forwardEscape(content, event) {
|
|
|
42
42
|
view.requestAnimationFrame(tick);
|
|
43
43
|
return true;
|
|
44
44
|
}
|
|
45
|
+
var POPUP = '[data-slot="combobox-content"]';
|
|
46
|
+
function hasOpenList(target) {
|
|
47
|
+
if (target.getAttribute("data-list-open") === "true")
|
|
48
|
+
return true;
|
|
49
|
+
if (target.getAttribute("role") !== "combobox" || target.getAttribute("aria-expanded") !== "true") {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const id = target.getAttribute("aria-controls");
|
|
53
|
+
const list = id ? target.ownerDocument.getElementById(id) : null;
|
|
54
|
+
return !!list?.closest(POPUP);
|
|
55
|
+
}
|
|
56
|
+
function keepListEscape(event) {
|
|
57
|
+
const target = event.composedPath?.()[0] ?? event.target;
|
|
58
|
+
if (event.defaultPrevented || target?.nodeType !== 1 || !hasOpenList(target)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
45
64
|
export {
|
|
46
|
-
forwardEscape
|
|
65
|
+
forwardEscape,
|
|
66
|
+
keepListEscape
|
|
47
67
|
};
|
|
48
68
|
|
|
49
|
-
//# debugId=
|
|
69
|
+
//# debugId=F5ACF4B859D649DF64756E2164756E21
|
|
50
70
|
//# sourceMappingURL=escape-forward.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/lib/escape-forward.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Escape pressed while an overlay is closing, handed on to the overlay below.\n *\n * Radix's and reka's `DismissableLayer` give Escape to the highest layer of\n * their stack only, and a dialog's layer leaves that stack when its content\n * unmounts — not when it closes. A content still on the page for its exit\n * animation therefore takes every Escape pressed meanwhile and does nothing\n * with it (it is already closed): the Sheet under a just-closed AlertDialog\n * stays open, and the user has to press Escape again.\n *\n * Called from the content's `onEscapeKeyDown` (after the caller's own\n * handler), `forwardEscape` does nothing unless `content` is closing\n * (`data-state=\"closed\"`) and the default was not prevented. Then it\n * prevents the default (so the closing layer does nothing either) and\n * presses Escape again — a new `keydown` on what has focus — once `content`\n * has left the page and the layer below listens again. It returns whether\n * it did.\n */\n\n// A content that never leaves (a `forceMount`) stops being waited on: about\n// two seconds at 60 frames per second.\nconst MAX_FRAMES = 120;\n\n// The window of the content's document: its frames, and its `KeyboardEvent`\n// (an iframe's, when the content is in one).\ntype Frames = Pick<Window, 'requestAnimationFrame'> & {\n\tKeyboardEvent: typeof KeyboardEvent;\n};\n\nfunction keyInit(event: KeyboardEvent): KeyboardEventInit {\n\treturn {\n\t\tkey: event.key,\n\t\tcode: event.code,\n\t\tlocation: event.location,\n\t\trepeat: event.repeat,\n\t\taltKey: event.altKey,\n\t\tctrlKey: event.ctrlKey,\n\t\tmetaKey: event.metaKey,\n\t\tshiftKey: event.shiftKey,\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tcomposed: true,\n\t};\n}\n\nexport function forwardEscape(\n\tcontent: HTMLElement | null | undefined,\n\tevent: KeyboardEvent,\n): boolean {\n\tif (event.defaultPrevented || content?.dataset.state !== 'closed') {\n\t\treturn false;\n\t}\n\tconst document = content.ownerDocument;\n\tconst view = document.defaultView as Frames | null;\n\tif (!view) return false;\n\tevent.preventDefault();\n\tconst init = keyInit(event);\n\tlet frames = 0;\n\tconst tick = () => {\n\t\t// Reopened meanwhile: it is a live layer again, and Escape is its own.\n\t\tif (content.dataset.state !== 'closed') return;\n\t\tif (content.isConnected) {\n\t\t\tif (++frames < MAX_FRAMES) view.requestAnimationFrame(tick);\n\t\t\treturn;\n\t\t}\n\t\t// The layer leaves the stack in an unmount cleanup; with Radix, the\n\t\t// layer below then re-renders and listens again in an effect of its\n\t\t// own. Two frames cover both.\n\t\tview.requestAnimationFrame(() =>\n\t\t\tview.requestAnimationFrame(() => {\n\t\t\t\tconst target = document.activeElement ?? document.body;\n\t\t\t\ttarget.dispatchEvent(new view.KeyboardEvent('keydown', init));\n\t\t\t}),\n\t\t);\n\t};\n\tview.requestAnimationFrame(tick);\n\treturn true;\n}\n"
|
|
5
|
+
"/**\n * Escape pressed while an overlay is closing, handed on to the overlay below.\n *\n * Radix's and reka's `DismissableLayer` give Escape to the highest layer of\n * their stack only, and a dialog's layer leaves that stack when its content\n * unmounts — not when it closes. A content still on the page for its exit\n * animation therefore takes every Escape pressed meanwhile and does nothing\n * with it (it is already closed): the Sheet under a just-closed AlertDialog\n * stays open, and the user has to press Escape again.\n *\n * Called from the content's `onEscapeKeyDown` (after the caller's own\n * handler), `forwardEscape` does nothing unless `content` is closing\n * (`data-state=\"closed\"`) and the default was not prevented. Then it\n * prevents the default (so the closing layer does nothing either) and\n * presses Escape again — a new `keydown` on what has focus — once `content`\n * has left the page and the layer below listens again. It returns whether\n * it did.\n */\n\n// A content that never leaves (a `forceMount`) stops being waited on: about\n// two seconds at 60 frames per second.\nconst MAX_FRAMES = 120;\n\n// The window of the content's document: its frames, and its `KeyboardEvent`\n// (an iframe's, when the content is in one).\ntype Frames = Pick<Window, 'requestAnimationFrame'> & {\n\tKeyboardEvent: typeof KeyboardEvent;\n};\n\nfunction keyInit(event: KeyboardEvent): KeyboardEventInit {\n\treturn {\n\t\tkey: event.key,\n\t\tcode: event.code,\n\t\tlocation: event.location,\n\t\trepeat: event.repeat,\n\t\taltKey: event.altKey,\n\t\tctrlKey: event.ctrlKey,\n\t\tmetaKey: event.metaKey,\n\t\tshiftKey: event.shiftKey,\n\t\tbubbles: true,\n\t\tcancelable: true,\n\t\tcomposed: true,\n\t};\n}\n\nexport function forwardEscape(\n\tcontent: HTMLElement | null | undefined,\n\tevent: KeyboardEvent,\n): boolean {\n\tif (event.defaultPrevented || content?.dataset.state !== 'closed') {\n\t\treturn false;\n\t}\n\tconst document = content.ownerDocument;\n\tconst view = document.defaultView as Frames | null;\n\tif (!view) return false;\n\tevent.preventDefault();\n\tconst init = keyInit(event);\n\tlet frames = 0;\n\tconst tick = () => {\n\t\t// Reopened meanwhile: it is a live layer again, and Escape is its own.\n\t\tif (content.dataset.state !== 'closed') return;\n\t\tif (content.isConnected) {\n\t\t\tif (++frames < MAX_FRAMES) view.requestAnimationFrame(tick);\n\t\t\treturn;\n\t\t}\n\t\t// The layer leaves the stack in an unmount cleanup; with Radix, the\n\t\t// layer below then re-renders and listens again in an effect of its\n\t\t// own. Two frames cover both.\n\t\tview.requestAnimationFrame(() =>\n\t\t\tview.requestAnimationFrame(() => {\n\t\t\t\tconst target = document.activeElement ?? document.body;\n\t\t\t\ttarget.dispatchEvent(new view.KeyboardEvent('keydown', init));\n\t\t\t}),\n\t\t);\n\t};\n\tview.requestAnimationFrame(tick);\n\treturn true;\n}\n\nconst POPUP = '[data-slot=\"combobox-content\"]';\n\n/**\n * Whether `target` is a field whose popup list is open: a Base UI combobox\n * (`aria-expanded` and an `aria-controls` list inside a `combobox-content`\n * popup, which a `cmdk` command palette's input is not), or a Vue\n * Autocomplete's textbox (`data-list-open`).\n */\nfunction hasOpenList(target: Element): boolean {\n\tif (target.getAttribute('data-list-open') === 'true') return true;\n\tif (\n\t\ttarget.getAttribute('role') !== 'combobox' ||\n\t\ttarget.getAttribute('aria-expanded') !== 'true'\n\t) {\n\t\treturn false;\n\t}\n\tconst id = target.getAttribute('aria-controls');\n\tconst list = id ? target.ownerDocument.getElementById(id) : null;\n\treturn !!list?.closest(POPUP);\n}\n\n/**\n * Escape pressed in a field whose list is open: the list's, not the layer's.\n * A Base UI combobox closes its list from a handler of its own on the input,\n * but a Radix / reka overlay listens for Escape on the document first and\n * closes itself. Called from the content's `onEscapeKeyDown` (before the\n * caller's own handler, which then sees the default prevented), it prevents\n * the default (the overlay stays open) and returns whether it did; the list\n * still closes on the input's own handler.\n *\n * The target is read from the event's composed path, and tested by\n * `nodeType` rather than `instanceof Element`, so a field in an iframe or a\n * shadow root counts too.\n */\nexport function keepListEscape(event: KeyboardEvent): boolean {\n\tconst target = event.composedPath?.()[0] ?? event.target;\n\tif (\n\t\tevent.defaultPrevented ||\n\t\t(target as Node | null)?.nodeType !== 1 ||\n\t\t!hasOpenList(target as Element)\n\t) {\n\t\treturn false;\n\t}\n\tevent.preventDefault();\n\treturn true;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";AAqBA,IAAM,aAAa;AAQnB,SAAS,OAAO,CAAC,OAAyC;AAAA,EACzD,OAAO;AAAA,IACN,KAAK,MAAM;AAAA,IACX,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM;AAAA,IAChB,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM;AAAA,IACd,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,IAChB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,EACX;AAAA;AAGM,SAAS,aAAa,CAC5B,SACA,OACU;AAAA,EACV,IAAI,MAAM,oBAAoB,SAAS,QAAQ,UAAU,UAAU;AAAA,IAClE,OAAO;AAAA,EACR;AAAA,EACA,MAAM,WAAW,QAAQ;AAAA,EACzB,MAAM,OAAO,SAAS;AAAA,EACtB,IAAI,CAAC;AAAA,IAAM,OAAO;AAAA,EAClB,MAAM,eAAe;AAAA,EACrB,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC1B,IAAI,SAAS;AAAA,EACb,MAAM,OAAO,MAAM;AAAA,IAElB,IAAI,QAAQ,QAAQ,UAAU;AAAA,MAAU;AAAA,IACxC,IAAI,QAAQ,aAAa;AAAA,MACxB,IAAI,EAAE,SAAS;AAAA,QAAY,KAAK,sBAAsB,IAAI;AAAA,MAC1D;AAAA,IACD;AAAA,IAIA,KAAK,sBAAsB,MAC1B,KAAK,sBAAsB,MAAM;AAAA,MAChC,MAAM,SAAS,SAAS,iBAAiB,SAAS;AAAA,MAClD,OAAO,cAAc,IAAI,KAAK,cAAc,WAAW,IAAI,CAAC;AAAA,KAC5D,CACF;AAAA;AAAA,EAED,KAAK,sBAAsB,IAAI;AAAA,EAC/B,OAAO;AAAA;",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";AAqBA,IAAM,aAAa;AAQnB,SAAS,OAAO,CAAC,OAAyC;AAAA,EACzD,OAAO;AAAA,IACN,KAAK,MAAM;AAAA,IACX,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM;AAAA,IAChB,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM;AAAA,IACd,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA,IACf,UAAU,MAAM;AAAA,IAChB,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,EACX;AAAA;AAGM,SAAS,aAAa,CAC5B,SACA,OACU;AAAA,EACV,IAAI,MAAM,oBAAoB,SAAS,QAAQ,UAAU,UAAU;AAAA,IAClE,OAAO;AAAA,EACR;AAAA,EACA,MAAM,WAAW,QAAQ;AAAA,EACzB,MAAM,OAAO,SAAS;AAAA,EACtB,IAAI,CAAC;AAAA,IAAM,OAAO;AAAA,EAClB,MAAM,eAAe;AAAA,EACrB,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC1B,IAAI,SAAS;AAAA,EACb,MAAM,OAAO,MAAM;AAAA,IAElB,IAAI,QAAQ,QAAQ,UAAU;AAAA,MAAU;AAAA,IACxC,IAAI,QAAQ,aAAa;AAAA,MACxB,IAAI,EAAE,SAAS;AAAA,QAAY,KAAK,sBAAsB,IAAI;AAAA,MAC1D;AAAA,IACD;AAAA,IAIA,KAAK,sBAAsB,MAC1B,KAAK,sBAAsB,MAAM;AAAA,MAChC,MAAM,SAAS,SAAS,iBAAiB,SAAS;AAAA,MAClD,OAAO,cAAc,IAAI,KAAK,cAAc,WAAW,IAAI,CAAC;AAAA,KAC5D,CACF;AAAA;AAAA,EAED,KAAK,sBAAsB,IAAI;AAAA,EAC/B,OAAO;AAAA;AAGR,IAAM,QAAQ;AAQd,SAAS,WAAW,CAAC,QAA0B;AAAA,EAC9C,IAAI,OAAO,aAAa,gBAAgB,MAAM;AAAA,IAAQ,OAAO;AAAA,EAC7D,IACC,OAAO,aAAa,MAAM,MAAM,cAChC,OAAO,aAAa,eAAe,MAAM,QACxC;AAAA,IACD,OAAO;AAAA,EACR;AAAA,EACA,MAAM,KAAK,OAAO,aAAa,eAAe;AAAA,EAC9C,MAAM,OAAO,KAAK,OAAO,cAAc,eAAe,EAAE,IAAI;AAAA,EAC5D,OAAO,CAAC,CAAC,MAAM,QAAQ,KAAK;AAAA;AAgBtB,SAAS,cAAc,CAAC,OAA+B;AAAA,EAC7D,MAAM,SAAS,MAAM,eAAe,EAAE,MAAM,MAAM;AAAA,EAClD,IACC,MAAM,oBACL,QAAwB,aAAa,KACtC,CAAC,YAAY,MAAiB,GAC7B;AAAA,IACD,OAAO;AAAA,EACR;AAAA,EACA,MAAM,eAAe;AAAA,EACrB,OAAO;AAAA;",
|
|
8
|
+
"debugId": "F5ACF4B859D649DF64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -10,6 +10,7 @@ export * from './pdf-escape';
|
|
|
10
10
|
export * from './pdf-page-geometry';
|
|
11
11
|
export * from './pdf-page-sizes';
|
|
12
12
|
export * from './pdf-pin-page';
|
|
13
|
+
export * from './pdf-reveal-hit';
|
|
13
14
|
export * from './pdf-scroll-spy';
|
|
14
15
|
export * from './pdf-text-search';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pdf-viewer/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pdf-viewer/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC"}
|