@datocms/astro 0.1.12 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,52 +1,62 @@
1
1
  {
2
- "name": "@datocms/astro",
3
- "description": "A set of components and utilities to work faster with DatoCMS in Astro projects.",
4
- "type": "module",
5
- "version": "0.1.12",
6
- "sideEffects": false,
7
- "repository": {
8
- "type": "git",
9
- "url": "git://github.com/datocms/astro-datocms.git"
10
- },
11
- "homepage": "https://github.com/datocms/astro-datocms",
12
- "license": "MIT",
13
- "author": "Stefano Verna <s.verna@datocms.com>",
14
- "contributors": ["Silvano Stralla <silvano@datocms.com>"],
15
- "keywords": [
16
- "astro",
17
- "withastro",
18
- "astro-component",
19
- "datocms",
20
- "typescript",
21
- "ui"
22
- ],
23
- "exports": {
24
- "./useVideoPlayer": "./src/useVideoPlayer/index.ts",
25
- "./VideoPlayer": "./src/VideoPlayer/index.ts",
26
- "./Image": "./src/Image/index.ts",
27
- "./StructuredText": "./src/StructuredText/index.ts",
28
- "./Seo": "./src/Seo/index.ts"
29
- },
30
- "engines": {
31
- "node": ">=18.0.0"
32
- },
33
- "files": ["src"],
34
- "dependencies": {
35
- "@mux/playback-core": "^0.25.1",
36
- "datocms-structured-text-utils": "^4.0.1",
37
- "typescript": "^5.5.4"
38
- },
39
- "peerDependencies": {
40
- "@mux/mux-player": "*",
41
- "astro": "*"
42
- },
43
- "peerDependenciesMeta": {
44
- "@mux/mux-player": {
45
- "optional": true
46
- }
47
- },
48
- "devDependencies": {
49
- "@mux/mux-player": "*",
50
- "astro": "^4.13.1"
51
- }
2
+ "name": "@datocms/astro",
3
+ "description": "A set of components and utilities to work faster with DatoCMS in Astro projects.",
4
+ "type": "module",
5
+ "version": "0.2.0",
6
+ "sideEffects": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git://github.com/datocms/astro-datocms.git"
10
+ },
11
+ "homepage": "https://github.com/datocms/astro-datocms",
12
+ "license": "MIT",
13
+ "author": "Stefano Verna <s.verna@datocms.com>",
14
+ "contributors": [
15
+ "Silvano Stralla <silvano@datocms.com>"
16
+ ],
17
+ "keywords": [
18
+ "astro",
19
+ "withastro",
20
+ "astro-component",
21
+ "datocms",
22
+ "typescript",
23
+ "ui"
24
+ ],
25
+ "scripts": {
26
+ "prepare": "npx simple-git-hooks",
27
+ "lint": "prettier --check .",
28
+ "format": "npx prettier . --write",
29
+ "test": "echo 1"
30
+ },
31
+ "exports": {
32
+ "./Image": "./src/Image/index.ts",
33
+ "./StructuredText": "./src/StructuredText/index.ts",
34
+ "./Seo": "./src/Seo/index.ts",
35
+ "./QueryListener": "./src/QueryListener/index.ts"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ },
40
+ "files": [
41
+ "src"
42
+ ],
43
+ "dependencies": {
44
+ "@0no-co/graphql.web": "^1.0.7",
45
+ "datocms-listen": "^1.0.0",
46
+ "datocms-structured-text-utils": "^4.0.1"
47
+ },
48
+ "peerDependencies": {
49
+ "astro": "*"
50
+ },
51
+ "devDependencies": {
52
+ "astro": "^4.13.1",
53
+ "np": "^10.0.7",
54
+ "prettier": "^3.3.3",
55
+ "prettier-plugin-astro": "^0.14.1",
56
+ "simple-git-hooks": "^2.11.1",
57
+ "typescript": "^5.5.4"
58
+ },
59
+ "simple-git-hooks": {
60
+ "pre-commit": "npm run format"
61
+ }
52
62
  }
@@ -1,9 +1,8 @@
1
1
  ---
2
-
3
2
  import { buildSrcSet } from './buildSrcSet';
4
3
  import type { ImageProps } from './types';
5
4
 
6
- interface Props extends ImageProps {};
5
+ interface Props extends ImageProps {}
7
6
 
