wxt 0.13.4 → 0.14.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.
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.13.4";
2
+ var version = "0.14.0";
3
3
 
4
4
  // src/core/utils/arrays.ts
5
5
  function every(array, predicate) {
@@ -2108,7 +2108,10 @@ function getContentScriptCssWebAccessibleResources(config, contentScripts, conte
2108
2108
  } else {
2109
2109
  resources.push({
2110
2110
  resources: [cssFile],
2111
- matches: script.options.matches
2111
+ matches: resolvePerBrowserOption(
2112
+ script.options.matches,
2113
+ config.browser
2114
+ ).map((matchPattern) => stripPathFromMatchPattern(matchPattern))
2112
2115
  });
2113
2116
  }
2114
2117
  });
@@ -2138,6 +2141,13 @@ function addHostPermission(manifest, hostPermission) {
2138
2141
  return;
2139
2142
  manifest.host_permissions.push(hostPermission);
2140
2143
  }
2144
+ function stripPathFromMatchPattern(pattern) {
2145
+ const protocolSepIndex = pattern.indexOf("://");
2146
+ if (protocolSepIndex === -1)
2147
+ return pattern;
2148
+ const startOfPath = pattern.indexOf("/", protocolSepIndex + 3);
2149
+ return pattern.substring(0, startOfPath) + "/*";
2150
+ }
2141
2151
 
2142
2152
  // src/core/utils/building/rebuild.ts
2143
2153
  async function rebuild(config, entrypointGroups, existingOutput = {
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import "./chunk-VBXJIVYU.js";
4
4
  import cac from "cac";
5
5
 
6
6
  // package.json
7
- var version = "0.13.4";
7
+ var version = "0.14.0";
8
8
 
9
9
  // src/core/utils/fs.ts
10
10
  import fs from "fs-extra";
@@ -2405,7 +2405,10 @@ function getContentScriptCssWebAccessibleResources(config, contentScripts, conte
2405
2405
  } else {
2406
2406
  resources.push({
2407
2407
  resources: [cssFile],
2408
- matches: script.options.matches
2408
+ matches: resolvePerBrowserOption(
2409
+ script.options.matches,
2410
+ config.browser
2411
+ ).map((matchPattern) => stripPathFromMatchPattern(matchPattern))
2409
2412
  });
2410
2413
  }
2411
2414
  });
@@ -2435,6 +2438,13 @@ function addHostPermission(manifest, hostPermission) {
2435
2438
  return;
2436
2439
  manifest.host_permissions.push(hostPermission);
2437
2440
  }
2441
+ function stripPathFromMatchPattern(pattern) {
2442
+ const protocolSepIndex = pattern.indexOf("://");
2443
+ if (protocolSepIndex === -1)
2444
+ return pattern;
2445
+ const startOfPath = pattern.indexOf("/", protocolSepIndex + 3);
2446
+ return pattern.substring(0, startOfPath) + "/*";
2447
+ }
2438
2448
 
2439
2449
  // src/core/utils/building/rebuild.ts
