@ai-matrx/media 0.1.1 → 0.2.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 CHANGED
@@ -1,5 +1,71 @@
1
1
  # @ai-matrx/media
2
2
 
3
+ ## 0.2.1 — 2026-08-30
4
+
5
+ Additive only — every default unchanged. Closes the wave-2 gap that kept the
6
+ host's video lightbox host-side: `MediaLightbox` had no video passthrough.
7
+
8
+ - **`MediaLightbox`** gains `autoPlay`, `playsInline`, `poster`, and
9
+ `playbackLabel`, forwarded to the underlying `InlineMediaRef`:
10
+ - `poster` is typed as the branded `DurableSrc` (law 3 — the host
11
+ resolves/mints it, exactly like the element src; no raw-string lane);
12
+ - `playbackLabel` sets the label reported to the host's existing
13
+ `playbackSession` port while the media plays (e.g. "Video
14
+ (fullscreen)") — playback still rides the ONE port, no new lane.
15
+ - **`InlineMediaRef`** gains the same two new props (`poster` →
16
+ `<video poster>`; `playbackLabel` → the playback-session registration,
17
+ defaulting to `alt` then "Media file" as before). `autoPlay`/`playsInline`
18
+ already existed there.
19
+
20
+ ## 0.2.0 — 2026-08-29
21
+
22
+ **THE SHARE MANDATE row is satisfied (wave M-SHARE, ruling C19).** The
23
+ share-popover BODIES land, additively, through the exact `MediaActionsPort` /
24
+ `SharePopover` contract 0.1.0 reserved for them — no breaking change, no
25
+ change to any existing entry's surface.
26
+
27
+ - **New entry `@ai-matrx/media/share`** (`"use client"` group):
28
+ - `MediaSharePopover` — the complete share body, ported from the canonical
29
+ matrx-frontend share flows (`ImageSharePopover` / `VideoSharePopover` —
30
+ ONE share mechanism) with the seams inverted:
31
+ - the public-link path (permanent CDN URL for public files, else
32
+ reuse-or-mint a no-expiry read-only share link) rides the ONE
33
+ `MediaClient.shareableUrl` door, asked on click; `null` **fails
34
+ closed** (law 4) and renders as inline error state;
35
+ - external refs get the simplified copy-external-link surface
36
+ (`shareableUrl` prefetched — pure classification there);
37
+ - "Manage all links" → the `manageLinks` host callback and the access
38
+ summary → the `AccessSummary` host slot (both iam surfaces are app
39
+ content per C8; rows/sections hide when unbound);
40
+ - toasts → the optional `notify` adapter; every failure ALSO renders
41
+ inline so no outcome is silent without one;
42
+ - **association affordances** ("Linked to" rows with live titles +
43
+ detach, "Attach to…" universal search + attach) consume
44
+ `@ai-matrx/associations` strictly through its public
45
+ provider/hooks surface, and degrade to ABSENT when no
46
+ `AssociationsProvider` is mounted.
47
+ - `createMediaSharePopover(options)` — binds the host-shaped options once
48
+ and returns a component matching the `SharePopover` slot exactly; the
49
+ tarball canary compiles that assignment with no cast.
50
+ - **Dependency direction:** `@ai-matrx/associations` is an **OPTIONAL peer**
51
+ (`>=0.4.0`) carried ONLY by `/share` — a media consumer of `.`, `/core`,
52
+ or `/react` never installs it (C8). Upgrading associations requires no
53
+ media release: the popover reaches it through the host-mounted provider.
54
+ - Six new inlined SVG glyphs (lucide v1.22.0: globe, link-2, settings-2,
55
+ loader-circle, plus, search) per C19 — still no icon library.
56
+ - Gates extended: the five-laws source scan covers the new files
57
+ automatically; `verify:tarball` now installs the PUBLISHED associations +
58
+ design-system packages and imports/requires `/share` from the packed
59
+ artifact, renders it without a provider (degradation proof), and
60
+ type-checks the no-cast `SharePopover` slot assignment.
61
+
62
+ **Deliberate divergences from the origin popovers** (seam-forced, not
63
+ defects): the three public-link label states ("Copy" vs "Create + copy",
64
+ CDN-vs-link sublabels) collapse to one label — link inventory lives behind
65
+ the host's `shareableUrl`; the mobile Drawer/desktop Popover split stays with
66
+ the shells/hosts (this is the BODY, positioned by its opener); the
67
+ `ShareLinkDialog` itself remains host content (C8) behind `manageLinks`.
68
+
3
69
  ## 0.1.1 — 2026-08-29
4
70
 
5
71
  Types-only fix; runtime behavior unchanged.
package/README.md CHANGED
@@ -15,6 +15,7 @@ correct path is the only path the types allow.
15
15
  @ai-matrx/media types only — MediaRef, DurableSrc, MediaClient, host ports
16
16
  @ai-matrx/media/core headless React hooks (platform-free state machines)
17
17
  @ai-matrx/media/react DOM components (Tailwind classes, inlined SVG icons)
18
+ @ai-matrx/media/share the complete share popover body (optional peer: @ai-matrx/associations)
18
19
  ```
19
20
 
20
21
  ## The rules the types enforce
@@ -86,6 +87,42 @@ without touching this package.
86
87
  </MediaProvider>
87
88
  ```
88
89
 
90
+ ### The complete share body (`/share`)
91
+
92
+ `/share` ships the popover BODY the slot was reserved for — the canonical
93
+ Matrx share experience:
94
+
95
+ - **Copy public link** — one click asks `MediaClient.shareableUrl(ref)` for
96
+ the truly-permanent URL (the host's implementation reuses or mints a
97
+ no-expiry share link, or returns the permanent CDN URL for public files)
98
+ and copies it. `null` fails closed — never a signed URL.
99
+ - **External refs** get the simplified surface: the safe external URL or a
100
+ disabled row.
101
+ - **Manage all links** / **who-can-see-this** are host slots
102
+ (`manageLinks` callback, `AccessSummary` component) — link inventory and
103
+ reachability live with the host's iam surfaces.
104
+ - **Linked to / Attach to…** — the association affordances, riding
105
+ `@ai-matrx/associations` through its public hooks. They light up when an
106
+ `AssociationsProvider` is mounted above and degrade to absent when not.
107
+
108
+ ```tsx
109
+ import { createMediaSharePopover } from "@ai-matrx/media/share";
110
+
111
+ const SharePopover = createMediaSharePopover({
112
+ manageLinks: (ctx) => openShareLinkDialog(ctx), // optional
113
+ AccessSummary, // optional host panel
114
+ notify: { success: toast.success, error: toast.error }, // optional
115
+ });
116
+
117
+ <MediaProvider client={client} ports={{ actions: { SharePopover, download, copy } }}>
118
+ {/* every toolbar/lightbox now opens the full share experience */}
119
+ </MediaProvider>
120
+ ```
121
+
122
+ Only `/share` carries the `@ai-matrx/associations` peer (optional — install
123
+ it, plus `@ai-matrx/design-system` which its `/react` entry loads, to use
124
+ this entry). The other entries never do.
125
+
89
126
  ## Styling
90
127
 
91
128
  `/react` uses Tailwind utility classes with semantic tokens (`bg-muted`,
@@ -97,9 +134,9 @@ without touching this package.
97
134
 
98
135
  ## SSR / RSC
99
136
 
100
- The root entry is server-safe (types + one pure function). `/core` and
101
- `/react` are client modules (`"use client"` is stamped per entry). Nothing
102
- touches `window` at import time.
137
+ The root entry is server-safe (types + one pure function). `/core`, `/react`
138
+ and `/share` are client modules (`"use client"` is stamped per entry).
139
+ Nothing touches `window` at import time.
103
140
 
104
141
  ## License
105
142
 
package/dist/react.cjs CHANGED
@@ -42,16 +42,22 @@ __export(react_exports, {
42
42
  FileVideoIcon: () => FileVideoIcon,
43
43
  FolderIcon: () => FolderIcon,
44
44
  FolderOpenIcon: () => FolderOpenIcon,
45
+ GlobeIcon: () => GlobeIcon,
45
46
  ImageIcon: () => ImageIcon,
46
47
  ImageOffIcon: () => ImageOffIcon,
47
48
  InlineMediaRef: () => InlineMediaRef,
49
+ Link2Icon: () => Link2Icon,
48
50
  MediaActionToolbar: () => MediaActionToolbar,
49
51
  MediaLightbox: () => MediaLightbox,
50
52
  MediaThumbnail: () => MediaThumbnail,
51
53
  MusicIcon: () => MusicIcon,
52
54
  PackageBoxIcon: () => PackageBoxIcon,
53
55
  PenToolIcon: () => PenToolIcon,
56
+ PlusIcon: () => PlusIcon,
57
+ SearchIcon: () => SearchIcon,
58
+ Settings2Icon: () => Settings2Icon,
54
59
  Share2Icon: () => Share2Icon,
60
+ SpinnerIcon: () => SpinnerIcon,
55
61
  SubtitlesIcon: () => SubtitlesIcon,
56
62
  UploadIcon: () => UploadIcon,
57
63
  UploadProgressList: () => UploadProgressList,
@@ -308,6 +314,43 @@ function CheckCircle2Icon(props) {
308
314
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 11 3 3L22 4" })
309
315
  ] });
310
316
  }
317
+ function GlobeIcon(props) {
318
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgProps(props), children: [
319
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 12h20" })
322
+ ] });
323
+ }
324
+ function Link2Icon(props) {
325
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgProps(props), children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 17H7A5 5 0 0 1 7 7h2" }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 7h2a5 5 0 1 1 0 10h-2" }),
328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", x2: "16", y1: "12", y2: "12" })
329
+ ] });
330
+ }
331
+ function Settings2Icon(props) {
332
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgProps(props), children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 7h-9" }),
334
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 17H5" }),
335
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "17", cy: "17", r: "3" }),
336
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "7", cy: "7", r: "3" })
337
+ ] });
338
+ }
339
+ function SpinnerIcon(props) {
340
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
341
+ }
342
+ function PlusIcon(props) {
343
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgProps(props), children: [
344
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 12h14" }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5v14" })
346
+ ] });
347
+ }
348
+ function SearchIcon(props) {
349
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgProps(props), children: [
350
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21 21-4.3-4.3" })
352
+ ] });
353
+ }
311
354
 