8
7
  const {
9
8
  data,
@@ -21,52 +20,45 @@ const placeholderStyle =
21
20
  usePlaceholder && data.base64
22
21
  ? {
23
22
  backgroundImage: `url("${data.base64}")`,
24
- backgroundSize: "cover",
25
- backgroundRepeat: "no-repeat",
26
- backgroundPosition: "50% 50%",
27
- color: "transparent",
23
+ backgroundSize: 'cover',
24
+ backgroundRepeat: 'no-repeat',
25
+ backgroundPosition: '50% 50%',
26
+ color: 'transparent',
28
27
  }
29
28
  : usePlaceholder && data.bgColor
30
- ? { backgroundColor: data.bgColor ?? undefined, color: "transparent" }
29
+ ? { backgroundColor: data.bgColor ?? undefined, color: 'transparent' }
31
30
  : undefined;
32
31
 
33
32
  const { width } = data;
34
33
 
35
- const height =
36
- data.height ?? Math.round(data.aspectRatio ? width / data.aspectRatio : 0);
34
+ const height = data.height ?? Math.round(data.aspectRatio ? width / data.aspectRatio : 0);
37
35
 
38
36
  const sizingStyle = {
39
37
  aspectRatio: `${width} / ${height}`,
40
- width: "100%",
38
+ width: '100%',
41
39
  maxWidth: `${width}px`,
42
- height: "auto",
40
+ height: 'auto',
43
41
  };
44
42
  ---
45
43
 
46
44
  <picture class={pictureClass} style={pictureStyle}>
47
45
  {
48
46
  data.webpSrcSet && (
49
- <source
50
- srcset={data.webpSrcSet}
51
- sizes={sizes ?? data.sizes ?? null}
52
- type="image/webp"
53
- />
47
+ <source srcset={data.webpSrcSet} sizes={sizes ?? data.sizes ?? null} type="image/webp" />
54
48
  )
55
49
  }
56
50
  <source
57
- srcset={data.srcSet ??
58
- buildSrcSet(data.src, data.width, srcSetCandidates) ??
59
- null}
51
+ srcset={data.srcSet ?? buildSrcSet(data.src, data.width, srcSetCandidates) ?? null}
60
52
  sizes={sizes ?? data.sizes ?? null}
61
53
  />
62
54
  {
63
55
  data.src && (
64
56
  <img
65
57
  src={data.src}
66
- alt={data.alt ?? ""}
58
+ alt={data.alt ?? ''}
67
59
  title={data.title ?? null}
68
- fetchpriority={priority ? "high" : undefined}
69
- loading={priority ? undefined : "lazy"}
60
+ fetchpriority={priority ? 'high' : undefined}
61
+ loading={priority ? undefined : 'lazy'}
70
62
  class={imgClass}
71
63
  style={{
72
64
  ...placeholderStyle,
@@ -1,10 +1,9 @@
1
-
2
- const bogusBaseUrl = "https://example.com/";
1
+ const bogusBaseUrl = 'https://example.com/';
3
2
 
4
3
  export const buildSrcSet = (
5
4
  src: string | null | undefined,
6
5
  width: number | undefined,
7
- candidateMultipliers: number[]
6
+ candidateMultipliers: number[],
8
7
  ) => {
9
8
  if (!(src && width)) {
10
9
  return undefined;
@@ -15,20 +14,14 @@ export const buildSrcSet = (
15
14
  const url = new URL(src, bogusBaseUrl);
16
15
 
17
16
  if (multiplier !== 1) {
18
- url.searchParams.set("dpr", `${multiplier}`);
19
- const maxH = url.searchParams.get("max-h");
20
- const maxW = url.searchParams.get("max-w");
17
+ url.searchParams.set('dpr', `${multiplier}`);
18
+ const maxH = url.searchParams.get('max-h');
19
+ const maxW = url.searchParams.get('max-w');
21
20
  if (maxH) {
22
- url.searchParams.set(
23
- "max-h",
24
- `${Math.floor(Number.parseInt(maxH) * multiplier)}`
25
- );
21
+ url.searchParams.set('max-h', `${Math.floor(Number.parseInt(maxH) * multiplier)}`);
26
22
  }
27
23
  if (maxW) {
28
- url.searchParams.set(
29
- "max-w",
30
- `${Math.floor(Number.parseInt(maxW) * multiplier)}`
31
- );
24
+ url.searchParams.set('max-w', `${Math.floor(Number.parseInt(maxW) * multiplier)}`);
32
25
  }
33
26
  }
34
27
 
@@ -38,8 +31,8 @@ export const buildSrcSet = (
38
31
  return null;
39
32
  }
40
33
 
41
- return `${url.toString().replace(bogusBaseUrl, "/")} ${finalWidth}w`;
34
+ return `${url.toString().replace(bogusBaseUrl, '/')} ${finalWidth}w`;
42
35
  })
43
36
  .filter(Boolean)
44
- .join(",");
37
+ .join(',');
45
38
  };
@@ -1,2 +1,2 @@
1
- import Image from "./Image.astro";
1
+ import Image from './Image.astro';
2
2
  export { Image };
@@ -56,11 +56,11 @@ export type ImageProps = {
56
56
  * -> https://web.dev/learn/design/responsive-images/#sizes
57
57
  * -> https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
58
58
  **/
59
- sizes?: HTMLImageElement["sizes"];
59
+ sizes?: HTMLImageElement['sizes'];
60
60
  /**
61
61
  * If `data` does not contain `srcSet`, the candidates for the `srcset` of the image will be auto-generated based on these width multipliers
62
62
  *
63
63
  * Default candidate multipliers are [0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4]
64
64
  **/
65
65
  srcSetCandidates?: number[];
66
- }
66
+ };
@@ -0,0 +1,56 @@
1
+ ---
2
+ import type { QueryListenerOptions } from './types';
3
+ import { print } from '@0no-co/graphql.web';
4
+
5
+ type Props<QueryResult, QueryVariables> = QueryListenerOptions<QueryResult, QueryVariables>;
6
+
7
+ const { query, ...rest } = Astro.props;
8
+
9
+ const stringifiedQuery = typeof query === 'object' ? print(query) : query;
10
+ ---
11
+
12
+ <datocms-query-listener data-config={JSON.stringify({ ...rest, query: stringifiedQuery })}>
13
+ </datocms-query-listener>
14
+
15
+ <script>
16
+ import { subscribeToQuery as subscribeToQueryFn } from 'datocms-listen';
17
+ import type { QueryListenerOptions } from './types';
18
+
19
+ class QueryListener extends HTMLElement {
20
+ config: QueryListenerOptions<unknown, unknown>;
21
+ updatesReceived: number = 0;
22
+
23
+ constructor() {
24
+ super();
25
+
26
+ if (!this.dataset.config) {
27
+ throw new Error('Missing config');
28
+ }
29
+
30
+ this.config = JSON.parse(this.dataset.config);
31
+
32
+ import('datocms-listen').then(({ subscribeToQuery }) => {
33
+ this.run(subscribeToQuery);
34
+ });
35
+ }
36
+
37
+ run(subscribeToQuery: typeof subscribeToQueryFn) {
38
+ subscribeToQuery<unknown, unknown>({
39
+ ...this.config,
40
+ onUpdate: () => {
41
+ this.updatesReceived += 1;
42
+
43
+ if (this.updatesReceived > 1) {
44
+ document.location.reload();
45
+ }
46
+ },
47
+ onChannelError: (error) => {
48
+ console.error('[QueryListener]', error);
49
+ },
50
+ });
51
+ }
52
+ }
53
+
54
+ // Tell the browser to use our AstroHeart class for <astro-heart> elements.
55
+ customElements.define('datocms-query-listener', QueryListener);
56
+ </script>
@@ -0,0 +1,3 @@
1
+ import QueryListener from './QueryListener.astro';
2
+
3
+ export { QueryListener };
@@ -0,0 +1,12 @@
1
+ import type { Options } from 'datocms-listen';
2
+
3
+ export type QueryListenerOptions<QueryResult, QueryVariables> = Omit<
4
+ Options<QueryResult, QueryVariables>,
5
+ | 'onStatusChange'
6
+ | 'onUpdate'
7
+ | 'onChannelError'
8
+ | 'onError'
9
+ | 'onEvent'
10
+ | 'fetcher'
11
+ | 'eventSourceClass'
12
+ >;
package/src/Seo/Seo.astro CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
- import { renderMetaTagsToString } from "./renderMetaTagsToString";
3
- import type { SeoOrFaviconTag, TitleMetaLinkTag } from "./types";
2
+ import { renderMetaTagsToString } from './renderMetaTagsToString';
3
+ import type { SeoOrFaviconTag, TitleMetaLinkTag } from './types';
4
4
 
5
5
  interface Props {
6
6
  data: TitleMetaLinkTag[] | SeoOrFaviconTag[];
package/src/Seo/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- import Seo from "./Seo.astro";
2
- export * from "./renderMetaTagsToString.js";
3
- export * from "./types.js";
1
+ import Seo from './Seo.astro';
2
+ export * from './renderMetaTagsToString.js';
3
+ export * from './types.js';
4
4
 
5
5
  export { Seo };
@@ -1,8 +1,6 @@
1
1
  import type { SeoOrFaviconTag, TitleMetaLinkTag } from './types.js';
2
2
 
3
- export function renderMetaTagsToString(
4
- data: TitleMetaLinkTag[] | SeoOrFaviconTag[],
5
- ): string {
3
+ export function renderMetaTagsToString(data: TitleMetaLinkTag[] | SeoOrFaviconTag[]): string {
6
4
  return data
7
5
  .map((tag) => {
8
6
  if (tag.tag === 'title') {
package/src/Seo/types.ts CHANGED
@@ -55,8 +55,7 @@ export type SeoOrFaviconTag = SeoTag | FaviconTag;
55
55
  export const isSeoTitleTag = (tag: any): tag is SeoTitleTag =>
56
56
  'tag' in tag && tag.tag === 'title' && !tag.attributes;
57
57
 
58
- export const isSeoTag = (tag: any): tag is SeoTag =>
59
- isSeoTitleTag(tag) || isSeoMetaTag(tag);
58
+ export const isSeoTag = (tag: any): tag is SeoTag => isSeoTitleTag(tag) || isSeoMetaTag(tag);
60
59
 
61
60
  export const isFaviconAttributes = (tag: any): tag is FaviconAttributes =>
62
61
  'sizes' in tag &&
@@ -68,9 +67,7 @@ export const isFaviconAttributes = (tag: any): tag is FaviconAttributes =>
68
67
  'href' in tag &&
69
68
  typeof tag.href === 'string';
70
69
 
71
- export const isAppleTouchIconAttributes = (
72
- tag: any,
73
- ): tag is AppleTouchIconAttributes =>
70
+ export const isAppleTouchIconAttributes = (tag: any): tag is AppleTouchIconAttributes =>
74
71
  'sizes' in tag &&
75
72
  typeof tag.sizes === 'string' &&
76
73
  'rel' in tag &&
@@ -82,32 +79,24 @@ export const isSeoLinkTag = (tag: any): tag is SeoLinkTag =>
82
79
  'tag' in tag &&
83
80
  tag.tag === 'link' &&
84
81
  !tag.content &&
85
- (isFaviconAttributes(tag.attributes) ||
86
- isAppleTouchIconAttributes(tag.attributes));
82
+ (isFaviconAttributes(tag.attributes) || isAppleTouchIconAttributes(tag.attributes));
87
83
 
88
- export const isFaviconTag = (tag: any): tag is FaviconTag =>
89
- isSeoMetaTag(tag) || isSeoLinkTag(tag);
84
+ export const isFaviconTag = (tag: any): tag is FaviconTag => isSeoMetaTag(tag) || isSeoLinkTag(tag);
90
85
 
91
86
  export const isSeoOrFaviconTag = (
92
87
  seoOrFaviconTag: TitleMetaLinkTag | SeoOrFaviconTag,
93
- ): seoOrFaviconTag is SeoOrFaviconTag =>
94
- isSeoTag(seoOrFaviconTag) || isFaviconTag(seoOrFaviconTag);
88
+ ): seoOrFaviconTag is SeoOrFaviconTag => isSeoTag(seoOrFaviconTag) || isFaviconTag(seoOrFaviconTag);
95
89
 
96
90
  export const isRegularMetaAttributes = (
97
91
  attributes: RegularMetaAttributes | OgMetaAttributes,
98
- ): attributes is RegularMetaAttributes =>
99
- 'name' in attributes && 'content' in attributes;
92
+ ): attributes is RegularMetaAttributes => 'name' in attributes && 'content' in attributes;
100
93
 
101
94
  export const isOgMetaAttributes = (
102
95
  attributes: RegularMetaAttributes | OgMetaAttributes,
103
- ): attributes is OgMetaAttributes =>
104
- 'property' in attributes && 'content' in attributes;
96
+ ): attributes is OgMetaAttributes => 'property' in attributes && 'content' in attributes;
105
97
 
106
- export const isSeoMetaTag = (
107
- seoMetaTag: SeoOrFaviconTag,
108
- ): seoMetaTag is SeoMetaTag =>
98
+ export const isSeoMetaTag = (seoMetaTag: SeoOrFaviconTag): seoMetaTag is SeoMetaTag =>
109
99
  'tag' in seoMetaTag &&
110
100
  seoMetaTag.tag === 'meta' &&
111
101
  !seoMetaTag.content &&
112
- (isRegularMetaAttributes(seoMetaTag.attributes) ||
113
- isOgMetaAttributes(seoMetaTag.attributes));
102
+ (isRegularMetaAttributes(seoMetaTag.attributes) || isOgMetaAttributes(seoMetaTag.attributes));
@@ -9,48 +9,41 @@ import {
9
9
  isBlock,
10
10
  isInlineItem,
11
11
  isItemLink,
12
- } from "datocms-structured-text-utils";
12
+ } from 'datocms-structured-text-utils';
13
13
 
14
14
  import {
15
15
  defaultComponents,
16
16
  throwRenderErrorForMissingBlock,
17
17
  throwRenderErrorForMissingComponent,
18
18
  throwRenderErrorForMissingLink,
19
- } from "./utils";
19
+ } from './utils';
20
20
 
21
- import type { PredicateComponentTuple } from "./types";
21
+ import type { PredicateComponentTuple } from './types';
22
22
 
23
23
  interface Props {
24
24
  node: Node;
25
- blocks: StructuredText["blocks"];
26
- links: StructuredText["links"];
25
+ blocks: StructuredText['blocks'];
26
+ links: StructuredText['links'];
27
27
  components: PredicateComponentTuple[];
28
28
  }
29
29
 
30
30
  const { node, blocks, links, components = [] } = Astro.props;
31
31
 
32
- const findBlock = (node: Block, blocks: StructuredText["blocks"]) =>
32
+ const findBlock = (node: Block, blocks: StructuredText['blocks']) =>
33
33
  (blocks || []).find(({ id }) => id === node.item);
34
34
 
35
- const findLink = (
36
- node: ItemLink | InlineItem,
37
- links: StructuredText["links"]
38
- ) => (links || []).find(({ id }) => id === node.item);
35
+ const findLink = (node: ItemLink | InlineItem, links: StructuredText['links']) =>
36
+ (links || []).find(({ id }) => id === node.item);
39
37
 
40
- const block =
41
- isBlock(node) &&
42
- (findBlock(node, blocks) || throwRenderErrorForMissingBlock(node));
38
+ const block = isBlock(node) && (findBlock(node, blocks) || throwRenderErrorForMissingBlock(node));
43
39
 
44
40
  const link =
45
- (isItemLink(node) &&
46
- (findLink(node, links) || throwRenderErrorForMissingLink(node))) ||
47
- (isInlineItem(node) &&
48
- (findLink(node, links) || throwRenderErrorForMissingLink(node)));
41
+ (isItemLink(node) && (findLink(node, links) || throwRenderErrorForMissingLink(node))) ||
42
+ (isInlineItem(node) && (findLink(node, links) || throwRenderErrorForMissingLink(node)));
49
43
 
50
44
  const predicateComponentTuple =
51
- [...components, ...defaultComponents].find(([predicate, component]) =>
52
- predicate(node)
53
- ) || throwRenderErrorForMissingComponent(node);
45
+ [...components, ...defaultComponents].find(([predicate, component]) => predicate(node)) ||
46
+ throwRenderErrorForMissingComponent(node);
54
47
 
55
48
  const Component = (predicateComponentTuple ?? [])[1];
56
49
  ---
@@ -65,16 +58,12 @@ const Component = (predicateComponentTuple ?? [])[1];
65
58
  ) : isItemLink(node) ? (
66
59
  <Component {node} {link}>
67
60
  {hasChildren(node) &&
68
- node.children.map((child) => (
69
- <Astro.self node={child} {blocks} {links} {components} />
70
- ))}
61
+ node.children.map((child) => <Astro.self node={child} {blocks} {links} {components} />)}
71
62
  </Component>
72
63
  ) : (
73
64
  <Component {node}>
74
65
  {hasChildren(node) &&
75
- node.children.map((child) => (
76
- <Astro.self node={child} {blocks} {links} {components} />
77
- ))}
66
+ node.children.map((child) => <Astro.self node={child} {blocks} {links} {components} />)}
78
67
  </Component>
79
68
  ))
80
69
  }
