@prismicio/vue 3.0.0-alpha.2 → 3.0.0-alpha.6

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.
@@ -22,50 +22,36 @@ const defaultImageComponent = "img";
22
22
  /**
23
23
  * Props for `<PrismicImage />`.
24
24
  */
25
- export type PrismicImageProps =
26
- | {
27
- /** The Prismic image field to render. */
28
- field: ImageField;
25
+ export type PrismicImageProps = {
26
+ /**
27
+ * The Prismic image field to render.
28
+ */
29
+ field: ImageField;
29
30
 
30
- /**
31
- * Ensures type union is a strict or.
32
- *
33
- * @internal
34
- */
35
- imageComponent?: never;
31
+ /**
32
+ * An HTML tag name, a component, or a functional component used to render images.
33
+ *
34
+ * @remarks
35
+ * HTML tag names and components will be rendered using the `img` tag
36
+ * interface (`src` and `alt` attribute). Components will also receive an
37
+ * additional `copyright` props.
38
+ * @defaultValue The one provided to `@prismicio/vue` plugin if configured, `"img"` otherwise.
39
+ */
40
+ imageComponent?: string | ConcreteComponent;
36
41
 
37
- /**
38
- * Ensures type union is a strict or.
39
- *
40
- * @internal
41
- */
42
- imageComponentAdditionalProps?: never;
43
- }
44
- | {
45
- /** The Prismic image field to render. */
46
- field: ImageField;
47
-
48
- /**
49
- * An HTML tag name, a component, or a functional component used to render images.
50
- *
51
- * @remarks HTML tag names and components will be rendered using the `img` tag interface (`src` and `alt` attribute). Components will also receive an additional `copyright` props.
52
- *
53
- * @defaultValue The one provided to `@prismicio/vue` plugin if configured, `"img"` otherwise.
54
- */
55
- imageComponent: string | ConcreteComponent;
56
-
57
- /**
58
- * A map of additional props to pass to the component used to render images when using one.
59
- */
60
- imageComponentAdditionalProps?: Record<string, unknown>;
61
- };
42
+ /**
43
+ * A map of additional props to pass to the component used to render images
44
+ * when using one.
45
+ */
46
+ imageComponentAdditionalProps?: Record<string, unknown>;
47
+ };
62
48
 
63
49
  /**
64
50
  * `<PrismicImage />` implementation.
65
51
  *
66
52
  * @internal
67
53
  */
