@openrails/contentkit-ui 0.98.0 → 0.98.3

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/README.md CHANGED
@@ -51,7 +51,7 @@ const urls = createContentURLs({ routes: { video: "watch", gallery: "g" }, langu
51
51
  onChange={(change) => queryClient.invalidateQueries({ queryKey: ["media", change.ref.id] })}
52
52
  onError={(error, { operation }) => report(operation, error)}
53
53
  >
54
- <ContentKitUiProvider appearance={{ theme: "inherit" }} language={lang} density={[2, 3]}>
54
+ <ContentKitUiProvider appearance={{ theme: "inherit" }} language={lang} density={[1, 3]}>
55
55
  <App />
56
56
  </ContentKitUiProvider>
57
57
  </ContentKitProvider>;
@@ -123,7 +123,7 @@ operation. This does not change the operation's result or its authentication.
123
123
  - **`ContentKitUiProvider`**: `appearance` (`theme`
124
124
  `light`/`dark`/`auto`/`inherit`, `variables` as `--ckui-*`), `language`
125
125
  (loads its built-in bundle), `messages` (bundles over it), `t` (host
126
- translate hook), `density` (default `[2, 3]`), `inlinePreview` (default true).
126
+ translate hook), `density` (default `[1, 3]`), `inlinePreview` (default true).
127
127
 
128
128
  ## Hooks
129
129
 
@@ -319,11 +319,12 @@ Plain-text entities sit directly below the cover, followed by other metadata.
319
319
  metadata={{ languages: false, traits: ["colored"], duration: false }} />
320
320
  ```
321
321
 
322
- Set `grid={{ minCardWidth: 320, mobileColumns: 2 }}` for large covers in a fluid
322
+ Set `grid={{ minCardWidth: 240, mobileColumns: 2, maxColumns: 10 }}` for covers in a fluid
323
323
  grid: two columns on small screens, then as many columns as the available
324
324
  width supports. This is supported by card grids, daily releases, Popular and
325
- `ContentRail` previews; an unconfigured rail remains horizontal. There is no
326
- desktop column ceiling, and other apps keep their existing layout by default.
325
+ `ContentRail` previews; an unconfigured rail remains horizontal. `maxColumns`
326
+ is optional: omit it for no desktop column ceiling. Other apps keep their
327
+ existing layout by default.
327
328
 
328
329
  `ContentGrid` and `ContentListing` take `locked`: `show` (default) marks the
329
330
  cards the reader doesn't open, `hide` leaves them out, and `collapse` lists
@@ -5,7 +5,7 @@ export interface Rendition {
5
5
  h?: number;
6
6
  url: string;
7
7
  }
8
- /** Device-pixel density range renditions target: even 1× screens get 2×, 3× phones 3×. */
8
+ /** Device-pixel density range renditions target: native density, up to 3×. */
9
9
  export type DensityRange = readonly [min: number, max: number];
10
10
  export declare const DEFAULT_DENSITY: DensityRange;
11
11
  /** devicePixelRatio clamped into range. */
@@ -1,5 +1,5 @@
1
1
  //#region src/client/rendition.ts
2
- var e = [2, 3];
2
+ var e = [1, 3];
3
3
  function t(t = e, n = typeof devicePixelRatio == "number" ? devicePixelRatio : 1) {
4
4
  return Math.min(t[1], Math.max(t[0], n || 1));
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rendition.js","names":[],"sources":["../../src/client/rendition.ts"],"sourcesContent":["/** One rendered width of an image, e.g. a public preset's file at one of its widths. */\nexport interface Rendition {\n w: number;\n /** Its height when known (the preset's aspect). */\n h?: number;\n url: string;\n}\n\n/** Device-pixel density range renditions target: even 1× screens get 2×, 3× phones 3×. */\nexport type DensityRange = readonly [min: number, max: number];\n\nexport const DEFAULT_DENSITY: DensityRange = [2, 3];\n\n/** devicePixelRatio clamped into range. */\nexport function densityFor(range: DensityRange = DEFAULT_DENSITY, dpr = typeof devicePixelRatio === \"number\" ? devicePixelRatio : 1): number {\n return Math.min(range[1], Math.max(range[0], dpr || 1));\n}\n\n/** Renditions with a URL and width, narrowest first. */\nexport function sortRenditions<T extends Rendition>(outputs: readonly T[] | null | undefined): T[] {\n return [...(outputs ?? [])].filter((o) => o.url && o.w > 0).sort((a, b) => a.w - b.w);\n}\n\n/**\n * The narrowest rendition at least cssWidth × density device pixels wide\n * (the widest when none is), e.g. 400 CSS px at 2× picks ≥ 800 px.\n */\nexport function pickRendition<T extends Rendition>(outputs: readonly T[] | null | undefined, cssWidth: number, density = densityFor()): T | undefined {\n const sorted = sortRenditions(outputs);\n const want = cssWidth * density;\n return sorted.find((o) => o.w >= want) ?? sorted.at(-1);\n}\n"],"mappings":";AAWA,IAAa,IAAgC,CAAC,GAAG,CAAC;AAGlD,SAAgB,EAAW,IAAsB,GAAiB,IAAM,OAAO,oBAAqB,WAAW,mBAAmB,GAAW;CAC3I,OAAO,KAAK,IAAI,EAAM,IAAI,KAAK,IAAI,EAAM,IAAI,KAAO,CAAC,CAAC;AACxD;AAGA,SAAgB,EAAoC,GAA+C;CACjG,OAAO,CAAC,GAAI,KAAW,CAAC,CAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACtF;AAMA,SAAgB,EAAmC,GAA0C,GAAkB,IAAU,EAAW,GAAkB;CACpJ,IAAM,IAAS,EAAe,CAAO,GAC/B,IAAO,IAAW;CACxB,OAAO,EAAO,MAAM,MAAM,EAAE,KAAK,CAAI,KAAK,EAAO,GAAG,EAAE;AACxD"}
1
+ {"version":3,"file":"rendition.js","names":[],"sources":["../../src/client/rendition.ts"],"sourcesContent":["/** One rendered width of an image, e.g. a public preset's file at one of its widths. */\nexport interface Rendition {\n w: number;\n /** Its height when known (the preset's aspect). */\n h?: number;\n url: string;\n}\n\n/** Device-pixel density range renditions target: native density, up to 3×. */\nexport type DensityRange = readonly [min: number, max: number];\n\nexport const DEFAULT_DENSITY: DensityRange = [1, 3];\n\n/** devicePixelRatio clamped into range. */\nexport function densityFor(range: DensityRange = DEFAULT_DENSITY, dpr = typeof devicePixelRatio === \"number\" ? devicePixelRatio : 1): number {\n return Math.min(range[1], Math.max(range[0], dpr || 1));\n}\n\n/** Renditions with a URL and width, narrowest first. */\nexport function sortRenditions<T extends Rendition>(outputs: readonly T[] | null | undefined): T[] {\n return [...(outputs ?? [])].filter((o) => o.url && o.w > 0).sort((a, b) => a.w - b.w);\n}\n\n/**\n * The narrowest rendition at least cssWidth × density device pixels wide\n * (the widest when none is), e.g. 400 CSS px at 2× picks ≥ 800 px.\n */\nexport function pickRendition<T extends Rendition>(outputs: readonly T[] | null | undefined, cssWidth: number, density = densityFor()): T | undefined {\n const sorted = sortRenditions(outputs);\n const want = cssWidth * density;\n return sorted.find((o) => o.w >= want) ?? sorted.at(-1);\n}\n"],"mappings":";AAWA,IAAa,IAAgC,CAAC,GAAG,CAAC;AAGlD,SAAgB,EAAW,IAAsB,GAAiB,IAAM,OAAO,oBAAqB,WAAW,mBAAmB,GAAW;CAC3I,OAAO,KAAK,IAAI,EAAM,IAAI,KAAK,IAAI,EAAM,IAAI,KAAO,CAAC,CAAC;AACxD;AAGA,SAAgB,EAAoC,GAA+C;CACjG,OAAO,CAAC,GAAI,KAAW,CAAC,CAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACtF;AAMA,SAAgB,EAAmC,GAA0C,GAAkB,IAAU,EAAW,GAAkB;CACpJ,IAAM,IAAS,EAAe,CAAO,GAC/B,IAAO,IAAW;CACxB,OAAO,EAAO,MAAM,MAAM,EAAE,KAAK,CAAI,KAAK,EAAO,GAAG,EAAE;AACxD"}
@@ -1,14 +1,17 @@
1
1
  import { CSSProperties, ReactNode } from 'react';
2
2
  import { Card, CardAccess, Chip as EntityChip } from '../../client/generated/wire.js';
3
+ import { ContentKitClient } from '../../client/client.js';
3
4
  import { Translator } from '../../i18n/messages.js';
4
5
  import { GroupLike, Labels } from '../groups/parts.js';
5
6
  export interface ContentCardProps {
6
7
  card: Card;
8
+ /** Overrides the provider's client for this card's public media configuration. */
9
+ client?: ContentKitClient;
7
10
  /** The card's link; default its canonical path. */
8
11
  href?: (card: Card) => string | undefined;
9
12
  /** Before the card's link is followed: a click signal. */
10
13
  onOpen?: (card: Card) => void;
11
- /** Cover shape: "portrait" (3:4, readers) or "landscape" (16:9, players). Default portrait. */
14
+ /** Fallback cover shape when the server declares no preset aspect. Default portrait (3:4). */
12
15
  shape?: "portrait" | "landscape";
13
16
  /** A CSS aspect ratio overriding shape, such as "182 / 260". */
14
17
  aspectRatio?: CSSProperties["aspectRatio"];
@@ -24,6 +27,8 @@ export interface ContentCardProps {
24
27
  filterEntity?: (entity: EntityChip, kind: string) => boolean;
25
28
  /** Bordered chips (default) or plain linked text. */
26
29
  entityStyle?: "chips" | "text";
30
+ /** One inline list (default), or a separate row for each group kind. */
31
+ entityLayout?: "inline" | "rows";
27
32
  /** Metadata fields to show; omitted fields keep their defaults. */
28
33
  metadata?: CardMetadata;
29
34
  /** Show like and favorite totals. Default true. */
@@ -52,7 +57,7 @@ export interface CardMetadata {
52
57
  /** Why a card is locked, in words (its price when it is on sale); null when it opens. */
53
58
  export declare function lockLabel(m: Translator, a: CardAccess, tiers?: readonly string[], labels?: Labels): string | null;
54
59
  /** One content in a listing: cover (a video the reader opens previews over it on hover), title, version, groups, counts, the reader's progress and why it is locked; what its kind's locked view hides is absent. */
55
- export declare function ContentCard({ card, href, onOpen, shape, aspectRatio, titlePosition, loadMedia, groupKinds, chips, filterEntity, entityStyle, metadata, showCounts, tiers, labels, owner, ownerHref, decorate, children, className }: ContentCardProps): import('react').JSX.Element;
60
+ export declare function ContentCard({ card, client, href, onOpen, shape, aspectRatio, titlePosition, loadMedia, groupKinds, chips, filterEntity, entityStyle, entityLayout, metadata, showCounts, tiers, labels, owner, ownerHref, decorate, children, className }: ContentCardProps): import('react').JSX.Element;
56
61
  /** The group that owns a content (a channel): its avatar and name, linking to its page. */
57
62
  export declare function OwnerChip({ group, href, className, loadMedia }: {
58
63
  group: GroupLike;
@@ -60,7 +65,7 @@ export declare function OwnerChip({ group, href, className, loadMedia }: {
60
65
  className?: string;
61
66
  loadMedia?: boolean;
62
67
  }): import('react').JSX.Element;
63
- export interface PostCardProps extends Omit<ContentCardProps, "shape" | "aspectRatio" | "titlePosition" | "chips" | "groupKinds" | "filterEntity" | "entityStyle" | "metadata"> {
68
+ export interface PostCardProps extends Omit<ContentCardProps, "shape" | "aspectRatio" | "titlePosition" | "chips" | "groupKinds" | "filterEntity" | "entityStyle" | "entityLayout" | "metadata"> {
64
69
  /** Above the title: the post's channel or author; default its owner group's chip. */
65
70
  byline?: ReactNode;
66
71
  }