2440
2450
  async function rebuild(config, entrypointGroups, existingOutput = {
package/dist/client.d.ts CHANGED
@@ -1,95 +1,23 @@
1
1
  import { a as ContentScriptContext } from './external-TYmXqKVq.js';
2
- import * as wxt_browser from 'wxt/browser';
3
2
  import 'webextension-polyfill';
4
3
 
5
- type ContentScriptOverlayAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
6
- /**
7
- * ![Visualization of different append modes](https://wxt.dev/content-script-ui-append.png)
8
- */
9
- type ContentScriptAppendMode = 'last' | 'first' | 'replace' | 'before' | 'after' | ((anchor: Element, ui: Element) => void);
10
- interface ContentScriptInlinePositioningOptions {
11
- type: 'inline';
12
- }
13
- interface ContentScriptOverlayPositioningOptions {
14
- type: 'overlay';
15
- /**
16
- * The `z-index` used on the `shadowHost`. Set to a positive number to show your UI over website
17
- * content.
18
- */
19
- zIndex?: number;
4
+ interface IntegratedContentScriptUi<TMounted> extends ContentScriptUi<TMounted> {
20
5
  /**
21
- * When using `type: "overlay"`, the mounted element is 0px by 0px in size. Alignment specifies
22
- * which corner is aligned with that 0x0 pixel space.
23
- *
24
- * ![Visualization of alignment options](https://wxt.dev/content-script-ui-alignment.png)
25
- *
26
- * @default "top-left"
27
- */
28
- alignment?: ContentScriptOverlayAlignment;
29
- }
30
- interface ContentScriptModalPositioningOptions {
31
- type: 'modal';
32
- /**
33
- * The `z-index` used on the `shadowHost`. Set to a positive number to show your UI over website
34
- * content.
6
+ * A wrapper div that assists in positioning.
35
7
  */
36
- zIndex?: number;
8
+ wrapper: HTMLElement;
37
9
  }
38
- /**
39
- * Choose between `"inline"`, `"overlay"`, or `"modal" `types.
40
- *
41
- * ![Visualization of different types](https://wxt.dev/content-script-ui-type.png)
42
- */
43
- type ContentScriptPositioningOptions = ContentScriptInlinePositioningOptions | ContentScriptOverlayPositioningOptions | ContentScriptModalPositioningOptions;
44
- interface ContentScriptAnchoredOptions {
10
+ interface IframeContentScriptUi<TMounted> extends ContentScriptUi<TMounted> {
45
11
  /**
46
- * A CSS selector, element, or function that returns one of the two. Along with `append`, the
47
- * `anchor` dictates where in the page the UI will be added.
12
+ * The iframe added to the DOM.
48
13
  */
49
- anchor?: string | Element | null | undefined | (() => string | Element | null | undefined);
14
+ iframe: HTMLIFrameElement;
50
15
  /**
51
- * In combination with `anchor`, decide how to add the UI to the DOM.
52
- *
53
- * - `"last"` (default) - Add the UI as the last child of the `anchor` element
54
- * - `"first"` - Add the UI as the last child of the `anchor` element
55
- * - `"replace"` - Replace the `anchor` element with the UI.
56
- * - `"before"` - Add the UI as the sibling before the `anchor` element
57
- * - `"after"` - Add the UI as the sibling after the `anchor` element
58
- * - `(anchor, ui) => void` - Customizable function that let's you add the UI to the DOM
16
+ * A wrapper div that assists in positioning.
59
17
  */
60
- append?: ContentScriptAppendMode | ((anchor: Element, ui: Element) => void);
18
+ wrapper: HTMLDivElement;
61
19
  }
62
-
63
- /**
64
- * Utility for mounting content script UI's with isolated styles and controlled event bubbling.
65
- * Automatically removed from the DOM when the content script's context is invalidated.
66
- *
67
- * See https://wxt.dev/guide/content-script-ui.html for full documentation.
68
- *
69
- * @example
70
- * // entrypoints/example-ui.content/index.ts
71
- * import "./style.css"
72
- *
73
- * export default defineContentScript({
74
- * matches: ["*://*.google.com/*"],
75
- * cssInjectionMode: "ui",
76
- *
77
- * async main(ctx) {
78
- * const ui = await createContentScriptUi(ctx, {
79
- * name: "example-overlay",
80
- * type: "modal",
81
- * mount(container) {
82
- * const app = document.createElement("div");
83
- * app.textContent = "Content Script UI";
84
- * container.append(app);
85
- * },
86
- * })
87
- * ui.mount();
88
- * }
89
- * })
90
- */
91
- declare function createContentScriptUi<TApp>(ctx: ContentScriptContext, options: ContentScriptUiOptions<TApp>): Promise<ContentScriptUi<TApp>>;
92
- interface ContentScriptUi<TApp> {
20
+ interface ShadowRootContentScriptUi<TMounted> extends ContentScriptUi<TMounted> {
93
21
  /**
94
22
  * The `HTMLElement` hosting the shadow root used to isolate the UI's styles. This is the element
95
23
  * that get's added to the DOM. This element's style is not isolated from the webpage.
@@ -104,10 +32,8 @@ interface ContentScriptUi<TApp> {
104
32
  * The shadow root performing the isolation.
105
33
  */
106
34
  shadow: ShadowRoot;
107
- /**
108
- * Custom data returned from the `options.mount` function.
109
- */
110
- mounted: TApp;
35
+ }
36
+ interface ContentScriptUi<TMounted> {
111
37
  /**
112
38
  * Function that mounts or remounts the UI on the page.
113
39
  */
@@ -116,32 +42,65 @@ interface ContentScriptUi<TApp> {
116
42
  * Function that removes the UI from the webpage.
117
43
  */
118
44
  remove: () => void;
45
+ /**>
46
+ * Custom data returned from the `options.mount` function.
47
+ */
48
+ mounted: TMounted | undefined;
119
49
  }
120
- type ContentScriptUiOptions<TApp> = ContentScriptPositioningOptions & ContentScriptAnchoredOptions & {
50
+ type ContentScriptUiOptions<TMounted> = ContentScriptPositioningOptions & ContentScriptAnchoredOptions & {
121
51
  /**
122
- * The name of the custom component used to host the ShadowRoot. Must be kebab-case.
52
+ * Callback called before the UI is removed from the webpage. Use to cleanup your UI, like
53
+ * unmounting your Vue or React apps.
123
54
  */
124
- name: string;
55
+ onRemove?: (mounted: TMounted | undefined) => void;
56
+ };
57
+ type IntegratedContentScriptUiOptions<TMounted> = ContentScriptUiOptions<TMounted> & {
58
+ /**
59
+ * Tag used to create the wrapper element.
60
+ *
61
+ * @default "div"
62
+ */
63
+ tag?: string;
125
64
  /**
126
65
  * Callback executed when mounting the UI. This function should create and append the UI to the
127
- * `container` element. It is called every time `ui.mount()` is called
66
+ * `wrapper` element. It is called every time `ui.mount()` is called.
128
67
  *
129
68
  * Optionally return a value that can be accessed at `ui.mounted` or in the `onRemove` callback.
130
69
  */
131
- mount: (container: Element) => TApp;
70
+ onMount: (wrapper: HTMLElement) => TMounted;
71
+ };
72
+ type IframeContentScriptUiOptions<TMounted> = ContentScriptUiOptions<TMounted> & {
132
73
  /**
133
- * Callback called when the UI is removed from the webpage. Use to cleanup your UI, like
134
- * unmounting your vue or react apps.
74
+ * The path to the HTML page that will be shown in the iframe. This string is passed into
75
+ * `browser.runtime.getURL`.
135
76
  */
136
- onRemove?: (mounted: TApp) => void;
77
+ page: PublicPath;
78
+ /**
79
+ * Callback executed when mounting the UI. Use this function to customize the iframe or wrapper
80
+ * element's appearance. It is called every time `ui.mount()` is called.
81
+ *
82
+ * Optionally return a value that can be accessed at `ui.mounted` or in the `onRemove` callback.
83
+ */
84
+ onMount?: (wrapper: HTMLElement, iframe: HTMLIFrameElement) => TMounted;
85
+ };
86
+ type ShadowRootContentScriptUiOptions<TMounted> = ContentScriptUiOptions<TMounted> & {
87
+ /**
88
+ * The name of the custom component used to host the ShadowRoot. Must be kebab-case.
89
+ */
90
+ name: string;
137
91
  /**
138
92
  * Custom CSS text to apply to the UI. If your content script imports/generates CSS and you've
139
93
  * set `cssInjectionMode: "ui"`, the imported CSS will be included automatically. You do not need
140
94
  * to pass those styles in here. This is for any additional styles not in the imported CSS.
141
- *
142
- * See https://wxt.dev/guide/content-script-ui.html for more info.
143
95
  */
144
96
  css?: string;
97
+ /**
98
+ * ShadowRoot's mode.
99
+ *
100
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/mode
101
+ * @default "open"
102
+ */
103
+ mode?: 'open' | 'closed';
145
104
  /**
146
105
  * When enabled, `event.stopPropagation` will be called on events trying to bubble out of the
147
106
  * shadow root.
@@ -151,51 +110,91 @@ type ContentScriptUiOptions<TApp> = ContentScriptPositioningOptions & ContentScr
151
110
  * - Set to an array of event names to stop the propagation of a custom list of events
152
111
  */
153
112
  isolateEvents?: boolean | string[];
113
+ /**
114
+ * Callback executed when mounting the UI. This function should create and append the UI to the
115
+ * `uiContainer` element. It is called every time `ui.mount()` is called.
116
+ *
117
+ * Optionally return a value that can be accessed at `ui.mounted` or in the `onRemove` callback.
118
+ */
119
+ onMount: (uiContainer: HTMLElement, shadow: ShadowRoot, shadowHost: HTMLElement) => TMounted;
154
120
  };
155
-
121
+ type ContentScriptOverlayAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
156
122
  /**
157
- * Utility for mounting a content script UI inside an iframe. Automatically removed from the DOM
158
- * when the content script's context is invalidated.
159
- *
160
- * See https://wxt.dev/entrypoints/content-scripts.html#iframe for full documentation.
161
- *
162
- * @example
163
- * export default defineContentScript({
164
- * matches: ["*://*.google.com/*"],
165
- *
166
- * main(ctx) {
167
- * const ui = await createContentScriptIframe(ctx, {
168
- * page: "/content-script-overlay.html",
169
- * type: "modal",
170
- * })
171
- * ui.mount();
172
- * }
173
- * })
123
+ * ![Visualization of different append modes](https://wxt.dev/content-script-ui-append.png)
174
124
  */
175
- declare function createContentScriptIframe(ctx: ContentScriptContext, options: ContentScriptIframeOptions): ContentScriptIframe;
176
- interface ContentScriptIframe {
125
+ type ContentScriptAppendMode = 'last' | 'first' | 'replace' | 'before' | 'after' | ((anchor: Element, ui: Element) => void);
126
+ interface ContentScriptInlinePositioningOptions {
127
+ position: 'inline';
128
+ }
129
+ interface ContentScriptOverlayPositioningOptions {
130
+ position: 'overlay';
177
131
  /**
178
- * The iframe added to the DOM.
132
+ * The `z-index` used on the `wrapper` element. Set to a positive number to show your UI over website
133
+ * content.
179
134
  */
180
- iframe: HTMLIFrameElement;
135
+ zIndex?: number;
181
136
  /**
182
- * A wrapper div that assists in positioning.
137
+ * When using `type: "overlay"`, the mounted element is 0px by 0px in size. Alignment specifies
138
+ * which corner is aligned with that 0x0 pixel space.
139
+ *
140
+ * ![Visualization of alignment options](https://wxt.dev/content-script-ui-alignment.png)
141
+ *
142
+ * @default "top-left"
183
143
  */
184
- wrapper: HTMLDivElement;
144
+ alignment?: ContentScriptOverlayAlignment;
145
+ }
146
+ interface ContentScriptModalPositioningOptions {
147
+ position: 'modal';
185
148
  /**
186
- * Function that mounts or remounts the UI on the page.
149
+ * The `z-index` used on the `shadowHost`. Set to a positive number to show your UI over website
150
+ * content.
187
151
  */
188
- mount: () => void;
152
+ zIndex?: number;
153
+ }
154
+ /**
155
+ * Choose between `"inline"`, `"overlay"`, or `"modal" `types.
156
+ *
157
+ * ![Visualization of different types](https://wxt.dev/content-script-ui-type.png)
158
+ */
159
+ type ContentScriptPositioningOptions = ContentScriptInlinePositioningOptions | ContentScriptOverlayPositioningOptions | ContentScriptModalPositioningOptions;
160
+ interface ContentScriptAnchoredOptions {
189
161
  /**
190
- * Function that removes the UI from the webpage.
162
+ * A CSS selector, element, or function that returns one of the two. Along with `append`, the
163
+ * `anchor` dictates where in the page the UI will be added.
191
164
  */
192
- remove: () => void;
193
- }
194
- type ContentScriptIframeOptions = ContentScriptPositioningOptions & ContentScriptAnchoredOptions & {
165
+ anchor?: string | Element | null | undefined | (() => string | Element | null | undefined);
195
166
  /**
196
- * The path to the unlisted HTML file to display in the iframe.
167
+ * In combination with `anchor`, decide how to add the UI to the DOM.
168
+ *
169
+ * - `"last"` (default) - Add the UI as the last child of the `anchor` element
170
+ * - `"first"` - Add the UI as the last child of the `anchor` element
171
+ * - `"replace"` - Replace the `anchor` element with the UI.
172
+ * - `"before"` - Add the UI as the sibling before the `anchor` element
173
+ * - `"after"` - Add the UI as the sibling after the `anchor` element
174
+ * - `(anchor, ui) => void` - Customizable function that let's you add the UI to the DOM
197
175
  */
198
- page: wxt_browser.PublicPath;
199
- };
176
+ append?: ContentScriptAppendMode | ((anchor: Element, ui: Element) => void);
177
+ }
178
+
179
+ /**
180
+ * Create a content script UI without any isolation.
181
+ *
182
+ * @see https://wxt.dev/guide/content-script-ui.html#integrated
183
+ */
184
+ declare function createIntegratedUi<TMounted>(ctx: ContentScriptContext, options: IntegratedContentScriptUiOptions<TMounted>): IntegratedContentScriptUi<TMounted>;
185
+ /**
186
+ * Create a content script UI using an iframe.
187
+ *
188
+ * @see https://wxt.dev/guide/content-script-ui.html#iframe
189
+ */
190
+ declare function createIframeUi<TMounted>(ctx: ContentScriptContext, options: IframeContentScriptUiOptions<TMounted>): IframeContentScriptUi<TMounted>;
191
+ /**
192
+ * Create a content script UI inside a [`ShadowRoot`](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot).
193
+ *
194
+ * > This function is async because it has to load the CSS via a network call.
195
+ *
196
+ * @see https://wxt.dev/guide/content-script-ui.html#shadowroot
197
+ */
198
+ declare function createShadowRootUi<TMounted>(ctx: ContentScriptContext, options: ShadowRootContentScriptUiOptions<TMounted>): Promise<ShadowRootContentScriptUi<TMounted>>;
200
199
 
201
- export { type ContentScriptAnchoredOptions, type ContentScriptAppendMode, ContentScriptContext, type ContentScriptIframe, type ContentScriptIframeOptions, type ContentScriptInlinePositioningOptions, type ContentScriptModalPositioningOptions, type ContentScriptOverlayAlignment, type ContentScriptOverlayPositioningOptions, type ContentScriptPositioningOptions, type ContentScriptUi, type ContentScriptUiOptions, createContentScriptIframe, createContentScriptUi };
200
+ export { type ContentScriptAnchoredOptions, type ContentScriptAppendMode, ContentScriptContext, type ContentScriptInlinePositioningOptions, type ContentScriptModalPositioningOptions, type ContentScriptOverlayAlignment, type ContentScriptOverlayPositioningOptions, type ContentScriptPositioningOptions, type ContentScriptUi, type ContentScriptUiOptions, type IframeContentScriptUi, type IframeContentScriptUiOptions, type IntegratedContentScriptUi, type IntegratedContentScriptUiOptions, type ShadowRootContentScriptUi, type ShadowRootContentScriptUiOptions, createIframeUi, createIntegratedUi, createShadowRootUi };
package/dist/client.js CHANGED
@@ -230,86 +230,59 @@ var ContentScriptContext = class _ContentScriptContext {
230
230
  }
231
231
  };
232
232
 
233
- // src/client/content-scripts/content-script-ui.ts
233
+ // src/client/content-scripts/ui/index.ts
234
234
  import { createIsolatedElement } from "@webext-core/isolated-element";
235
-
236
- // src/client/utils/content-script-ui.ts
237
- function mountContentScriptUiRoot(root, options) {
238
- const anchor = getAnchor(options);
239
- if (anchor == null)
240
- throw Error(
241
- "Failed to mount content script UI: could not find anchor element"
242
- );
243
- switch (options.append) {
244
- case void 0:
245
- case "last":
246
- anchor.append(root);
247
- break;
248
- case "first":
249
- if (anchor.firstChild) {
250
- anchor.insertBefore(root, anchor.firstChild);
251
- } else {
252
- anchor.append(root);
253
- }
254
- break;
255
- case "replace":
256
- anchor.replaceWith(root);
257
- break;
258
- case "after":
259
- anchor.replaceWith(anchor, root);
260
- break;
261
- case "before":
262
- anchor.replaceWith(root, anchor);
263
- break;
264
- default:
265
- options.append(anchor, root);
266
- break;
267
- }
268
- }
269
- function applyContentScriptUiPosition(root, positionedElement, options) {
270
- if (options.type !== "inline") {
271
- if (options.zIndex != null)
272
- root.style.zIndex = String(options.zIndex);
273
- root.style.overflow = "visible";
274
- root.style.position = "relative";
275
- root.style.width = "0";
276
- root.style.height = "0";
277
- root.style.display = "block";
278
- if (positionedElement) {
279
- if (options.type === "overlay") {
280
- positionedElement.style.position = "absolute";
281
- if (options.alignment?.startsWith("bottom-"))
282
- positionedElement.style.bottom = "0";
283
- else
284
- positionedElement.style.top = "0";
285
- if (options.alignment?.endsWith("-right"))
286
- positionedElement.style.right = "0";
287
- else
288
- positionedElement.style.left = "0";
289
- } else {
290
- positionedElement.style.position = "fixed";
291
- positionedElement.style.top = "0";
292
- positionedElement.style.bottom = "0";
293
- positionedElement.style.left = "0";
294
- positionedElement.style.right = "0";
295
- }
296
- }
297
- }
235
+ function createIntegratedUi(ctx, options) {
236
+ const wrapper = document.createElement(options.tag || "div");
237
+ wrapper.setAttribute("data-wxt-integrated", "");
238
+ let mounted = void 0;
239
+ const mount = () => {
240
+ applyPosition(wrapper, void 0, options);
241
+ mountUi(wrapper, options);
242
+ mounted = options.onMount?.(wrapper);
243
+ };
244
+ const remove = () => {
245
+ options.onRemove?.(mounted);
246
+ wrapper.remove();
247
+ };
248
+ ctx.onInvalidated(remove);
249
+ return {
250
+ mounted,
251
+ wrapper,
252
+ mount,
253
+ remove
254
+ };
298
255
  }
299
- function getAnchor(options) {
300
- if (options.anchor == null)
301
- return document.body;
302
- let resolved = typeof options.anchor === "function" ? options.anchor() : options.anchor;
303
- if (typeof resolved === "string")
304
- return document.querySelector(resolved) ?? void 0;
305
- return resolved ?? void 0;
256
+ function createIframeUi(ctx, options) {
257
+ const wrapper = document.createElement("div");
258
+ wrapper.setAttribute("data-wxt-iframe", "");
259
+ const iframe = document.createElement("iframe");
260
+ iframe.src = browser.runtime.getURL(options.page);
261
+ wrapper.appendChild(iframe);
262
+ let mounted = void 0;
263
+ const mount = () => {
264
+ applyPosition(wrapper, iframe, options);
265
+ mountUi(wrapper, options);
266
+ mounted = options.onMount?.(wrapper, iframe);
267
+ };
268
+ const remove = () => {
269
+ options.onRemove?.(mounted);
270
+ wrapper.remove();
271
+ };
272
+ ctx.onInvalidated(remove);
273
+ return {
274
+ mounted,
275
+ iframe,
276
+ wrapper,
277
+ mount,
278
+ remove
279
+ };
306
280
  }
307
-
308
- // src/client/content-scripts/content-script-ui.ts
309
- async function createContentScriptUi(ctx, options) {
281
+ async function createShadowRootUi(ctx, options) {
310
282
  const css = [options.css ?? ""];
311
283
  if (ctx.options?.cssInjectionMode === "ui") {
312
- css.push(await loadCss());
284
+ const entryCss = await loadCss();
285
+ css.push(entryCss.replaceAll(":root", ":host"));
313
286
  }
314
287
  const {
315
288
  isolatedElement: uiContainer,
@@ -320,18 +293,15 @@ async function createContentScriptUi(ctx, options) {
320
293
  css: {
321
294
  textContent: css.join("\n").trim()
322
295
  },
323
- mode: "open",
296
+ mode: options.mode ?? "open",
324
297
  isolateEvents: options.isolateEvents
325
298
  });
299
+ shadowHost.setAttribute("data-wxt-shadow-root", "");
326
300
  let mounted;
327
301
  const mount = () => {
328
- mounted = options.mount(uiContainer);
329
- mountContentScriptUiRoot(shadowHost, options);
330
- applyContentScriptUiPosition(
331
- shadowHost,
332
- shadow.querySelector("html"),
333
- options
334
- );
302
+ mounted = options.onMount(uiContainer, shadow, shadowHost);
303
+ mountUi(shadowHost, options);
304
+ applyPosition(shadowHost, shadow.querySelector("html"), options);
335
305
  };
336
306
  const remove = () => {
337
307
  shadowHost.remove();
@@ -349,12 +319,81 @@ async function createContentScriptUi(ctx, options) {
349
319
  mounted
350
320
  };
351
321
  }
322
+ function applyPosition(root, positionedElement, options) {
323
+ if (options.position === "inline")
324
+ return;
325
+ if (options.zIndex != null)
326
+ root.style.zIndex = String(options.zIndex);
327
+ root.style.overflow = "visible";
328
+ root.style.position = "relative";
329
+ root.style.width = "0";
330
+ root.style.height = "0";
331
+ root.style.display = "block";
332
+ if (positionedElement) {
333
+ if (options.position === "overlay") {
334
+ positionedElement.style.position = "absolute";
335
+ if (options.alignment?.startsWith("bottom-"))
336
+ positionedElement.style.bottom = "0";
337
+ else
338
+ positionedElement.style.top = "0";
339
+ if (options.alignment?.endsWith("-right"))
340
+ positionedElement.style.right = "0";
341
+ else
342
+ positionedElement.style.left = "0";
343
+ } else {
344
+ positionedElement.style.position = "fixed";
345
+ positionedElement.style.top = "0";
346
+ positionedElement.style.bottom = "0";
347
+ positionedElement.style.left = "0";
348
+ positionedElement.style.right = "0";
349
+ }
350
+ }
351
+ }
352
+ function getAnchor(options) {
353
+ if (options.anchor == null)
354
+ return document.body;
355
+ let resolved = typeof options.anchor === "function" ? options.anchor() : options.anchor;
356
+ if (typeof resolved === "string")
357
+ return document.querySelector(resolved) ?? void 0;
358
+ return resolved ?? void 0;
359
+ }
360
+ function mountUi(root, options) {
361
+ const anchor = getAnchor(options);
362
+ if (anchor == null)
363
+ throw Error(
364
+ "Failed to mount content script UI: could not find anchor element"
365
+ );
366
+ switch (options.append) {
367
+ case void 0:
368
+ case "last":
369
+ anchor.append(root);
370
+ break;
371
+ case "first":
372
+ if (anchor.firstChild) {
373
+ anchor.insertBefore(root, anchor.firstChild);
374
+ } else {
375
+ anchor.append(root);
376
+ }
377
+ break;
378
+ case "replace":
379
+ anchor.replaceWith(root);
380
+ break;
381
+ case "after":
382
+ anchor.replaceWith(anchor, root);
383
+ break;
384
+ case "before":
385
+ anchor.replaceWith(root, anchor);
386
+ break;
387
+ default:
388
+ options.append(anchor, root);
389
+ break;
390
+ }
391
+ }
352
392
  async function loadCss() {
353
393
  const url = browser.runtime.getURL(`/content-scripts/${__ENTRYPOINT__}.css`);
354
394
  try {
355
395
  const res = await fetch(url);
356
- const css = await res.text();
357
- return css.replaceAll(":root", ":host");
396
+ return await res.text();
358
397
  } catch (err) {
359
398
  logger.warn(
360
399
  `Failed to load styles @ ${url}. Did you forget to import the stylesheet in your entrypoint?`,
@@ -363,31 +402,9 @@ async function loadCss() {
363
402
  return "";
364
403
  }
365
404
  }
366
-
367
- // src/client/content-scripts/content-script-iframe.ts
368
- function createContentScriptIframe(ctx, options) {
369
- const wrapper = document.createElement("div");
370
- wrapper.classList.add("wxt-iframe-wrapper");
371
- const iframe = document.createElement("iframe");
372
- iframe.src = browser.runtime.getURL(options.page);
373
- wrapper.appendChild(iframe);
374
- const mount = () => {
375
- applyContentScriptUiPosition(wrapper, iframe, options);
376
- mountContentScriptUiRoot(wrapper, options);
377
- };
378
- const remove = () => {
379
- wrapper.remove();
380
- };
381
- ctx.onInvalidated(remove);
382
- return {
383
- iframe,
384
- wrapper,
385
- mount,
386
- remove
387
- };
388
- }
389
405
  export {
390
406
  ContentScriptContext,
391
- createContentScriptIframe,
392
- createContentScriptUi
407
+ createIframeUi,
408
+ createIntegratedUi,
409
+ createShadowRootUi
393
410
  };
package/dist/index.cjs CHANGED
@@ -4337,7 +4337,7 @@ function getChunkSortWeight(filename) {
4337
4337
  var import_picocolors3 = __toESM(require("picocolors"), 1);
4338
4338
 
4339
4339
  // package.json
4340
- var version = "0.13.4";
4340
+ var version = "0.14.0";
4341
4341
 
4342
4342
  // src/core/utils/log/printHeader.ts
4343
4343
  var import_consola2 = require("consola");
@@ -4831,7 +4831,10 @@ function getContentScriptCssWebAccessibleResources(config, contentScripts, conte
4831
4831
  } else {
4832
4832
  resources.push({
4833
4833
  resources: [cssFile],
4834
- matches: script.options.matches
4834
+ matches: resolvePerBrowserOption(
4835
+ script.options.matches,
4836
+ config.browser
4837
+ ).map((matchPattern) => stripPathFromMatchPattern(matchPattern))
4835
4838
  });
4836
4839
  }
4837
4840
  });
@@ -4861,6 +4864,13 @@ function addHostPermission(manifest, hostPermission) {
4861
4864
  return;
4862
4865
  manifest.host_permissions.push(hostPermission);
4863
4866
  }
4867
+ function stripPathFromMatchPattern(pattern) {
4868
+ const protocolSepIndex = pattern.indexOf("://");
4869
+ if (protocolSepIndex === -1)
4870
+ return pattern;
4871
+ const startOfPath = pattern.indexOf("/", protocolSepIndex + 3);
4872
+ return pattern.substring(0, startOfPath) + "/*";
4873
+ }
4864
4874
 
4865
4875
  // src/core/utils/building/rebuild.ts
4866
4876
  async function rebuild(config, entrypointGroups, existingOutput = {
package/dist/index.d.cts CHANGED
@@ -62,6 +62,6 @@ declare function prepare(config: InlineConfig): Promise<void>;
62
62
  */
63
63
  declare function zip(config?: InlineConfig): Promise<string[]>;
64
64
 
65
- var version = "0.13.4";
65
+ var version = "0.14.0";
66
66
 
67
67
  export { BuildOutput, ExtensionRunnerConfig, InlineConfig, UserConfig, WxtDevServer, build, clean, createServer, defineConfig, defineRunnerConfig, initialize, prepare, version, zip };
package/dist/index.d.ts CHANGED
@@ -62,6 +62,6 @@ declare function prepare(config: InlineConfig): Promise<void>;
62
62
  */
63
63
  declare function zip(config?: InlineConfig): Promise<string[]>;
64
64
 
65
- var version = "0.13.4";
65
+ var version = "0.14.0";
66
66
 
67
67
  export { BuildOutput, ExtensionRunnerConfig, InlineConfig, UserConfig, WxtDevServer, build, clean, createServer, defineConfig, defineRunnerConfig, initialize, prepare, version, zip };
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  rebuild,
16
16
  resolvePerBrowserOption,
17
17
  version
18
- } from "./chunk-DHQJ6WF5.js";
18
+ } from "./chunk-4BYWUUR2.js";
19
19
  import "./chunk-VBXJIVYU.js";
20
20
 
21
21
  // src/core/build.ts
package/dist/testing.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  tsconfigPaths,
6
6
  unimport,
7
7
  webextensionPolyfillMock
8
- } from "./chunk-DHQJ6WF5.js";
8
+ } from "./chunk-4BYWUUR2.js";
9
9
  import "./chunk-VBXJIVYU.js";
10
10
 
11
11
  // src/testing/fake-browser.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wxt",
3
3
  "type": "module",
4
- "version": "0.13.4",
4
+ "version": "0.14.0",
5
5
  "description": "Next gen framework for developing web extensions",
6
6
  "engines": {
7
7
  "node": ">=18",