312
355
  // src/core/file-kind.ts
313
356
  var ROWS = [
@@ -895,6 +938,8 @@ function InlineMediaRef({
895
938
  playsInline,
896
939
  preload,
897
940
  controlsList,
941
+ poster,
942
+ playbackLabel,
898
943
  rounded = "md",
899
944
  onClick,
900
945
  onError,
@@ -938,7 +983,7 @@ function InlineMediaRef({
938
983
  {
939
984
  isPlaying: isMediaPlaying,
940
985
  source: "file-media",
941
- label: alt || "Media file",
986
+ label: playbackLabel ?? (alt || "Media file"),
942
987
  trackKey
943
988
  },
944
989
  sessionElRef
@@ -1079,6 +1124,7 @@ function InlineMediaRef({
1079
1124
  playsInline,
1080
1125
  preload,
1081
1126
  controlsList,
1127
+ poster,
1082
1128
  onLoadedData: onLoad,
1083
1129
  onError: handleLoadError,
1084
1130
  crossOrigin,
@@ -2037,6 +2083,10 @@ function MediaLightbox({
2037
2083
  fileName,
2038
2084
  alt,
2039
2085
  as,
2086
+ autoPlay,
2087
+ playsInline,
2088
+ poster,
2089
+ playbackLabel,
2040
2090
  actions,
2041
2091
  hideUnavailableActions = false,
2042
2092
  headerExtra,
@@ -2115,7 +2165,11 @@ function MediaLightbox({
2115
2165
  fit: "contain",
2116
2166
  rounded: "none",
2117
2167
  alt: alt ?? fileName ?? "",
2118
- as
2168
+ as,
2169
+ autoPlay,
2170
+ playsInline,
2171
+ poster,
2172
+ playbackLabel
2119
2173
  }
2120
2174
  ) })
2121
2175
  }