68
- export const PrismicImageImpl = defineComponent({
54
+ export const PrismicImageImpl = /*#__PURE__*/ defineComponent({
69
55
  name: "PrismicImage",
70
56
  props: {
71
57
  field: {
@@ -12,11 +12,7 @@ import {
12
12
  ComputedRef,
13
13
  } from "vue";
14
14
 
15
- import {
16
- asLink,
17
- documentAsLink,
18
- LinkResolverFunction,
19
- } from "@prismicio/helpers";
15
+ import { asLink, LinkResolverFunction } from "@prismicio/helpers";
20
16
  import { LinkField, PrismicDocument } from "@prismicio/types";
21
17
 
22
18
  import { isInternalURL } from "../lib/isInternalURL";
@@ -44,14 +40,16 @@ const defaultBlankTargetRelAttribute = "noopener noreferrer";
44
40
  * Props for `<PrismicLink />`.
45
41
  */
46
42
  export type PrismicLinkProps = {
47
- /** The Prismic link field or document to render. */
43
+ /**
44
+ * The Prismic link field or document to render.
45
+ */
48
46
  field: LinkField | PrismicDocument;
49
47
 
50
48
  /**
51
- * A link resolver function used to resolve links when not using the route resolver parameter with `@prismicio/client`.
49
+ * A link resolver function used to resolve links when not using the route
50
+ * resolver parameter with `@prismicio/client`.
52
51
  *
53
52
  * @defaultValue The link resolver provided to `@prismicio/vue` plugin if configured.
54
- *
55
53
  * @see Link resolver documentation {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver#link-resolver}
56
54
  */
57
55
  linkResolver?: LinkResolverFunction;
@@ -59,38 +57,44 @@ export type PrismicLinkProps = {
59
57
  /**
60
58
  * An explicit `target` attribute to apply to the rendered link.
61
59
  */
62
- target?: string;
60
+ target?: string | null;
63
61
 
64
62
  /**
65
63
  * An explicit `rel` attribute to apply to the rendered link.
66
64
  */
67
- rel?: string;
65
+ rel?: string | null;
68
66
 
69
67
  /**
70
68
  * Value of the `rel` attribute to use on links rendered with `target="_blank"`.
71
69
  *
72
70
  * @defaultValue The one provided to `@prismicio/vue` plugin if configured, `"noopener noreferrer"` otherwise.
73
71
  */
74
- blankTargetRelAttribute?: string;
72
+ blankTargetRelAttribute?: string | null;
75
73
 
76
74
  /**
77
- * An HTML tag name, a component, or a functional component used to render internal links.
78
- *
79
- * @remarks HTML tag names will be rendered using the anchor tag interface (`href`, `target`, and `rel` attributes).
80
- *
81
- * @remarks Components will be rendered using Vue Router {@link RouterLink} interface (`to` props).
75
+ * An HTML tag name, a component, or a functional component used to render
76
+ * internal links.
82
77
  *
78
+ * @remarks
79
+ * HTML tag names will be rendered using the anchor tag interface (`href`,
80
+ * `target`, and `rel` attributes).
81
+ * @remarks
82
+ * Components will be rendered using Vue Router {@link RouterLink} interface
83
+ * (`to` props).
83
84
  * @defaultValue The one provided to `@prismicio/vue` plugin if configured, {@link RouterLink} otherwise.
84
85
  */
85
86
  internalComponent?: string | ConcreteComponent;
86
87
 
87
88
  /**
88
- * An HTML tag name, a component, or a functional component used to render external links.
89
- *
90
- * @remarks HTML tag names will be rendered using the anchor tag interface (`href`, `target`, and `rel` attributes).
91
- *
92
- * @remarks Components will be rendered using Vue Router {@link RouterLink} interface (`to` props).
89
+ * An HTML tag name, a component, or a functional component used to render
90
+ * external links.
93
91
  *
92
+ * @remarks
93
+ * HTML tag names will be rendered using the anchor tag interface (`href`,
94
+ * `target`, and `rel` attributes).
95
+ * @remarks
96
+ * Components will be rendered using Vue Router {@link RouterLink} interface
97
+ * (`to` props).
94
98
  * @defaultValue The one provided to `@prismicio/vue` plugin if configured, `"a"` otherwise.
95
99
  */
96
100
  externalComponent?: string | ConcreteComponent;
@@ -105,16 +109,24 @@ export type UsePrismicLinkOptions = VueUseOptions<PrismicLinkProps>;
105
109
  * Return type of {@link usePrismicLink}.
106
110
  */
107
111
  export type UsePrismicLinkReturnType = {
108
- /** Suggested component to render for provided link field. */
112
+ /**
113
+ * Suggested component to render for provided link field.
114
+ */
109
115
  type: ComputedRef<string | ConcreteComponent>;
110
116
 
111
- /** Resolved anchor `href` value. */
117
+ /**
118
+ * Resolved anchor `href` value.
119
+ */
112
120
  href: ComputedRef<string>;
113
121
 
114
- /** Resolved anchor `target` value. */
122
+ /**
123
+ * Resolved anchor `target` value.
124
+ */
115
125
  target: ComputedRef<string | null>;
116
126
 
117
- /** Resolved anchor `rel` value. */
127
+ /**
128
+ * Resolved anchor `rel` value.
129
+ */
118
130
  rel: ComputedRef<string | null>;
119
131
  };
120
132
 
@@ -149,29 +161,37 @@ export const usePrismicLink = (
149
161
  const field = unref(props.field);
150
162
  const linkResolver = unref(props.linkResolver) ?? options.linkResolver;
151
163
 
152
- return "data" in field && field.data
153
- ? documentAsLink(field, linkResolver) ?? ""
154
- : asLink(field, linkResolver) ?? "";
164
+ return asLink(field, linkResolver) ?? "";
155
165
  });
156
166
  const target = computed(() => {
157
167
  const field = unref(props.field);
168
+ const target = unref(props.target);
158
169
 
159
- return (
160
- unref(props.target) ||
161
- (field && "target" in field && field.target ? field.target : null)
162
- );
170
+ if (typeof target !== "undefined") {
171
+ return target;
172
+ } else {
173
+ return field && "target" in field && field.target ? field.target : null;
174
+ }
163
175
  });
164
176
  const rel = computed(() => {
165
- const field = unref(props.field);
177
+ const rel = unref(props.rel);
178
+
179
+ if (typeof rel !== "undefined") {
180
+ return rel;
181
+ } else if (target.value === "_blank") {
182
+ const blankTargetRelAttribute = unref(props.blankTargetRelAttribute);
166
183
 
167
- return (
168
- unref(props.rel) ||
169
- (target.value === "_blank" && field && "target" in field && field
170
- ? unref(props.blankTargetRelAttribute) ||
171
- options.components?.linkBlankTargetRelAttribute ||
172
- defaultBlankTargetRelAttribute
173
- : null)
174
- );
184
+ if (typeof blankTargetRelAttribute !== "undefined") {
185
+ return blankTargetRelAttribute;
186
+ } else {
187
+ return typeof options.components?.linkBlankTargetRelAttribute !==
188
+ "undefined"
189
+ ? options.components.linkBlankTargetRelAttribute
190
+ : defaultBlankTargetRelAttribute;
191
+ }
192
+ } else {
193
+ return null;
194
+ }
175
195
  });
176
196
 
177
197
  return {
@@ -187,7 +207,7 @@ export const usePrismicLink = (
187
207
  *
188
208
  * @internal
189
209
  */
190
- export const PrismicLinkImpl = defineComponent({
210
+ export const PrismicLinkImpl = /*#__PURE__*/ defineComponent({
191
211
  name: "PrismicLink",
192
212
  props: {
193
213
  field: {
@@ -17,22 +17,18 @@ import {
17
17
  watch,
18
18
  } from "vue";
19
19
  import { routerKey } from "vue-router";
20
- import escapeHTML from "escape-html";
21
20
 
22
21
  import {
23
22
  asHTML,
24
- asLink,
25
23
  HTMLFunctionSerializer,
26
24
  HTMLMapSerializer,
27
25
  LinkResolverFunction,
28
- Element,
29
26
  } from "@prismicio/helpers";
30
- import { LinkType, RichTextField, RTLinkNode } from "@prismicio/types";
27
+ import { RichTextField } from "@prismicio/types";
31
28
 
32
29
  import { VueUseOptions } from "../types";
33
30
  import { usePrismic } from "../usePrismic";
34
31
  import { simplyResolveComponent } from "../lib/simplyResolveComponent";
35
- import { composeSerializers, wrapMapSerializer } from "@prismicio/richtext";
36
32
  import { isInternalURL } from "../lib/isInternalURL";
37
33
 
38
34
  /**
@@ -44,14 +40,16 @@ const defaultWrapper = "div";
44
40
  * Props for `<PrismicRichText />`.
45
41
  */
46
42
  export type PrismicRichTextProps = {
47
- /** The Prismic rich text or title field to render. */
43
+ /**
44
+ * The Prismic rich text or title field to render.
45
+ */
48
46
  field: RichTextField;
49
47
 
50
48
  /**
51
- * A link resolver function used to resolve link when not using the route resolver parameter with `@prismicio/client`.
49
+ * A link resolver function used to resolve link when not using the route
50
+ * resolver parameter with `@prismicio/client`.
52
51
  *
53
52
  * @defaultValue The link resolver provided to `@prismicio/vue` plugin if configured.
54
- *
55
53
  * @see Link resolver documentation {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver#link-resolver}
56
54
  */
57
55
  linkResolver?: LinkResolverFunction;
@@ -60,7 +58,6 @@ export type PrismicRichTextProps = {
60
58
  * An HTML serializer to customize the way rich text fields are rendered.
61
59
  *
62
60
  * @defaultValue The HTML serializer provided to `@prismicio/vue` plugin if configured.
63
- *
64
61
  * @see HTML serializer documentation {@link https://prismic.io/docs/core-concepts/html-serializer}
65
62
  */
66
63
  htmlSerializer?: HTMLFunctionSerializer | HTMLMapSerializer;
@@ -84,44 +81,12 @@ export type UsePrismicRichTextOptions = VueUseOptions<
84
81
  * Return type of {@link usePrismicRichText}.
85
82
  */
86
83
  export type UsePrismicRichTextReturnType = {
87
- /** Serialized rich text field as HTML. */
84
+ /**
85
+ * Serialized rich text field as HTML.
86
+ */
88
87
  html: ComputedRef<string>;
89
88
  };
90
89
 
91
- /**
92
- * Serializes hyperlink for Vue, applying `data-router-link` attribute to internal links for usage with Vue Router.
93
- *
94
- * @param linkResolver - A link resolver function to use
95
- * @param node - The link node to serialize
96
- * @param children - The children of the link node
97
- *
98
- * @returns Serialized hyperlink
99
- */
100
- const serializeVueHyperlink = (
101
- linkResolver: LinkResolverFunction | undefined,
102
- node: RTLinkNode,
103
- children: string[],
104
- ) => {
105
- switch (node.data.link_type) {
106
- case LinkType.Web: {
107
- return `<a href="${escapeHTML(node.data.url)}" target="${
108
- node.data.target
109
- }" rel="noopener noreferrer">${children.join("")}</a>`;
110
- }
111
-
112
- case LinkType.Document: {
113
- return `<a data-router-link href="${asLink(
114
- node.data,
115
- linkResolver,
116
- )}">${children.join("")}</a>`;
117
- }
118
-
119
- case LinkType.Media: {
120
- return `<a href="${node.data.url}">${children.join("")}</a>`;
121
- }
122
- }
123
- };
124
-
125
90
  /**
126
91
  * A low level composable that returns a serialized rich text field as HTML.
127
92
  *
@@ -136,34 +101,10 @@ export const usePrismicRichText = (
136
101
 
137
102
  const html = computed(() => {
138
103
  const linkResolver = unref(props.linkResolver) ?? options.linkResolver;
139
-
140
- const maybeSerializer =
104
+ const htmlSerializer =
141
105
  unref(props.htmlSerializer) ?? options.htmlSerializer;
142
- // Extends default HTML serializer to handle Vue Router links
143
- let serializer: HTMLFunctionSerializer = (
144
- _type,
145
- node,
146
- _content,
147
- children,
148
- _key,
149
- ) => {
150
- switch (node.type) {
151
- case Element.hyperlink:
152
- return serializeVueHyperlink(linkResolver, node, children);
153
- default:
154
- return null;
155
- }
156
- };
157
- if (maybeSerializer) {
158
- serializer = composeSerializers(
159
- typeof maybeSerializer === "object"
160
- ? wrapMapSerializer(maybeSerializer)
161
- : maybeSerializer,
162
- serializer,
163
- );
164
- }
165
106
 
166
- return asHTML(unref(props.field), linkResolver, serializer);
107
+ return asHTML(unref(props.field), linkResolver, htmlSerializer);
167
108
  });
168
109
 
169
110
  return {
@@ -176,11 +117,11 @@ export const usePrismicRichText = (
176
117
  *
177
118
  * @internal
178
119
  */
179
- export const PrismicRichTextImpl = defineComponent({
120
+ export const PrismicRichTextImpl = /*#__PURE__*/ defineComponent({
180
121
  name: "PrismicRichText",
181
122
  props: {
182
123
  field: {
183
- type: Array as PropType<RichTextField>,
124
+ type: Array as unknown as PropType<RichTextField>,
184
125
  required: true,
185
126
  },
186
127
  linkResolver: {
@@ -209,53 +150,51 @@ export const PrismicRichTextImpl = defineComponent({
209
150
 
210
151
  const { html } = usePrismicRichText(props);
211
152
 
212
- const root = ref<HTMLElement | Component | null>(null);
153
+ const root = ref<HTMLElement | Comment | Component | null>(null);
213
154
 
214
155
  const maybeRouter = inject(routerKey, null);
215
156
  if (maybeRouter) {
216
- let links: NodeList | null = null;
217
-
218
- const navigate: EventListener = (event: Event) => {
219
- let target = event.target as (Node & ParentNode) | null;
220
- let i = 0;
221
- // Go throught 5 parents max to find a tag
222
- while (
223
- i < 5 &&
224
- target &&
225
- !(target instanceof HTMLAnchorElement) &&
226
- target.parentNode
227
- ) {
228
- target = target.parentNode;
229
- i++;
230
- }
231
-
232
- // If target is still not a link, ignore
233
- if (!(target instanceof HTMLAnchorElement)) {
234
- return;
235
- }
236
-
237
- const href = target.getAttribute("href");
238
- // Get link target, if internal link, navigate with router link
239
- if (href && isInternalURL(href)) {
240
- event.preventDefault();
241
- maybeRouter.push(href);
242
- }
157
+ type InternalLink = {
158
+ element: HTMLAnchorElement;
159
+ listener: EventListener;
160
+ };
161
+ let links: InternalLink[] = [];
162
+
163
+ const navigate: EventListener = function (
164
+ this: { href: string },
165
+ event: Event,
166
+ ) {
167
+ event.preventDefault();
168
+ maybeRouter.push(this.href);
243
169
  };
244
170
 
245
171
  const addListeners = () => {
246
- const node: HTMLElement | null =
172
+ const node: HTMLElement | Comment | null =
247
173
  root.value && "$el" in root.value ? root.value.$el : root.value;
248
- links =
249
- node &&
250
- node.querySelectorAll &&
251
- node.querySelectorAll("a[data-router-link]");
252
- links &&
253
- links.forEach((link) => link.addEventListener("click", navigate));
174
+ if (node && "querySelectorAll" in node) {
175
+ // Get all internal link tags and add listeners on them
176
+ links = Array.from(node.querySelectorAll("a"))
177
+ .map((element) => {
178
+ const href = element.getAttribute("href");
179
+
180
+ if (href && isInternalURL(href)) {
181
+ const listener = navigate.bind({ href });
182
+ element.addEventListener("click", listener);
183
+
184
+ return { element, listener };
185
+ } else {
186
+ return false;
187
+ }
188
+ })
189
+ .filter((link): link is InternalLink => link as boolean);
190
+ }
254
191
  };
255
192
 
256
193
  const removeListeners = () => {
257
- links?.forEach((link) => link.removeEventListener("click", navigate));
258
- links = null;
194
+ links.forEach(({ element, listener }) =>
195
+ element.removeEventListener("click", listener),
196
+ );
197
+ links = [];
259
198
  };
260
199
 
261
200
  watch(
@@ -4,11 +4,11 @@ import {
4
4
  computed,
5
5
  ComputedRef,
6
6
  ConcreteComponent,
7
- DefineComponent,
8
7
  defineComponent,
9
8
  h,
10
9
  PropType,
11
10
  unref,
11
+ VNode,
12
12
  VNodeProps,
13
13
  } from "vue";
14
14
 
@@ -27,7 +27,9 @@ const defaultWrapper = "div";
27
27
  * Props for `<PrismicText />`.
28
28
  */
29
29
  export type PrismicTextProps = {
30
- /** The Prismic rich text or title field to render. */
30
+ /**
31
+ * The Prismic rich text or title field to render.
32
+ */
31
33
  field: RichTextField;
32
34
 
33
35
  /**
@@ -56,7 +58,9 @@ export type UsePrismicTextOptions = VueUseOptions<
56
58
  * Return type of {@link usePrismicText}.
57
59
  */
58
60
  export type UsePrismicTextReturnType = {
59
- /** Serialized rich text field as plain text. */
61
+ /**
62
+ * Serialized rich text field as plain text.
63
+ */
60
64
  text: ComputedRef<string>;
61
65
  };
62
66
 
@@ -84,11 +88,11 @@ export const usePrismicText = (
84
88
  *
85
89
  * @internal
86
90
  */
87
- export const PrismicTextImpl = defineComponent({
91
+ export const PrismicTextImpl = /*#__PURE__*/ defineComponent({
88
92
  name: "PrismicText",
89
93
  props: {
90
94
  field: {
91
- type: Array as PropType<RichTextField>,
95
+ type: Array as unknown as PropType<RichTextField>,
92
96
  required: true,
93
97
  },
94
98
  separator: {
@@ -120,7 +124,7 @@ export const PrismicTextImpl = defineComponent({
120
124
  // return h(parent, null, { default: () => text.value });
121
125
  // }
122
126
 
123
- return h(parent as DefineComponent, null, {
127
+ return h(parent as VNode, null, {
124
128
  default: () => text.value,
125
129
  });
126
130
  };