@ai-matrx/media 0.3.0 → 0.4.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 +156 -0
- package/README.md +60 -3
- package/dist/next.cjs +92 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +74 -0
- package/dist/next.d.ts +74 -0
- package/dist/next.js +60 -0
- package/dist/next.js.map +1 -0
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -1
- package/dist/react.d.ts +10 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/viewers.cjs +1756 -0
- package/dist/viewers.cjs.map +1 -0
- package/dist/viewers.d.cts +289 -0
- package/dist/viewers.d.ts +289 -0
- package/dist/viewers.js +1738 -0
- package/dist/viewers.js.map +1 -0
- package/package.json +31 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,161 @@
|
|
|
1
1
|
# @ai-matrx/media
|
|
2
2
|
|
|
3
|
+
## 0.4.1 — 2026-08-30
|
|
4
|
+
|
|
5
|
+
**Fixes a crash class in 0.4.0's `/viewers` dispatch. Every 0.4.0 consumer must
|
|
6
|
+
move to 0.4.1** — the bug is invisible until a real engine is registered, which
|
|
7
|
+
is what every host does.
|
|
8
|
+
|
|
9
|
+
### Consumer action (C28)
|
|
10
|
+
|
|
11
|
+
- Upgrade. No API change; nothing to rewrite.
|
|
12
|
+
|
|
13
|
+
### The defect
|
|
14
|
+
|
|
15
|
+
`MediaFileViewer` CALLED the registered viewer as a plain function
|
|
16
|
+
(`viewer(props)`), and `CodeViewer` did the same with the registered
|
|
17
|
+
highlighter. Every real engine adapter uses hooks — it resolves a display URL,
|
|
18
|
+
reads the host theme, joins a playback session — so those hooks landed in the
|
|
19
|
+
DISPATCHER's hook list instead of the body's own. A single body renders fine;
|
|
20
|
+
the moment the file kind changes (image → code, code → PDF) the hook count
|
|
21
|
+
changes and React throws "Rendered fewer hooks than expected", taking the whole
|
|
22
|
+
preview surface down. Both now mount through `createElement`, so each body gets
|
|
23
|
+
its own component instance and its own hook list.
|
|
24
|
+
|
|
25
|
+
Found while adopting 0.4.0 in matrx-frontend, before the host swap shipped.
|
|
26
|
+
Guarded by a new test that mounts hook-using bodies and then switches kinds
|
|
27
|
+
three times — the exact sequence that used to crash.
|
|
28
|
+
|
|
29
|
+
## 0.4.0 — 2026-08-30
|
|
30
|
+
|
|
31
|
+
**The package renders FILES now, not just media elements** — and it knows what
|
|
32
|
+
Next.js is. Two new subpaths close this package's ALL-INCLUSIVE-LAW retrofit
|
|
33
|
+
row: `./next` (the framework seam every Next host was rebuilding) and
|
|
34
|
+
`./viewers` (the full-pane file viewers matrx-frontend owned).
|
|
35
|
+
|
|
36
|
+
### Consumer action (C28)
|
|
37
|
+
|
|
38
|
+
- **`./next` replaces every hand-written `next/image` adapter.** A host's
|
|
39
|
+
`ImageComponent` port collapses to
|
|
40
|
+
`ImageComponent: NextMediaImage` (or `createNextMediaImageComponent({…})`).
|
|
41
|
+
Delete the local wrapper — including the four `as React.*Handler` casts it
|
|
42
|
+
needed; the package owns those now. `next` is an **optional peer** (`>=14`),
|
|
43
|
+
so non-Next consumers are unaffected and nothing new installs for them.
|
|
44
|
+
- **`./viewers` replaces host-owned text / code / SVG / HTML / generic
|
|
45
|
+
previewers.** A host now registers only what the package cannot ship — its
|
|
46
|
+
heavy engines — and renders `<MediaFileViewer>`:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
registerMediaViewer("pdf", HostPdfViewer); // PDF.js, react-pdf…
|
|
50
|
+
registerMediaCodeHighlighter(PrismHighlighter); // optional: colour
|
|
51
|
+
<MediaFileViewer source={{ kind: "ref", ref }} fileName={name} />
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Delete the absorbed bodies. Anything NOT registered renders the announcing
|
|
55
|
+
default, never a dead pane.
|
|
56
|
+
- 🚨 **`formatFileSize` behavior change (`/react`).** It now accepts
|
|
57
|
+
`number | null | undefined` and returns `"—"` for null / undefined / NaN /
|
|
58
|
+
negative, where it previously returned a confident, wrong `"0 B"`. Any
|
|
59
|
+
consumer asserting `"0 B"` for a missing size must update. (Defect found
|
|
60
|
+
while absorbing the viewers: matrx-frontend's own `formatFileSize` already
|
|
61
|
+
had this guard and the package's did not — C22 says the package carries the
|
|
62
|
+
better one.)
|
|
63
|
+
- **No other existing export changed shape.**
|
|
64
|
+
|
|
65
|
+
### `./next` — the Next.js binding (NEW)
|
|
66
|
+
|
|
67
|
+
- `NextMediaImage` and `createNextMediaImageComponent({ unoptimized?, quality?,
|
|
68
|
+
sizes?, priority?, loader?, className? })` — a `MediaHostPorts.ImageComponent`
|
|
69
|
+
implementation over `next/image`, with `unoptimized: true` as the default
|
|
70
|
+
because Matrx durable URLs are session-cookie authenticated and Next's
|
|
71
|
+
optimizer fetches them SERVER-side, where there is no user session.
|
|
72
|
+
- **The deliberate divergence from `@ai-matrx/data`'s `/next`** (which imports
|
|
73
|
+
no `next/*` module): `next/image` is not data crossing a seam, it IS the
|
|
74
|
+
renderer, so no structural seam can express it — the ALL-INCLUSIVE LAW names
|
|
75
|
+
this exact wrapper as package-owned. Confined to this one entry; the
|
|
76
|
+
package's components still reach Next only through the `ImageComponent` port.
|
|
77
|
+
- The port's structurally-typed handlers are narrowed to DOM handler types
|
|
78
|
+
here, once, instead of in every host.
|
|
79
|
+
|
|
80
|
+
### `./viewers` — full-pane file viewers (NEW)
|
|
81
|
+
|
|
82
|
+
Absorbed from matrx-frontend `features/files/components/core/FilePreview/`:
|
|
83
|
+
`PreviewerSwitch` (the dispatcher) plus the `TextPreview`, `CodePreview`,
|
|
84
|
+
`SvgPreview`, `HtmlPreview` and `GenericPreview` bodies. Behavior ported
|
|
85
|
+
verbatim except where noted below.
|
|
86
|
+
|
|
87
|
+
- `MediaFileViewer` — kind dispatch with the C23 resolution order: a host
|
|
88
|
+
registration wins, else the package's built-in body, else the **announcing
|
|
89
|
+
default** that names the missing engine and the remedy and still offers
|
|
90
|
+
download / view-as-text. A blank pane is not a reachable state.
|
|
91
|
+
- Built-in bodies: `TextViewer`, `CodeViewer`, `SvgViewer` (rendered + XML
|
|
92
|
+
source), `HtmlViewer` (sandboxed frame + source), `GenericViewer`.
|
|
93
|
+
- `registerMediaViewer(kind, Component)` / `registerMediaCodeHighlighter(fn)` —
|
|
94
|
+
the heavy-engine seam, on `globalThis` `Symbol.for` slots so a registration
|
|
95
|
+
made in one loader graph is visible from the other (the tarball canary
|
|
96
|
+
proves it across ESM/CJS). Both return an unregister function.
|
|
97
|
+
- `getPreviewKind(fileName, mimeType?)` — kind derivation from the package's
|
|
98
|
+
own file-kind registry, so a fresh app dispatches correctly with zero setup.
|
|
99
|
+
A host with a richer registry passes `previewKind` explicitly.
|
|
100
|
+
- `MediaViewerSource` has two lanes: `{kind:"ref"}` (everything through the
|
|
101
|
+
MediaClient) and `{kind:"blob"}` (bytes the host already downloaded — proven
|
|
102
|
+
by test to make **zero** client calls).
|
|
103
|
+
- The markup viewers take OPTIONAL `markupControls`; a host control rail drives
|
|
104
|
+
mode / viewport / reload, and without one the viewer draws its own toolbar
|
|
105
|
+
and is fully capable (the original hard-wired itself to an app context).
|
|
106
|
+
- **Why `CodeViewer` ships without a highlighter** (C8, the diff-package Monaco
|
|
107
|
+
precedent): Prism is a ~150KB browser-only engine and a headless consumer
|
|
108
|
+
must not carry it. The package ships monospace, line-numbered, wrap-toggling,
|
|
109
|
+
copyable, truncation-honest code — everything but colour — and the engine
|
|
110
|
+
rides `registerMediaCodeHighlighter`. That default announces nothing because
|
|
111
|
+
nothing failed.
|
|
112
|
+
- **`HtmlViewer`'s sandbox is non-configurable**: `allow-scripts allow-popups
|
|
113
|
+
allow-forms`, never `allow-same-origin`, plus `referrerPolicy="no-referrer"`.
|
|
114
|
+
One wrong token is a real XSS against the host origin, so hosts do not get a
|
|
115
|
+
knob. Asserted in the source suite AND on the packed artifact.
|
|
116
|
+
|
|
117
|
+
### Defects fixed in the port (never silently — C22)
|
|
118
|
+
|
|
119
|
+
- **A user-visible debug artifact is gone.** `GenericPreview` shipped a
|
|
120
|
+
fuchsia `ring-2` and a "GenericPreview" corner badge — a layering-debug
|
|
121
|
+
visualization commented "Rip this out when done" — to every user opening an
|
|
122
|
+
unpreviewable file. The package has no debug chrome.
|
|
123
|
+
- **`blob.text()` is no longer assumed.** All four absorbed text-reading
|
|
124
|
+
previewers called it directly; it does not exist in Safari < 14, older
|
|
125
|
+
WebViews (the Tauri shell's floor), or jsdom, and the failure surfaced to the
|
|
126
|
+
user as `blob.text is not a function` — as though the FILE were broken.
|
|
127
|
+
`readBlobText` falls back through `arrayBuffer()` and `FileReader`.
|
|
128
|
+
- **`formatFileSize`** — see Consumer action above.
|
|
129
|
+
- **Four copies of the read-cap-truncate-report machinery became one**
|
|
130
|
+
(`useViewerText`), as did the error card, skeleton and copy button.
|
|
131
|
+
|
|
132
|
+
### Gate
|
|
133
|
+
|
|
134
|
+
`pnpm typecheck && pnpm test && pnpm check:package` green: 125 tests
|
|
135
|
+
(14 new C23 tests across three targets — the announcing default incl. its
|
|
136
|
+
falsifiability leg, the built-in bodies unregistered, and dispatch with zero
|
|
137
|
+
host configuration), publint, attw node16, and a tarball canary extended with
|
|
138
|
+
the `/next` no-cast `MediaHostPorts` assignment, the `/viewers` ESM+CJS export
|
|
139
|
+
and render legs, the packed-artifact sandbox assertion, and the viewer-registry
|
|
140
|
+
dual-graph proof. `/next` is not loaded in the bare-node ESM leg by design:
|
|
141
|
+
Next publishes `next/image` extensionless with no `exports` map, so only
|
|
142
|
+
bundlers and TypeScript resolve it — it is proven via attw, the type canary,
|
|
143
|
+
and a real `require()` in the CJS leg.
|
|
144
|
+
|
|
145
|
+
### Deliberately NOT absorbed (recorded, not forgotten)
|
|
146
|
+
|
|
147
|
+
- **The PDF viewer tree** (`matrx-frontend/features/pdf`, 49 files): PDF.js +
|
|
148
|
+
annotation layer + document scanner + surface registry + server-side
|
|
149
|
+
extraction API. It is a FEATURE, not a viewer body, and it rides the
|
|
150
|
+
`registerMediaViewer("pdf", …)` seam.
|
|
151
|
+
- **Markdown / spreadsheet / Office viewers**: remark+rehype+KaTeX, SheetJS +
|
|
152
|
+
PapaParse, and a server extraction endpoint respectively — heavy engines or
|
|
153
|
+
host-server-coupled. Same seam.
|
|
154
|
+
- **Image / video / audio viewers**: they bind host domain systems (a
|
|
155
|
+
zoom/rotate control rail, the unified playback-session registry, a
|
|
156
|
+
design-system slider). They already consume `/core`; absorbing their bodies
|
|
157
|
+
is the next wave, not this one.
|
|
158
|
+
|
|
3
159
|
## 0.3.0 — 2026-08-30
|
|
4
160
|
|
|
5
161
|
**A terminal media failure can never be silent again.** Born from the
|
package/README.md
CHANGED
|
@@ -146,6 +146,63 @@ default, never silent. If your `MediaClient.recoverLoadError` returns a
|
|
|
146
146
|
`secret_source: "ephemeral"`, the package immediately captures an app-wide
|
|
147
147
|
warning that private renders will break across server restarts/instances.
|
|
148
148
|
|
|
149
|
+
## File viewers (`/viewers`)
|
|
150
|
+
|
|
151
|
+
Full-pane rendering of ONE file — a preview pane, a file tab, a code editor's
|
|
152
|
+
binary-file fallback. `MediaFileViewer` dispatches on the file kind and ships
|
|
153
|
+
working bodies for text, code, SVG, HTML and unknown files.
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { MediaFileViewer } from "@ai-matrx/media/viewers";
|
|
157
|
+
|
|
158
|
+
<MediaFileViewer
|
|
159
|
+
source={{ kind: "ref", ref: { file_id } }}
|
|
160
|
+
fileName={file.name}
|
|
161
|
+
fileSize={file.size}
|
|
162
|
+
generic={{ onDownload }}
|
|
163
|
+
/>;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Kinds whose rendering IS a heavy browser-only engine — PDF, Markdown,
|
|
167
|
+
spreadsheets, Office documents — are yours to register, so a consumer that only
|
|
168
|
+
shows text files never carries a PDF engine:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { registerMediaViewer, registerMediaCodeHighlighter } from "@ai-matrx/media/viewers";
|
|
172
|
+
|
|
173
|
+
registerMediaViewer("pdf", MyPdfViewer); // gets MediaViewerProps
|
|
174
|
+
registerMediaCodeHighlighter(MyPrismHighlighter); // optional: colour for code
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Until you register one, that kind renders an **announcing default**: it names
|
|
178
|
+
the missing engine and the remedy and still offers download / view-as-text. It
|
|
179
|
+
is never a blank pane. (Code is different: with no highlighter registered it
|
|
180
|
+
renders complete — monospace, line-numbered, copyable — just without colour,
|
|
181
|
+
so it announces nothing.)
|
|
182
|
+
|
|
183
|
+
Registering a kind the package already renders replaces the built-in, which is
|
|
184
|
+
how you plug in a domain-specific viewer of your own.
|
|
185
|
+
|
|
186
|
+
The `blob` source lane (`{ kind: "blob", blob, url }`) renders bytes you
|
|
187
|
+
already have without touching the `MediaClient` at all.
|
|
188
|
+
|
|
189
|
+
## Next.js (`/next`)
|
|
190
|
+
|
|
191
|
+
The `ImageComponent` port, implemented over `next/image` so you never write
|
|
192
|
+
that wrapper again. `next` is an optional peer — nothing installs it for you,
|
|
193
|
+
and no other entry imports it.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import { NextMediaImage } from "@ai-matrx/media/next";
|
|
197
|
+
|
|
198
|
+
const ports: MediaHostPorts = { ImageComponent: NextMediaImage };
|
|
199
|
+
// or: createNextMediaImageComponent({ unoptimized: false, quality: 90 })
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
It defaults to `unoptimized`, which is correct for Matrx media: durable file
|
|
203
|
+
URLs are session-cookie authenticated and Next's optimizer fetches them from
|
|
204
|
+
the server, where there is no user session.
|
|
205
|
+
|
|
149
206
|
## Styling
|
|
150
207
|
|
|
151
208
|
`/react` uses Tailwind utility classes with semantic tokens (`bg-muted`,
|
|
@@ -157,9 +214,9 @@ warning that private renders will break across server restarts/instances.
|
|
|
157
214
|
|
|
158
215
|
## SSR / RSC
|
|
159
216
|
|
|
160
|
-
The root entry is server-safe (types + one pure function). `/core`, `/react
|
|
161
|
-
and `/
|
|
162
|
-
Nothing touches `window` at import time.
|
|
217
|
+
The root entry is server-safe (types + one pure function). `/core`, `/react`,
|
|
218
|
+
`/share`, `/viewers` and `/next` are client modules (`"use client"` is stamped
|
|
219
|
+
per entry). Nothing touches `window` at import time.
|
|
163
220
|
|
|
164
221
|
## License
|
|
165
222
|
|
package/dist/next.cjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/next.ts
|
|
32
|
+
var next_exports = {};
|
|
33
|
+
__export(next_exports, {
|
|
34
|
+
NextMediaImage: () => NextMediaImage,
|
|
35
|
+
createNextMediaImageComponent: () => createNextMediaImageComponent
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(next_exports);
|
|
38
|
+
|
|
39
|
+
// src/next/image.tsx
|
|
40
|
+
var import_image = __toESM(require("next/image"), 1);
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
+
function createNextMediaImageComponent(options = {}) {
|
|
43
|
+
const {
|
|
44
|
+
unoptimized = true,
|
|
45
|
+
quality,
|
|
46
|
+
sizes,
|
|
47
|
+
priority,
|
|
48
|
+
loader,
|
|
49
|
+
className: baseClassName
|
|
50
|
+
} = options;
|
|
51
|
+
function NextMediaImageWithOptions({
|
|
52
|
+
src,
|
|
53
|
+
alt,
|
|
54
|
+
width,
|
|
55
|
+
height,
|
|
56
|
+
className,
|
|
57
|
+
onError,
|
|
58
|
+
onClick,
|
|
59
|
+
onKeyDown,
|
|
60
|
+
role,
|
|
61
|
+
tabIndex
|
|
62
|
+
}) {
|
|
63
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
64
|
+
import_image.default,
|
|
65
|
+
{
|
|
66
|
+
src,
|
|
67
|
+
alt,
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
unoptimized,
|
|
71
|
+
...quality !== void 0 ? { quality } : {},
|
|
72
|
+
...sizes !== void 0 ? { sizes } : {},
|
|
73
|
+
...priority !== void 0 ? { priority } : {},
|
|
74
|
+
...loader !== void 0 ? {
|
|
75
|
+
loader: ({ src: src2, width: width2, quality: loaderQuality }) => loader({ source: src2, width: width2, quality: loaderQuality })
|
|
76
|
+
} : {},
|
|
77
|
+
...baseClassName !== void 0 || className !== void 0 ? {
|
|
78
|
+
className: [baseClassName, className].filter((part) => !!part).join(" ")
|
|
79
|
+
} : {},
|
|
80
|
+
...onError !== void 0 ? { onError } : {},
|
|
81
|
+
...onClick !== void 0 ? { onClick } : {},
|
|
82
|
+
...onKeyDown !== void 0 ? { onKeyDown } : {},
|
|
83
|
+
...role !== void 0 ? { role } : {},
|
|
84
|
+
...tabIndex !== void 0 ? { tabIndex } : {}
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
NextMediaImageWithOptions.displayName = "NextMediaImage";
|
|
89
|
+
return NextMediaImageWithOptions;
|
|
90
|
+
}
|
|
91
|
+
var NextMediaImage = createNextMediaImageComponent();
|
|
92
|
+
//# sourceMappingURL=next.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/next.ts","../src/next/image.tsx"],"sourcesContent":["/**\n * `@ai-matrx/media/next` — the Next.js platform binding.\n *\n * ONE export a Next host needs, replacing the wrapper every Next app was\n * hand-writing (`MediaHostPorts.ImageComponent` over `next/image`). This is\n * the ONLY entry in the package that imports a `next/*` module; `next` is an\n * OPTIONAL peer, so no other consumer pays for it and no other entry may\n * reach for it. See the rationale block in `./next/image.tsx`.\n */\n\nexport {\n createNextMediaImageComponent,\n NextMediaImage,\n type NextMediaImageLoaderArgs,\n type NextMediaImageOptions,\n} from \"./next/image\";\n","/**\n * src/next/image.tsx — the Next.js `ImageComponent` port implementation.\n *\n * WHY THIS ENTRY IMPORTS `next/image` (the deliberate divergence from the\n * data 0.5.0 `/next` precedent, which imports NO `next/*` module):\n *\n * `@ai-matrx/data/next` could keep Next out of its source because everything\n * it needed from Next — `cookies()`, `NextResponse` — is DATA passed across a\n * structural seam. `next/image` is not data: it is the rendering component\n * itself, and its entire value (the optimizer endpoint, the srcset builder,\n * the lazy/priority machinery, the blur placeholder) lives inside the module.\n * A \"seam\" for it degenerates into exactly the thing THE ALL-INCLUSIVE LAW\n * names as the failure — \"the `next/image`/`next/link` wrappers\" that every\n * host was rebuilding by hand (matrx-frontend's was 35 lines of prop\n * forwarding with four `as` casts). So this ONE entry takes `next` as an\n * OPTIONAL peer and owns the wrapper; no other entry in the package may.\n *\n * The seam is preserved where it still buys something: the package's\n * components never import this module. They call `MediaHostPorts.ImageComponent`,\n * which defaults to a plain `<img>`. A Next host assigns `NextMediaImage` (or\n * a configured one) and nothing else in the package learns that Next exists.\n */\n\n\"use client\";\n\nimport Image from \"next/image\";\nimport type { MediaImageComponentProps } from \"../types\";\n\n/**\n * Structural mirror of Next's `ImageLoaderProps` — declared here so the\n * package's public types never re-export a `next/*` type (which would make\n * the shape of our API depend on the consumer's Next version).\n */\nexport interface NextMediaImageLoaderArgs {\n source: string;\n width: number;\n quality?: number | undefined;\n}\n\nexport interface NextMediaImageOptions {\n /**\n * Skip Next's optimizer endpoint. Defaults to `true`, which is the ONLY\n * correct default for Matrx media: durable file URLs are session-cookie\n * authenticated, and `/_next/image` fetches them from the SERVER, which\n * carries no user session — an optimized private image 404s. Set this to\n * `false` only for a host whose media is genuinely public CDN content and\n * whose `next.config` allows the remote pattern.\n */\n unoptimized?: boolean | undefined;\n quality?: number | undefined;\n sizes?: string | undefined;\n priority?: boolean | undefined;\n loader?: ((args: NextMediaImageLoaderArgs) => string) | undefined;\n /** Extra class applied under the caller's `className` (last-wins merge). */\n className?: string | undefined;\n}\n\n/**\n * Build a Next.js `ImageComponent` port with fixed options.\n *\n * ```tsx\n * const ports: MediaHostPorts = {\n * ImageComponent: createNextMediaImageComponent({ quality: 90 }),\n * };\n * ```\n */\nexport function createNextMediaImageComponent(\n options: NextMediaImageOptions = {},\n): (props: MediaImageComponentProps) => React.ReactElement {\n const {\n unoptimized = true,\n quality,\n sizes,\n priority,\n loader,\n className: baseClassName,\n } = options;\n\n function NextMediaImageWithOptions({\n src,\n alt,\n width,\n height,\n className,\n onError,\n onClick,\n onKeyDown,\n role,\n tabIndex,\n }: MediaImageComponentProps): React.ReactElement {\n return (\n <Image\n src={src}\n alt={alt}\n width={width}\n height={height}\n unoptimized={unoptimized}\n {...(quality !== undefined ? { quality } : {})}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(priority !== undefined ? { priority } : {})}\n {...(loader !== undefined\n ? {\n loader: ({ src, width, quality: loaderQuality }) =>\n loader({ source: src, width, quality: loaderQuality }),\n }\n : {})}\n {...(baseClassName !== undefined || className !== undefined\n ? {\n className: [baseClassName, className]\n .filter((part): part is string => !!part)\n .join(\" \"),\n }\n : {})}\n // The port's handlers are structurally typed (`(event: unknown) => void`)\n // so the root entry stays free of React type imports. Narrowing them to\n // the DOM handler shapes is this binding's job — a host must never write\n // these casts again (C22: the massage lives in the package).\n {...(onError !== undefined\n ? { onError: onError as React.ReactEventHandler<HTMLImageElement> }\n : {})}\n {...(onClick !== undefined\n ? { onClick: onClick as React.MouseEventHandler<HTMLImageElement> }\n : {})}\n {...(onKeyDown !== undefined\n ? { onKeyDown: onKeyDown as React.KeyboardEventHandler<HTMLImageElement> }\n : {})}\n {...(role !== undefined ? { role } : {})}\n {...(tabIndex !== undefined ? { tabIndex } : {})}\n />\n );\n }\n\n NextMediaImageWithOptions.displayName = \"NextMediaImage\";\n return NextMediaImageWithOptions;\n}\n\n/**\n * The zero-configuration Next.js `ImageComponent` port — `unoptimized`, every\n * port prop forwarded. This is the whole of what a Next host needs:\n *\n * ```tsx\n * import { NextMediaImage } from \"@ai-matrx/media/next\";\n * const ports: MediaHostPorts = { ImageComponent: NextMediaImage };\n * ```\n */\nexport const NextMediaImage = createNextMediaImageComponent();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyBA,mBAAkB;AAkEZ;AAzBC,SAAS,8BACd,UAAiC,CAAC,GACuB;AACzD,QAAM;AAAA,IACJ,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,IAAI;AAEJ,WAAS,0BAA0B;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAiD;AAC/C,WACE;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACC,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,QACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7C,GAAI,WAAW,SACZ;AAAA,UACE,QAAQ,CAAC,EAAE,KAAAC,MAAK,OAAAC,QAAO,SAAS,cAAc,MAC5C,OAAO,EAAE,QAAQD,MAAK,OAAAC,QAAO,SAAS,cAAc,CAAC;AAAA,QACzD,IACA,CAAC;AAAA,QACJ,GAAI,kBAAkB,UAAa,cAAc,SAC9C;AAAA,UACE,WAAW,CAAC,eAAe,SAAS,EACjC,OAAO,CAAC,SAAyB,CAAC,CAAC,IAAI,EACvC,KAAK,GAAG;AAAA,QACb,IACA,CAAC;AAAA,QAKJ,GAAI,YAAY,SACb,EAAE,QAA8D,IAChE,CAAC;AAAA,QACJ,GAAI,YAAY,SACb,EAAE,QAA8D,IAChE,CAAC;AAAA,QACJ,GAAI,cAAc,SACf,EAAE,UAAqE,IACvE,CAAC;AAAA,QACJ,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,QACrC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA;AAAA,IAChD;AAAA,EAEJ;AAEA,4BAA0B,cAAc;AACxC,SAAO;AACT;AAWO,IAAM,iBAAiB,8BAA8B;","names":["Image","src","width"]}
|
package/dist/next.d.cts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MediaImageComponentProps } from './index.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* src/next/image.tsx — the Next.js `ImageComponent` port implementation.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS ENTRY IMPORTS `next/image` (the deliberate divergence from the
|
|
7
|
+
* data 0.5.0 `/next` precedent, which imports NO `next/*` module):
|
|
8
|
+
*
|
|
9
|
+
* `@ai-matrx/data/next` could keep Next out of its source because everything
|
|
10
|
+
* it needed from Next — `cookies()`, `NextResponse` — is DATA passed across a
|
|
11
|
+
* structural seam. `next/image` is not data: it is the rendering component
|
|
12
|
+
* itself, and its entire value (the optimizer endpoint, the srcset builder,
|
|
13
|
+
* the lazy/priority machinery, the blur placeholder) lives inside the module.
|
|
14
|
+
* A "seam" for it degenerates into exactly the thing THE ALL-INCLUSIVE LAW
|
|
15
|
+
* names as the failure — "the `next/image`/`next/link` wrappers" that every
|
|
16
|
+
* host was rebuilding by hand (matrx-frontend's was 35 lines of prop
|
|
17
|
+
* forwarding with four `as` casts). So this ONE entry takes `next` as an
|
|
18
|
+
* OPTIONAL peer and owns the wrapper; no other entry in the package may.
|
|
19
|
+
*
|
|
20
|
+
* The seam is preserved where it still buys something: the package's
|
|
21
|
+
* components never import this module. They call `MediaHostPorts.ImageComponent`,
|
|
22
|
+
* which defaults to a plain `<img>`. A Next host assigns `NextMediaImage` (or
|
|
23
|
+
* a configured one) and nothing else in the package learns that Next exists.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Structural mirror of Next's `ImageLoaderProps` — declared here so the
|
|
28
|
+
* package's public types never re-export a `next/*` type (which would make
|
|
29
|
+
* the shape of our API depend on the consumer's Next version).
|
|
30
|
+
*/
|
|
31
|
+
interface NextMediaImageLoaderArgs {
|
|
32
|
+
source: string;
|
|
33
|
+
width: number;
|
|
34
|
+
quality?: number | undefined;
|
|
35
|
+
}
|
|
36
|
+
interface NextMediaImageOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Skip Next's optimizer endpoint. Defaults to `true`, which is the ONLY
|
|
39
|
+
* correct default for Matrx media: durable file URLs are session-cookie
|
|
40
|
+
* authenticated, and `/_next/image` fetches them from the SERVER, which
|
|
41
|
+
* carries no user session — an optimized private image 404s. Set this to
|
|
42
|
+
* `false` only for a host whose media is genuinely public CDN content and
|
|
43
|
+
* whose `next.config` allows the remote pattern.
|
|
44
|
+
*/
|
|
45
|
+
unoptimized?: boolean | undefined;
|
|
46
|
+
quality?: number | undefined;
|
|
47
|
+
sizes?: string | undefined;
|
|
48
|
+
priority?: boolean | undefined;
|
|
49
|
+
loader?: ((args: NextMediaImageLoaderArgs) => string) | undefined;
|
|
50
|
+
/** Extra class applied under the caller's `className` (last-wins merge). */
|
|
51
|
+
className?: string | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build a Next.js `ImageComponent` port with fixed options.
|
|
55
|
+
*
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const ports: MediaHostPorts = {
|
|
58
|
+
* ImageComponent: createNextMediaImageComponent({ quality: 90 }),
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function createNextMediaImageComponent(options?: NextMediaImageOptions): (props: MediaImageComponentProps) => React.ReactElement;
|
|
63
|
+
/**
|
|
64
|
+
* The zero-configuration Next.js `ImageComponent` port — `unoptimized`, every
|
|
65
|
+
* port prop forwarded. This is the whole of what a Next host needs:
|
|
66
|
+
*
|
|
67
|
+
* ```tsx
|
|
68
|
+
* import { NextMediaImage } from "@ai-matrx/media/next";
|
|
69
|
+
* const ports: MediaHostPorts = { ImageComponent: NextMediaImage };
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare const NextMediaImage: (props: MediaImageComponentProps) => React.ReactElement;
|
|
73
|
+
|
|
74
|
+
export { NextMediaImage, type NextMediaImageLoaderArgs, type NextMediaImageOptions, createNextMediaImageComponent };
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { MediaImageComponentProps } from './index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* src/next/image.tsx — the Next.js `ImageComponent` port implementation.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS ENTRY IMPORTS `next/image` (the deliberate divergence from the
|
|
7
|
+
* data 0.5.0 `/next` precedent, which imports NO `next/*` module):
|
|
8
|
+
*
|
|
9
|
+
* `@ai-matrx/data/next` could keep Next out of its source because everything
|
|
10
|
+
* it needed from Next — `cookies()`, `NextResponse` — is DATA passed across a
|
|
11
|
+
* structural seam. `next/image` is not data: it is the rendering component
|
|
12
|
+
* itself, and its entire value (the optimizer endpoint, the srcset builder,
|
|
13
|
+
* the lazy/priority machinery, the blur placeholder) lives inside the module.
|
|
14
|
+
* A "seam" for it degenerates into exactly the thing THE ALL-INCLUSIVE LAW
|
|
15
|
+
* names as the failure — "the `next/image`/`next/link` wrappers" that every
|
|
16
|
+
* host was rebuilding by hand (matrx-frontend's was 35 lines of prop
|
|
17
|
+
* forwarding with four `as` casts). So this ONE entry takes `next` as an
|
|
18
|
+
* OPTIONAL peer and owns the wrapper; no other entry in the package may.
|
|
19
|
+
*
|
|
20
|
+
* The seam is preserved where it still buys something: the package's
|
|
21
|
+
* components never import this module. They call `MediaHostPorts.ImageComponent`,
|
|
22
|
+
* which defaults to a plain `<img>`. A Next host assigns `NextMediaImage` (or
|
|
23
|
+
* a configured one) and nothing else in the package learns that Next exists.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Structural mirror of Next's `ImageLoaderProps` — declared here so the
|
|
28
|
+
* package's public types never re-export a `next/*` type (which would make
|
|
29
|
+
* the shape of our API depend on the consumer's Next version).
|
|
30
|
+
*/
|
|
31
|
+
interface NextMediaImageLoaderArgs {
|
|
32
|
+
source: string;
|
|
33
|
+
width: number;
|
|
34
|
+
quality?: number | undefined;
|
|
35
|
+
}
|
|
36
|
+
interface NextMediaImageOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Skip Next's optimizer endpoint. Defaults to `true`, which is the ONLY
|
|
39
|
+
* correct default for Matrx media: durable file URLs are session-cookie
|
|
40
|
+
* authenticated, and `/_next/image` fetches them from the SERVER, which
|
|
41
|
+
* carries no user session — an optimized private image 404s. Set this to
|
|
42
|
+
* `false` only for a host whose media is genuinely public CDN content and
|
|
43
|
+
* whose `next.config` allows the remote pattern.
|
|
44
|
+
*/
|
|
45
|
+
unoptimized?: boolean | undefined;
|
|
46
|
+
quality?: number | undefined;
|
|
47
|
+
sizes?: string | undefined;
|
|
48
|
+
priority?: boolean | undefined;
|
|
49
|
+
loader?: ((args: NextMediaImageLoaderArgs) => string) | undefined;
|
|
50
|
+
/** Extra class applied under the caller's `className` (last-wins merge). */
|
|
51
|
+
className?: string | undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build a Next.js `ImageComponent` port with fixed options.
|
|
55
|
+
*
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const ports: MediaHostPorts = {
|
|
58
|
+
* ImageComponent: createNextMediaImageComponent({ quality: 90 }),
|
|
59
|
+
* };
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function createNextMediaImageComponent(options?: NextMediaImageOptions): (props: MediaImageComponentProps) => React.ReactElement;
|
|
63
|
+
/**
|
|
64
|
+
* The zero-configuration Next.js `ImageComponent` port — `unoptimized`, every
|
|
65
|
+
* port prop forwarded. This is the whole of what a Next host needs:
|
|
66
|
+
*
|
|
67
|
+
* ```tsx
|
|
68
|
+
* import { NextMediaImage } from "@ai-matrx/media/next";
|
|
69
|
+
* const ports: MediaHostPorts = { ImageComponent: NextMediaImage };
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare const NextMediaImage: (props: MediaImageComponentProps) => React.ReactElement;
|
|
73
|
+
|
|
74
|
+
export { NextMediaImage, type NextMediaImageLoaderArgs, type NextMediaImageOptions, createNextMediaImageComponent };
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/next/image.tsx
|
|
4
|
+
import Image from "next/image";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
function createNextMediaImageComponent(options = {}) {
|
|
7
|
+
const {
|
|
8
|
+
unoptimized = true,
|
|
9
|
+
quality,
|
|
10
|
+
sizes,
|
|
11
|
+
priority,
|
|
12
|
+
loader,
|
|
13
|
+
className: baseClassName
|
|
14
|
+
} = options;
|
|
15
|
+
function NextMediaImageWithOptions({
|
|
16
|
+
src,
|
|
17
|
+
alt,
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
className,
|
|
21
|
+
onError,
|
|
22
|
+
onClick,
|
|
23
|
+
onKeyDown,
|
|
24
|
+
role,
|
|
25
|
+
tabIndex
|
|
26
|
+
}) {
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
Image,
|
|
29
|
+
{
|
|
30
|
+
src,
|
|
31
|
+
alt,
|
|
32
|
+
width,
|
|
33
|
+
height,
|
|
34
|
+
unoptimized,
|
|
35
|
+
...quality !== void 0 ? { quality } : {},
|
|
36
|
+
...sizes !== void 0 ? { sizes } : {},
|
|
37
|
+
...priority !== void 0 ? { priority } : {},
|
|
38
|
+
...loader !== void 0 ? {
|
|
39
|
+
loader: ({ src: src2, width: width2, quality: loaderQuality }) => loader({ source: src2, width: width2, quality: loaderQuality })
|
|
40
|
+
} : {},
|
|
41
|
+
...baseClassName !== void 0 || className !== void 0 ? {
|
|
42
|
+
className: [baseClassName, className].filter((part) => !!part).join(" ")
|
|
43
|
+
} : {},
|
|
44
|
+
...onError !== void 0 ? { onError } : {},
|
|
45
|
+
...onClick !== void 0 ? { onClick } : {},
|
|
46
|
+
...onKeyDown !== void 0 ? { onKeyDown } : {},
|
|
47
|
+
...role !== void 0 ? { role } : {},
|
|
48
|
+
...tabIndex !== void 0 ? { tabIndex } : {}
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
NextMediaImageWithOptions.displayName = "NextMediaImage";
|
|
53
|
+
return NextMediaImageWithOptions;
|
|
54
|
+
}
|
|
55
|
+
var NextMediaImage = createNextMediaImageComponent();
|
|
56
|
+
export {
|
|
57
|
+
NextMediaImage,
|
|
58
|
+
createNextMediaImageComponent
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=next.js.map
|
package/dist/next.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/next/image.tsx"],"sourcesContent":["/**\n * src/next/image.tsx — the Next.js `ImageComponent` port implementation.\n *\n * WHY THIS ENTRY IMPORTS `next/image` (the deliberate divergence from the\n * data 0.5.0 `/next` precedent, which imports NO `next/*` module):\n *\n * `@ai-matrx/data/next` could keep Next out of its source because everything\n * it needed from Next — `cookies()`, `NextResponse` — is DATA passed across a\n * structural seam. `next/image` is not data: it is the rendering component\n * itself, and its entire value (the optimizer endpoint, the srcset builder,\n * the lazy/priority machinery, the blur placeholder) lives inside the module.\n * A \"seam\" for it degenerates into exactly the thing THE ALL-INCLUSIVE LAW\n * names as the failure — \"the `next/image`/`next/link` wrappers\" that every\n * host was rebuilding by hand (matrx-frontend's was 35 lines of prop\n * forwarding with four `as` casts). So this ONE entry takes `next` as an\n * OPTIONAL peer and owns the wrapper; no other entry in the package may.\n *\n * The seam is preserved where it still buys something: the package's\n * components never import this module. They call `MediaHostPorts.ImageComponent`,\n * which defaults to a plain `<img>`. A Next host assigns `NextMediaImage` (or\n * a configured one) and nothing else in the package learns that Next exists.\n */\n\n\"use client\";\n\nimport Image from \"next/image\";\nimport type { MediaImageComponentProps } from \"../types\";\n\n/**\n * Structural mirror of Next's `ImageLoaderProps` — declared here so the\n * package's public types never re-export a `next/*` type (which would make\n * the shape of our API depend on the consumer's Next version).\n */\nexport interface NextMediaImageLoaderArgs {\n source: string;\n width: number;\n quality?: number | undefined;\n}\n\nexport interface NextMediaImageOptions {\n /**\n * Skip Next's optimizer endpoint. Defaults to `true`, which is the ONLY\n * correct default for Matrx media: durable file URLs are session-cookie\n * authenticated, and `/_next/image` fetches them from the SERVER, which\n * carries no user session — an optimized private image 404s. Set this to\n * `false` only for a host whose media is genuinely public CDN content and\n * whose `next.config` allows the remote pattern.\n */\n unoptimized?: boolean | undefined;\n quality?: number | undefined;\n sizes?: string | undefined;\n priority?: boolean | undefined;\n loader?: ((args: NextMediaImageLoaderArgs) => string) | undefined;\n /** Extra class applied under the caller's `className` (last-wins merge). */\n className?: string | undefined;\n}\n\n/**\n * Build a Next.js `ImageComponent` port with fixed options.\n *\n * ```tsx\n * const ports: MediaHostPorts = {\n * ImageComponent: createNextMediaImageComponent({ quality: 90 }),\n * };\n * ```\n */\nexport function createNextMediaImageComponent(\n options: NextMediaImageOptions = {},\n): (props: MediaImageComponentProps) => React.ReactElement {\n const {\n unoptimized = true,\n quality,\n sizes,\n priority,\n loader,\n className: baseClassName,\n } = options;\n\n function NextMediaImageWithOptions({\n src,\n alt,\n width,\n height,\n className,\n onError,\n onClick,\n onKeyDown,\n role,\n tabIndex,\n }: MediaImageComponentProps): React.ReactElement {\n return (\n <Image\n src={src}\n alt={alt}\n width={width}\n height={height}\n unoptimized={unoptimized}\n {...(quality !== undefined ? { quality } : {})}\n {...(sizes !== undefined ? { sizes } : {})}\n {...(priority !== undefined ? { priority } : {})}\n {...(loader !== undefined\n ? {\n loader: ({ src, width, quality: loaderQuality }) =>\n loader({ source: src, width, quality: loaderQuality }),\n }\n : {})}\n {...(baseClassName !== undefined || className !== undefined\n ? {\n className: [baseClassName, className]\n .filter((part): part is string => !!part)\n .join(\" \"),\n }\n : {})}\n // The port's handlers are structurally typed (`(event: unknown) => void`)\n // so the root entry stays free of React type imports. Narrowing them to\n // the DOM handler shapes is this binding's job — a host must never write\n // these casts again (C22: the massage lives in the package).\n {...(onError !== undefined\n ? { onError: onError as React.ReactEventHandler<HTMLImageElement> }\n : {})}\n {...(onClick !== undefined\n ? { onClick: onClick as React.MouseEventHandler<HTMLImageElement> }\n : {})}\n {...(onKeyDown !== undefined\n ? { onKeyDown: onKeyDown as React.KeyboardEventHandler<HTMLImageElement> }\n : {})}\n {...(role !== undefined ? { role } : {})}\n {...(tabIndex !== undefined ? { tabIndex } : {})}\n />\n );\n }\n\n NextMediaImageWithOptions.displayName = \"NextMediaImage\";\n return NextMediaImageWithOptions;\n}\n\n/**\n * The zero-configuration Next.js `ImageComponent` port — `unoptimized`, every\n * port prop forwarded. This is the whole of what a Next host needs:\n *\n * ```tsx\n * import { NextMediaImage } from \"@ai-matrx/media/next\";\n * const ports: MediaHostPorts = { ImageComponent: NextMediaImage };\n * ```\n */\nexport const NextMediaImage = createNextMediaImageComponent();\n"],"mappings":";;;AAyBA,OAAO,WAAW;AAkEZ;AAzBC,SAAS,8BACd,UAAiC,CAAC,GACuB;AACzD,QAAM;AAAA,IACJ,cAAc;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,IAAI;AAEJ,WAAS,0BAA0B;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAiD;AAC/C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACC,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,QACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,QAC7C,GAAI,WAAW,SACZ;AAAA,UACE,QAAQ,CAAC,EAAE,KAAAA,MAAK,OAAAC,QAAO,SAAS,cAAc,MAC5C,OAAO,EAAE,QAAQD,MAAK,OAAAC,QAAO,SAAS,cAAc,CAAC;AAAA,QACzD,IACA,CAAC;AAAA,QACJ,GAAI,kBAAkB,UAAa,cAAc,SAC9C;AAAA,UACE,WAAW,CAAC,eAAe,SAAS,EACjC,OAAO,CAAC,SAAyB,CAAC,CAAC,IAAI,EACvC,KAAK,GAAG;AAAA,QACb,IACA,CAAC;AAAA,QAKJ,GAAI,YAAY,SACb,EAAE,QAA8D,IAChE,CAAC;AAAA,QACJ,GAAI,YAAY,SACb,EAAE,QAA8D,IAChE,CAAC;AAAA,QACJ,GAAI,cAAc,SACf,EAAE,UAAqE,IACvE,CAAC;AAAA,QACJ,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,QACrC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA;AAAA,IAChD;AAAA,EAEJ;AAEA,4BAA0B,cAAc;AACxC,SAAO;AACT;AAWO,IAAM,iBAAiB,8BAA8B;","names":["src","width"]}
|
package/dist/react.cjs
CHANGED
|
@@ -1803,7 +1803,7 @@ var import_react11 = require("react");
|
|
|
1803
1803
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1804
1804
|
var AUTO_DISMISS_MS = 1e4;
|
|
1805
1805
|
function formatFileSize(bytes) {
|
|
1806
|
-
if (!Number.isFinite(bytes) || bytes < 0) return "
|
|
1806
|
+
if (bytes == null || !Number.isFinite(bytes) || bytes < 0) return "\u2014";
|
|
1807
1807
|
if (bytes < 1024) return `${bytes} B`;
|
|
1808
1808
|
const units = ["KB", "MB", "GB", "TB"];
|
|
1809
1809
|
let value = bytes;
|