@@ -7,7 +7,7 @@
7
7
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
8
8
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
9
9
 
10
- - [Setup](#setup)
10
+ - [Setup](#setup)
11
11
  - [Basic usage](#basic-usage)
12
12
  - [Customization](#customization)
13
13
  - [Custom components for blocks](#custom-components-for-blocks)
@@ -3,10 +3,10 @@ import {
3
3
  type StructuredText,
4
4
  type Document,
5
5
  isStructuredText,
6
- } from "datocms-structured-text-utils";
6
+ } from 'datocms-structured-text-utils';
7
7
 
8
- import Node from "./Node.astro";
9
- import type { PredicateComponentTuple } from "./types";
8
+ import Node from './Node.astro';
9
+ import type { PredicateComponentTuple } from './types';
10
10
 
11
11
  interface Props {
12
12
  data: StructuredText | Document | null;
@@ -15,9 +15,7 @@ interface Props {
15
15
 
16
16
  const { data, components = [] } = Astro.props;
17
17
 
18
- const node =
19
- data != null &&
20
- (isStructuredText(data) ? (data.value as Document) : data).document;
18
+ const node = data != null && (isStructuredText(data) ? (data.value as Document) : data).document;
21
19
 
22
20
  const blocks = isStructuredText(data) ? data?.blocks : undefined;
23
21
 
@@ -1,5 +1,5 @@
1
- import StructuredText from "./StructuredText.astro";
1
+ import StructuredText from './StructuredText.astro';
2
2
 
3
- export { defaultComponents } from "./utils";
3
+ export { defaultComponents } from './utils';
4
4
 
5
5
  export { StructuredText };
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { Blockquote } from "datocms-structured-text-utils";
2
+ import type { Blockquote } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: Blockquote;
@@ -1,13 +1,13 @@
1
1
  ---
2
- import type { Code } from "datocms-structured-text-utils";
2
+ import { Code as AstroCode } from 'astro:components';
3
+ import type { Code as CodeNode } from 'datocms-structured-text-utils';
3
4
 
4
5
  interface Props {
5
- node: Code;
6
+ // https://www.datocms.com/docs/structured-text/dast#code
7
+ node: CodeNode;
6
8
  }
7
9
 
8
10
  const { node } = Astro.props;
9
-
10
- const { code, language } = node;
11
11
  ---
12
12
 
13
- <pre class={language}>{code}</pre>
13
+ <AstroCode code={node.code} lang={node.language as 'js'} />
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { Heading } from "datocms-structured-text-utils";
2
+ import type { Heading } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: Heading;
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { Link } from "datocms-structured-text-utils";
2
+ import type { Link } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: Link;
@@ -11,7 +11,7 @@ const { url, meta } = node;
11
11
 
12
12
  let target: string | undefined = undefined;
13
13
 
14
- const targetMetaEntry = meta?.find((metaEntry) => metaEntry.id === "target");
14
+ const targetMetaEntry = meta?.find((metaEntry) => metaEntry.id === 'target');
15
15
 
16
16
  if (targetMetaEntry?.value) {
17
17
  target = targetMetaEntry.value;
@@ -19,7 +19,7 @@ if (targetMetaEntry?.value) {
19
19
 
20
20
  let rel: string | undefined = undefined;
21
21
 
22
- const relMetaEntry = meta?.find((metaEntry) => metaEntry.id === "rel");
22
+ const relMetaEntry = meta?.find((metaEntry) => metaEntry.id === 'rel');
23
23
 
24
24
  if (relMetaEntry?.value) {
25
25
  rel = relMetaEntry.value;
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { List } from "datocms-structured-text-utils";
2
+ import type { List } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: List;
@@ -9,7 +9,7 @@ const { node } = Astro.props;
9
9
  ---
10
10
 
11
11
  {
12
- node.style === "numbered" ? (
12
+ node.style === 'numbered' ? (
13
13
  <ol>
14
14
  <slot />
15
15
  </ol>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { ListItem } from "datocms-structured-text-utils";
2
+ import type { ListItem } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: ListItem;
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { Paragraph } from "datocms-structured-text-utils";
2
+ import type { Paragraph } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: Paragraph;
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { Root } from "datocms-structured-text-utils";
2
+ import type { Root } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: Root;
@@ -1,6 +1,6 @@
1
1
  ---
2
- import type { Span } from "datocms-structured-text-utils";
3
- import Lines from "../Lines.astro";
2
+ import type { Span } from 'datocms-structured-text-utils';
3
+ import Lines from '../Lines.astro';
4
4
 
5
5
  interface Props {
6
6
  node: Span;
@@ -16,37 +16,37 @@ const [mark, ...otherMarks] = marks ?? [];
16
16
  {
17
17
  !mark ? (
18
18
  <Lines lines={node.value.split(/\n/)} />
19
- ) : mark === "emphasis" ? (
19
+ ) : mark === 'emphasis' ? (
20
20
  <em>
21
21
  <Astro.self node={{ type, value, marks: otherMarks }}>
22
22
  <slot />
23
23
  </Astro.self>
24
24
  </em>
25
- ) : mark === "highlight" ? (
25
+ ) : mark === 'highlight' ? (
26
26
  <mark>
27
27
  <Astro.self node={{ type, value, marks: otherMarks }}>
28
28
  <slot />
29
29
  </Astro.self>
30
30
  </mark>
31
- ) : mark === "strikethrough" ? (
31
+ ) : mark === 'strikethrough' ? (
32
32
  <del>
33
33
  <Astro.self node={{ type, value, marks: otherMarks }}>
34
34
  <slot />
35
35
  </Astro.self>
36
36
  </del>
37
- ) : mark === "strong" ? (
37
+ ) : mark === 'strong' ? (
38
38
  <strong>
39
39
  <Astro.self node={{ type, value, marks: otherMarks }}>
40
40
  <slot />
41
41
  </Astro.self>
42
42
  </strong>
43
- ) : mark === "underline" ? (
43
+ ) : mark === 'underline' ? (
44
44
  <u>
45
45
  <Astro.self node={{ type, value, marks: otherMarks }}>
46
46
  <slot />
47
47
  </Astro.self>
48
48
  </u>
49
- ) : mark === "code" ? (
49
+ ) : mark === 'code' ? (
50
50
  <code>
51
51
  <Astro.self node={{ type, value, marks: otherMarks }}>
52
52
  <slot />
@@ -1,5 +1,5 @@
1
1
  ---
2
- import type { ThematicBreak } from "datocms-structured-text-utils";
2
+ import type { ThematicBreak } from 'datocms-structured-text-utils';
3
3
 
4
4
  interface Props {
5
5
  node: ThematicBreak;
@@ -1,4 +1,4 @@
1
- import type { Node } from "datocms-structured-text-utils";
1
+ import type { Node } from 'datocms-structured-text-utils';
2
2
 
3
3
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
4
4
  type AstroComponent = (props: any) => any;
@@ -1,92 +1,90 @@
1
1
  import {
2
- type Block,
3
- type InlineItem,
4
- type ItemLink,
5
- type Node,
6
- RenderError,
7
- type StructuredText,
8
- isBlock,
9
- isBlockquote,
10
- isCode,
11
- isHeading,
12
- isInlineItem,
13
- isItemLink,
14
- isLink,
15
- isList,
16
- isListItem,
17
- isParagraph,
18
- isRoot,
19
- isSpan,
20
- isThematicBreak,
21
- } from "datocms-structured-text-utils";
2
+ type Block,
3
+ type InlineItem,
4
+ type ItemLink,
5
+ type Node,
6
+ RenderError,
7
+ type StructuredText,
8
+ isBlock,
9
+ isBlockquote,
10
+ isCode,
11
+ isHeading,
12
+ isInlineItem,
13
+ isItemLink,
14
+ isLink,
15
+ isList,
16
+ isListItem,
17
+ isParagraph,
18
+ isRoot,
19
+ isSpan,
20
+ isThematicBreak,
21
+ } from 'datocms-structured-text-utils';
22
22
 
23
- import Blockquote from "./nodes/Blockquote.astro";
24
- import Code from "./nodes/Code.astro";
25
- import Heading from "./nodes/Heading.astro";
26
- import Link from "./nodes/Link.astro";
27
- import List from "./nodes/List.astro";
28
- import ListItem from "./nodes/ListItem.astro";
29
- import Paragraph from "./nodes/Paragraph.astro";
30
- import Root from "./nodes/Root.astro";
31
- import Span from "./nodes/Span.astro";
32
- import ThematicBreak from "./nodes/ThematicBreak.astro";
23
+ import Blockquote from './nodes/Blockquote.astro';
24
+ import Code from './nodes/Code.astro';
25
+ import Heading from './nodes/Heading.astro';
26
+ import Link from './nodes/Link.astro';
27
+ import List from './nodes/List.astro';
28
+ import ListItem from './nodes/ListItem.astro';
29
+ import Paragraph from './nodes/Paragraph.astro';
30
+ import Root from './nodes/Root.astro';
31
+ import Span from './nodes/Span.astro';
32
+ import ThematicBreak from './nodes/ThematicBreak.astro';
33
33
 
34
- import type { PredicateComponentTuple } from "./types";
34
+ import type { PredicateComponentTuple } from './types';
35
35
 
36
36
  export const defaultComponents: PredicateComponentTuple[] = [
37
- [isParagraph, Paragraph],
38
- [isRoot, Root],
39
- [isSpan, Span],
40
- [isLink, Link],
41
- [isList, List],
42
- [isHeading, Heading],
43
- [isBlockquote, Blockquote],
44
- [isListItem, ListItem],
45
- [isThematicBreak, ThematicBreak],
46
- [isCode, Code],
37
+ [isParagraph, Paragraph],
38
+ [isRoot, Root],
39
+ [isSpan, Span],
40
+ [isLink, Link],
41
+ [isList, List],
42
+ [isHeading, Heading],
43
+ [isBlockquote, Blockquote],
44
+ [isListItem, ListItem],
45
+ [isThematicBreak, ThematicBreak],
46
+ [isCode, Code],
47
47
  ];
48
48
 
49
49
  export const throwRenderErrorForMissingComponent = (node: Node) => {
50
- if (isInlineItem(node)) {
51
- throw new RenderError(
52
- `The Structured Text document contains an 'inlineItem' node, but no component for rendering is specified!`,
53
- node,
54
- );
55
- }
50
+ if (isInlineItem(node)) {
51
+ throw new RenderError(
52
+ `The Structured Text document contains an 'inlineItem' node, but no component for rendering is specified!`,
53
+ node,
54
+ );
55
+ }
56
56
 
57
- if (isItemLink(node)) {
58
- throw new RenderError(
59
- `The Structured Text document contains an 'itemLink' node, but no component for rendering is specified!`,
60
- node,
61
- );
62
- }
57
+ if (isItemLink(node)) {
58
+ throw new RenderError(
59
+ `The Structured Text document contains an 'itemLink' node, but no component for rendering is specified!`,
60
+ node,
61
+ );
62
+ }
63
63
 
64
- if (isBlock(node)) {
65
- throw new RenderError(
66
- `The Structured Text document contains a 'block' node, but no component for rendering is specified!`,
67
- node,
68
- );
69
- }
64
+ if (isBlock(node)) {
65
+ throw new RenderError(
66
+ `The Structured Text document contains a 'block' node, but no component for rendering is specified!`,
67
+ node,
68
+ );
69
+ }
70
70
  };
71
71
 
72
72
  export const throwRenderErrorForMissingBlock = (node: Block) => {
73
- throw new RenderError(
74
- `The Structured Text document contains a 'block' node, but cannot find a record with ID ${node.item} inside data.blocks!`,
75
- node,
76
- );
73
+ throw new RenderError(
74
+ `The Structured Text document contains a 'block' node, but cannot find a record with ID ${node.item} inside data.blocks!`,
75
+ node,
76
+ );
77
77
  };
78
78
 
79
79
  export const throwRenderErrorForMissingLink = (node: ItemLink | InlineItem) => {
80
- throw new RenderError(
81
- `The Structured Text document contains an 'itemLink' node, but cannot find a record with ID ${node.item} inside data.links!`,
82
- node,
83
- );
80
+ throw new RenderError(
81
+ `The Structured Text document contains an 'itemLink' node, but cannot find a record with ID ${node.item} inside data.links!`,
82
+ node,
83
+ );
84
84
  };
85
85
 
86
- export const findBlock = (node: Block, blocks: StructuredText["blocks"]) =>
87
- (blocks || []).find(({ id }) => id === node.item);
86
+ export const findBlock = (node: Block, blocks: StructuredText['blocks']) =>
87
+ (blocks || []).find(({ id }) => id === node.item);
88
88
 
89
- export const findLink = (
90
- node: ItemLink | InlineItem,
91
- links: StructuredText["links"],
92
- ) => (links || []).find(({ id }) => id === node.item);
89
+ export const findLink = (node: ItemLink | InlineItem, links: StructuredText['links']) =>
90
+ (links || []).find(({ id }) => id === node.item);
@@ -1,30 +0,0 @@
1
- ---
2
- import type { VideoPlayerProps } from "./types";
3
- import { useVideoPlayer } from "../useVideoPlayer";
4
- import { toNativeProps } from "./utils";
5
-
6
- interface Props extends VideoPlayerProps {}
7
-
8
- const {
9
- data,
10
- disableCookies = true,
11
- preload = "metadata",
12
- ...otherProps
13
- } = Astro.props;
14
-
15
- const computedProps = {
16
- ...useVideoPlayer({ data }),
17
- disableCookies,
18
- preload,
19
- };
20
- ---
21
-
22
- <mux-player
23
- stream-type="on-demand"
24
- {...toNativeProps(computedProps)}
25
- {...toNativeProps(otherProps)}
26
- ></mux-player>
27
-
28
- <script>
29
- import "@mux/mux-player";
30
- </script>
@@ -1,2 +0,0 @@
1
- import VideoPlayer from "./VideoPlayer.astro";
2
- export { VideoPlayer };
@@ -1,72 +0,0 @@
1
- import type { MuxMediaProps } from "@mux/playback-core";
2
- import type { JSX } from 'astro/jsx-runtime';
3
-
4
- type StyleAttribute = JSX.HTMLAttributes["style"];
5
-
6
- type Maybe<T> = T | null;
7
-
8
- export type Video = {
9
- /** Title attribute (`title`) for the video */
10
- title?: Maybe<string>;
11
- /** The height of the video */
12
- height?: Maybe<number>;
13
- /** The width of the video */
14
- width?: Maybe<number>;
15
- /** The MUX playback ID */
16
- muxPlaybackId?: Maybe<string>;
17
- /** The MUX playback ID */
18
- playbackId?: Maybe<string>;
19
- /** A data: URI containing a blurhash for the video */
20
- blurUpThumb?: Maybe<string>;
21
- /** Other data can be passed, but they have no effect on rendering the player */
22
- // biome-ignore lint/suspicious/noExplicitAny: we intentionally want to allow to add any other value to this video object
23
- [k: string]: any;
24
- };
25
-
26
- // Extracted from mux-player-react
27
-
28
- type VideoApiAttributes = {
29
- currentTime: number;
30
- volume: number;
31
- paused: boolean;
32
- src: string | null;
33
- poster: string;
34
- playbackRate: number;
35
- playsInline: boolean;
36
- preload: string;
37
- crossOrigin: string;
38
- autoPlay: boolean | string;
39
- loop: boolean;
40
- muted: boolean;
41
- class?: string;
42
- style?: StyleAttribute;
43
- };
44
-
45
- // Extracted from mux-player-react
46
-
47
- export type MuxPlayerProps = Partial<MuxMediaProps> & Partial<VideoApiAttributes> & {
48
- hotkeys?: string;
49
- nohotkeys?: boolean;
50
- defaultHiddenCaptions?: boolean;
51
- forwardSeekOffset?: number;
52
- backwardSeekOffset?: number;
53
- metadataVideoId?: string;
54
- metadataVideoTitle?: string;
55
- metadataViewerUserId?: string;
56
- primaryColor?: string;
57
- secondaryColor?: string;
58
- accentColor?: string;
59
- placeholder?: string;
60
- playbackRates?: number[];
61
- defaultShowRemainingTime?: boolean;
62
- defaultDuration?: number;
63
- noVolumePref?: boolean;
64
- thumbnailTime?: number;
65
- title?: string;
66
- theme?: string;
67
- themeProps?: { [k: string]: any };
68
- };
69
-
70
- export type VideoPlayerProps = MuxPlayerProps & {
71
- data: Video;
72
- };
@@ -1,50 +0,0 @@
1
- // Adapted from mux-player-react
2
-
3
- const ReactPropToAttrNameMap = {
4
- crossOrigin: 'crossorigin',
5
- viewBox: 'viewBox',
6
- playsInline: 'playsinline',
7
- autoPlay: 'autoplay',
8
- playbackRate: 'playbackrate',
9
- };
10
-
11
- type KeyTypes = string | number | symbol;
12
- type Maybe<T> = T | null | undefined;
13
-
14
- const isNil = (x: unknown): x is null | undefined => x === undefined;
15
-
16
- // Type Guard to determine if a given key is actually a key of some object of type T
17
- export const isKeyOf = <T extends {} = any>(k: KeyTypes, o: Maybe<T>): k is keyof T => {
18
- if (isNil(o)) return false;
19
- return k in o;
20
- };
21
-
22
- const toKebabCase = (string: string) => string.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
23
-
24
- const toNativeAttrName = (propName: string, propValue: any): string | undefined => {
25
- if (typeof propValue === 'boolean' && !propValue) return undefined;
26
- if (isKeyOf(propName, ReactPropToAttrNameMap)) return ReactPropToAttrNameMap[propName];
27
- if (propValue === undefined) return undefined;
28
- if (/[A-Z]/.test(propName)) return toKebabCase(propName);
29
- return propName;
30
- };
31
-
32
- const toNativeAttrValue = (propValue: any, propName: string) => {
33
- if (typeof propValue === 'boolean') return '';
34
- return propValue;
35
- };
36
-
37
- export const toNativeProps = (props = {}) => {
38
- return Object.entries(props).reduce<{ [k: string]: string }>((transformedProps, [propName, propValue]) => {
39
- const attrName = toNativeAttrName(propName, propValue);
40
-
41
- // prop was stripped. Don't add.
42
- if (!attrName) {
43
- return transformedProps;
44
- }
45
-
46
- const attrValue = toNativeAttrValue(propValue, propName);
47
- transformedProps[attrName] = attrValue;
48
- return transformedProps;
49
- }, {});
50
- };
@@ -1,55 +0,0 @@
1
- import type { MuxPlayerProps, Video } from "../VideoPlayer/types";
2
-
3
- type Maybe<T> = T | null;
4
- type Possibly<T> = Maybe<T> | undefined;
5
-
6
- function computedTitle(title: Possibly<string>): MuxPlayerProps {
7
- return title ? { title } : {};
8
- };
9
-
10
- function computedPlaybackId(
11
- muxPlaybackId: Possibly<string>,
12
- playbackId: Possibly<string>,
13
- ): MuxPlayerProps {
14
- if (!(muxPlaybackId || playbackId)) {
15
- return {};
16
- }
17
-
18
- return { playbackId: `${muxPlaybackId || playbackId}` };
19
- };
20
-
21
- function computedStyle(width: Possibly<number>, height: Possibly<number>): MuxPlayerProps {
22
- if (!(width && height)) {
23
- return {};
24
- }
25
-
26
- return {
27
- style: {
28
- aspectRatio: `${width} / ${height}`,
29
- },
30
- };
31
- };
32
-
33
- function computedPlaceholder(blurUpThumb: Possibly<string>): MuxPlayerProps {
34
- return blurUpThumb ? { placeholder: blurUpThumb } : {};
35
- };
36
-
37
- type UseVideoPlayerArgs = {
38
- data?: Video;
39
- };
40
-
41
- export function useVideoPlayer({
42
- data,
43
- }: UseVideoPlayerArgs): MuxPlayerProps {
44
- const { title, width, height, playbackId, muxPlaybackId, blurUpThumb } =
45
- data || {};
46
-
47
- if (data === undefined) return {};
48
-
49
- return {
50
- ...(computedTitle(title) || {}),
51
- ...(computedPlaybackId(muxPlaybackId, playbackId) || {}),
52
- ...(computedStyle(width, height) || {}),
53
- ...(computedPlaceholder(blurUpThumb) || {}),
54
- };
55
- };