@addon-core/inject-css 0.3.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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Addon Stack; Anjey Tsibylskij
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # @addon-core/inject-css
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40addon-core%2Finject-css.svg?logo=npm)](https://www.npmjs.com/package/@addon-core/inject-css)
4
+ [![npm downloads](https://img.shields.io/npm/dm/%40addon-core%2Finject-css.svg)](https://www.npmjs.com/package/@addon-core/inject-css)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md)
6
+ [![CI](https://github.com/addon-stack/inject-css/actions/workflows/ci.yml/badge.svg)](https://github.com/addon-stack/inject-css/actions/workflows/ci.yml)
7
+
8
+ A lightweight, TypeScript-ready library for injecting CSS into browser extension pages.
9
+ Automatically detects Chrome Extension Manifest V2 and V3 and delegates to the appropriate API via [@addon-core/browser](https://github.com/addon-stack/browser).
10
+
11
+ ## Table of Contents
12
+
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [Injecting CSS Code](#injecting-css-code)
16
+ - [Injecting CSS Files](#injecting-css-files)
17
+ - [Updating Options](#updating-options)
18
+ - [API](#api)
19
+ - [Options](#options)
20
+ - [Examples](#examples)
21
+ - [License](#license)
22
+
23
+ ## Installation
24
+
25
+ ### npm:
26
+
27
+ ```bash
28
+ npm install @addon-core/inject-css
29
+ ```
30
+
31
+ ### pnpm:
32
+
33
+ ```bash
34
+ pnpm add @addon-core/inject-css
35
+ ```
36
+
37
+ ### yarn:
38
+
39
+ ```bash
40
+ yarn add @addon-core/inject-css
41
+ ```
42
+
43
+
44
+ ## Usage
45
+
46
+ ```ts
47
+ import injectCss, {InjectCssOptions} from "@addon-core/inject-css";
48
+
49
+ // Initialize an injector with a target tab ID
50
+ const injector = injectCss({tabId: 123});
51
+
52
+ // Inject raw CSS code into the page
53
+ await injector.insert("body { background-color: #f0f0f0; }");
54
+
55
+ // Inject one or more CSS files (paths relative to extension)
56
+ await injector.file("styles/main.css");
57
+ await injector.file(["styles/reset.css", "styles/theme.css"]);
58
+
59
+ // Update options dynamically and reuse the injector
60
+ injector.options({frameId: true, origin: "USER"});
61
+ await injector.insert("p { color: red; }");
62
+ ```
63
+
64
+ ### Injecting CSS Code
65
+
66
+ Use the `insert(css: string)` method to inject raw CSS code.
67
+
68
+ ### Injecting CSS Files
69
+
70
+ Use the `file(files: string | string[])` method to inject CSS file(s).
71
+
72
+ ### Updating Options
73
+
74
+ Use the `options(opts: Partial<InjectCssOptions>)` method to merge or override options on an existing injector instance.
75
+
76
+ ## API
77
+
78
+ ### `injectCss(options: InjectCssOptions): InjectCssContract`
79
+
80
+ Creates a new CSS injector instance. Detects the manifest version (V2 or V3) via `@addon-core/browser` and delegates to the appropriate implementation.
81
+
82
+ #### `InjectCssContract`
83
+
84
+ - `insert(css: string): Promise<void>` — Inject raw CSS code.
85
+ - `file(files: string | string[]): Promise<void>` — Inject one or more CSS files.
86
+ - `options(opts: Partial<InjectCssOptions>): this` — Update injector options.
87
+
88
+ ## Options
89
+
90
+ The injector accepts the following options (passed to `injectCss(options)` and/or `injector.options(opts)`):
91
+
92
+ | Option | Type | Description |
93
+ | --------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------- |
94
+ | tabId | number | Required. Target browser tab ID. |
95
+ | frameId | boolean \| number \| number[] | Optional. Select frames to inject into: `true` for all frames; number or array for specific. |
96
+ | matchAboutBlank | boolean | Optional. (V2 only) Include `about:blank` and similar subframes. Defaults to `true`. |
97
+ | runAt | 'document_start' \| 'document_end' \| 'document_idle' | Optional. (V2 only) Injection timing, matches Chrome's `runAt` in `insertCSS`. |
98
+ | documentId | string \| string[] | Optional. (V3 only) Document IDs for scripting targets. |
99
+ | origin | 'AUTHOR' \| 'USER' | Optional. CSS origin matching Chrome's API (`cssOrigin` in V2, `origin` in V3). |
100
+
101
+ ## Examples
102
+
103
+ ```ts
104
+ import injectCss from "@addon-core/inject-css";
105
+
106
+ // Initialize with a mix of options
107
+ const injector = injectCss({
108
+ tabId: 123,
109
+ frameId: [1, 2], // (V2 & V3)
110
+ runAt: "document_end", // (V2 only)
111
+ documentId: "main-doc-id", // (V3 only)
112
+ origin: "AUTHOR", // 'AUTHOR' or 'USER'
113
+ });
114
+
115
+ // Inject raw CSS code
116
+ await injector.insert("body { background-color: #fafafa; }");
117
+
118
+ // Inject one or more CSS files
119
+ await injector.file(["styles/reset.css", "styles/theme.css"]);
120
+ ```
121
+
122
+
123
+ ## License
124
+
125
+ MIT © Addon Stack
package/dist/index.cjs ADDED
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ default: () => index_default
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+ var import_browser3 = require("@addon-core/browser");
27
+
28
+ // src/InjectCssV2.ts
29
+ var import_browser = require("@addon-core/browser");
30
+
31
+ // src/AbstractInjectCss.ts
32
+ var AbstractInjectCss_default = class {
33
+ constructor(_options) {
34
+ this._options = _options;
35
+ }
36
+ options(options) {
37
+ this._options = { ...this._options, ...options, tabId: options.tabId ?? this._options.tabId };
38
+ return this;
39
+ }
40
+ get frameIds() {
41
+ const { frameId } = this._options;
42
+ return typeof frameId === "number" ? [frameId] : typeof frameId !== "boolean" ? frameId : void 0;
43
+ }
44
+ get allFrames() {
45
+ const { frameId } = this._options;
46
+ return typeof frameId === "boolean" ? frameId : void 0;
47
+ }
48
+ get matchAboutBlank() {
49
+ const { matchAboutBlank } = this._options;
50
+ return typeof matchAboutBlank === "boolean" ? matchAboutBlank : true;
51
+ }
52
+ };
53
+
54
+ // src/InjectCssV2.ts
55
+ var InjectCssV2_default = class extends AbstractInjectCss_default {
56
+ async insert(code) {
57
+ const { tabId, runAt } = this._options;
58
+ const details = {
59
+ code,
60
+ runAt,
61
+ cssOrigin: this.cssOrigin,
62
+ matchAboutBlank: this.matchAboutBlank
63
+ };
64
+ if (this.allFrames) {
65
+ await (0, import_browser.insertCssTab)(tabId, { ...details, allFrames: true });
66
+ } else if (this.frameIds) {
67
+ await Promise.all(this.frameIds.map((frameId) => (0, import_browser.insertCssTab)(tabId, { ...details, frameId })));
68
+ } else {
69
+ await (0, import_browser.insertCssTab)(tabId, details);
70
+ }
71
+ }
72
+ async file(files) {
73
+ const { tabId, runAt } = this._options;
74
+ const fileList = typeof files === "string" ? [files] : files;
75
+ const injectTasks = [];
76
+ for (const file of fileList) {
77
+ const details = {
78
+ file,
79
+ runAt,
80
+ cssOrigin: this.cssOrigin,
81
+ matchAboutBlank: this.matchAboutBlank
82
+ };
83
+ if (this.allFrames) {
84
+ injectTasks.push((0, import_browser.insertCssTab)(tabId, { ...details, allFrames: true }));
85
+ } else if (this.frameIds) {
86
+ injectTasks.push(...this.frameIds.map((frameId) => (0, import_browser.insertCssTab)(tabId, { ...details, frameId })));
87
+ } else {
88
+ injectTasks.push((0, import_browser.insertCssTab)(tabId, details));
89
+ }
90
+ }
91
+ await Promise.all(injectTasks);
92
+ }
93
+ get cssOrigin() {
94
+ const { origin } = this._options;
95
+ return origin && origin.toLowerCase();
96
+ }
97
+ };
98
+
99
+ // src/InjectCssV3.ts
100
+ var import_browser2 = require("@addon-core/browser");
101
+ var InjectCssV3_default = class extends AbstractInjectCss_default {
102
+ async insert(css) {
103
+ await (0, import_browser2.insertCss)({
104
+ target: this.target,
105
+ origin: this._options.origin,
106
+ css
107
+ });
108
+ }
109
+ async file(fileList) {
110
+ await (0, import_browser2.insertCss)({
111
+ target: this.target,
112
+ origin: this._options.origin,
113
+ files: typeof fileList === "string" ? [fileList] : fileList
114
+ });
115
+ }
116
+ get target() {
117
+ const target = { tabId: this._options.tabId };
118
+ if (this.frameIds && this.frameIds.length > 0) {
119
+ return { ...target, frameIds: this.frameIds };
120
+ }
121
+ if (this.allFrames === true) {
122
+ return { ...target, allFrames: true };
123
+ }
124
+ const isFirefox = !!browser().runtime.getBrowserInfo;
125
+ if (!isFirefox) {
126
+ const documentIds = this.documentIds;
127
+ if (documentIds && documentIds.length > 0) {
128
+ return { ...target, documentIds };
129
+ }
130
+ }
131
+ return target;
132
+ }
133
+ get documentIds() {
134
+ const { documentId } = this._options;
135
+ return typeof documentId === "string" ? [documentId] : documentId;
136
+ }
137
+ };
138
+
139
+ // src/index.ts
140
+ var index_default = (options) => {
141
+ return (0, import_browser3.isManifestVersion3)() ? new InjectCssV3_default(options) : new InjectCssV2_default(options);
142
+ };
143
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/InjectCssV2.ts","../src/AbstractInjectCss.ts","../src/InjectCssV3.ts"],"sourcesContent":["import {isManifestVersion3} from \"@addon-core/browser\";\nimport InjectCssV2 from \"./InjectCssV2\";\nimport InjectCssV3 from \"./InjectCssV3\";\nimport type {InjectCssContract, InjectCssOptions} from \"./types\";\n\nexport type {InjectCssContract, InjectCssOptions};\n\nexport default (options: InjectCssOptions): InjectCssContract => {\n return isManifestVersion3() ? new InjectCssV3(options) : new InjectCssV2(options);\n};\n","import {insertCssTab} from \"@addon-core/browser\";\nimport AbstractInjectCss from \"./AbstractInjectCss\";\n\ntype CSSOrigin = chrome.extensionTypes.CSSOrigin;\ntype InjectDetails = chrome.extensionTypes.InjectDetails;\n\nexport default class extends AbstractInjectCss {\n public async insert(code: string): Promise<void> {\n const {tabId, runAt} = this._options;\n\n const details: InjectDetails = {\n code,\n runAt,\n cssOrigin: this.cssOrigin,\n matchAboutBlank: this.matchAboutBlank,\n };\n\n if (this.allFrames) {\n await insertCssTab(tabId, {...details, allFrames: true});\n } else if (this.frameIds) {\n await Promise.all(this.frameIds.map(frameId => insertCssTab(tabId, {...details, frameId})));\n } else {\n await insertCssTab(tabId, details);\n }\n }\n\n public async file(files: string | string[]): Promise<void> {\n const {tabId, runAt} = this._options;\n\n const fileList = typeof files === \"string\" ? [files] : files;\n\n const injectTasks: Promise<any>[] = [];\n\n for (const file of fileList) {\n const details: InjectDetails = {\n file,\n runAt,\n cssOrigin: this.cssOrigin,\n matchAboutBlank: this.matchAboutBlank,\n };\n\n if (this.allFrames) {\n injectTasks.push(insertCssTab(tabId, {...details, allFrames: true}));\n } else if (this.frameIds) {\n injectTasks.push(...this.frameIds.map(frameId => insertCssTab(tabId, {...details, frameId})));\n } else {\n injectTasks.push(insertCssTab(tabId, details));\n }\n }\n\n await Promise.all(injectTasks);\n }\n\n protected get cssOrigin(): CSSOrigin | undefined {\n const {origin} = this._options;\n\n return origin && (origin.toLowerCase() as CSSOrigin);\n }\n}\n","import type {InjectCssContract, InjectCssOptions} from \"./types\";\n\nexport default abstract class implements InjectCssContract {\n constructor(protected _options: InjectCssOptions) {}\n\n public options(options: Partial<InjectCssOptions>): this {\n this._options = {...this._options, ...options, tabId: options.tabId ?? this._options.tabId};\n\n return this;\n }\n\n public abstract insert(css: string): Promise<void>;\n\n public abstract file(files: string | string[]): Promise<void>;\n\n protected get frameIds(): number[] | undefined {\n const {frameId} = this._options;\n\n return typeof frameId === \"number\" ? [frameId] : typeof frameId !== \"boolean\" ? frameId : undefined;\n }\n\n protected get allFrames(): boolean | undefined {\n const {frameId} = this._options;\n\n return typeof frameId === \"boolean\" ? frameId : undefined;\n }\n\n protected get matchAboutBlank(): boolean {\n const {matchAboutBlank} = this._options;\n\n return typeof matchAboutBlank === \"boolean\" ? matchAboutBlank : true;\n }\n}\n","import {insertCss} from \"@addon-core/browser\";\nimport AbstractInjectCss from \"./AbstractInjectCss\";\n\ntype InjectionTarget = chrome.scripting.InjectionTarget;\n\nexport default class extends AbstractInjectCss {\n public async insert(css: string): Promise<void> {\n await insertCss({\n target: this.target,\n origin: this._options.origin,\n css,\n });\n }\n\n public async file(fileList: string | string[]): Promise<void> {\n await insertCss({\n target: this.target,\n origin: this._options.origin,\n files: typeof fileList === \"string\" ? [fileList] : fileList,\n });\n }\n\n protected get target(): InjectionTarget {\n const target = {tabId: this._options.tabId};\n\n if (this.frameIds && this.frameIds.length > 0) {\n return {...target, frameIds: this.frameIds};\n }\n\n if (this.allFrames === true) {\n return {...target, allFrames: true};\n }\n\n // Firefox does not support `documentIds` in the target\n // getBrowserInfo is only available in firefox\n // @ts-expect-error\n const isFirefox = !!browser().runtime.getBrowserInfo;\n\n if (!isFirefox) {\n const documentIds = this.documentIds;\n\n if (documentIds && documentIds.length > 0) {\n return {...target, documentIds};\n }\n }\n\n return target;\n }\n\n protected get documentIds(): string[] | undefined {\n const {documentId} = this._options;\n\n return typeof documentId === \"string\" ? [documentId] : documentId;\n }\n}\n"],"mappings":"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","names":["import_browser","import_browser"]}
@@ -0,0 +1,19 @@
1
+ type RunAt = chrome.extensionTypes.RunAt;
2
+ type StyleOrigin = chrome.scripting.StyleOrigin;
3
+ interface InjectCssOptions {
4
+ tabId: number;
5
+ frameId?: boolean | number | number[];
6
+ matchAboutBlank?: boolean;
7
+ origin?: StyleOrigin;
8
+ runAt?: RunAt;
9
+ documentId?: string | string[];
10
+ }
11
+ interface InjectCssContract {
12
+ insert: (css: string) => Promise<void>;
13
+ file: (files: string | string[]) => Promise<void>;
14
+ options: (options: Partial<InjectCssOptions>) => this;
15
+ }
16
+
17
+ declare const _default: (options: InjectCssOptions) => InjectCssContract;
18
+
19
+ export { type InjectCssContract, type InjectCssOptions, _default as default };
package/dist/index.js ADDED
@@ -0,0 +1,122 @@
1
+ // src/index.ts
2
+ import { isManifestVersion3 } from "@addon-core/browser";
3
+
4
+ // src/InjectCssV2.ts
5
+ import { insertCssTab } from "@addon-core/browser";
6
+
7
+ // src/AbstractInjectCss.ts
8
+ var AbstractInjectCss_default = class {
9
+ constructor(_options) {
10
+ this._options = _options;
11
+ }
12
+ options(options) {
13
+ this._options = { ...this._options, ...options, tabId: options.tabId ?? this._options.tabId };
14
+ return this;
15
+ }
16
+ get frameIds() {
17
+ const { frameId } = this._options;
18
+ return typeof frameId === "number" ? [frameId] : typeof frameId !== "boolean" ? frameId : void 0;
19
+ }
20
+ get allFrames() {
21
+ const { frameId } = this._options;
22
+ return typeof frameId === "boolean" ? frameId : void 0;
23
+ }
24
+ get matchAboutBlank() {
25
+ const { matchAboutBlank } = this._options;
26
+ return typeof matchAboutBlank === "boolean" ? matchAboutBlank : true;
27
+ }
28
+ };
29
+
30
+ // src/InjectCssV2.ts
31
+ var InjectCssV2_default = class extends AbstractInjectCss_default {
32
+ async insert(code) {
33
+ const { tabId, runAt } = this._options;
34
+ const details = {
35
+ code,
36
+ runAt,
37
+ cssOrigin: this.cssOrigin,
38
+ matchAboutBlank: this.matchAboutBlank
39
+ };
40
+ if (this.allFrames) {
41
+ await insertCssTab(tabId, { ...details, allFrames: true });
42
+ } else if (this.frameIds) {
43
+ await Promise.all(this.frameIds.map((frameId) => insertCssTab(tabId, { ...details, frameId })));
44
+ } else {
45
+ await insertCssTab(tabId, details);
46
+ }
47
+ }
48
+ async file(files) {
49
+ const { tabId, runAt } = this._options;
50
+ const fileList = typeof files === "string" ? [files] : files;
51
+ const injectTasks = [];
52
+ for (const file of fileList) {
53
+ const details = {
54
+ file,
55
+ runAt,
56
+ cssOrigin: this.cssOrigin,
57
+ matchAboutBlank: this.matchAboutBlank
58
+ };
59
+ if (this.allFrames) {
60
+ injectTasks.push(insertCssTab(tabId, { ...details, allFrames: true }));
61
+ } else if (this.frameIds) {
62
+ injectTasks.push(...this.frameIds.map((frameId) => insertCssTab(tabId, { ...details, frameId })));
63
+ } else {
64
+ injectTasks.push(insertCssTab(tabId, details));
65
+ }
66
+ }
67
+ await Promise.all(injectTasks);
68
+ }
69
+ get cssOrigin() {
70
+ const { origin } = this._options;
71
+ return origin && origin.toLowerCase();
72
+ }
73
+ };
74
+
75
+ // src/InjectCssV3.ts
76
+ import { insertCss } from "@addon-core/browser";
77
+ var InjectCssV3_default = class extends AbstractInjectCss_default {
78
+ async insert(css) {
79
+ await insertCss({
80
+ target: this.target,
81
+ origin: this._options.origin,
82
+ css
83
+ });
84
+ }
85
+ async file(fileList) {
86
+ await insertCss({
87
+ target: this.target,
88
+ origin: this._options.origin,
89
+ files: typeof fileList === "string" ? [fileList] : fileList
90
+ });
91
+ }
92
+ get target() {
93
+ const target = { tabId: this._options.tabId };
94
+ if (this.frameIds && this.frameIds.length > 0) {
95
+ return { ...target, frameIds: this.frameIds };
96
+ }
97
+ if (this.allFrames === true) {
98
+ return { ...target, allFrames: true };
99
+ }
100
+ const isFirefox = !!browser().runtime.getBrowserInfo;
101
+ if (!isFirefox) {
102
+ const documentIds = this.documentIds;
103
+ if (documentIds && documentIds.length > 0) {
104
+ return { ...target, documentIds };
105
+ }
106
+ }
107
+ return target;
108
+ }
109
+ get documentIds() {
110
+ const { documentId } = this._options;
111
+ return typeof documentId === "string" ? [documentId] : documentId;
112
+ }
113
+ };
114
+
115
+ // src/index.ts
116
+ var index_default = (options) => {
117
+ return isManifestVersion3() ? new InjectCssV3_default(options) : new InjectCssV2_default(options);
118
+ };
119
+ export {
120
+ index_default as default
121
+ };
122
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/InjectCssV2.ts","../src/AbstractInjectCss.ts","../src/InjectCssV3.ts"],"sourcesContent":["import {isManifestVersion3} from \"@addon-core/browser\";\nimport InjectCssV2 from \"./InjectCssV2\";\nimport InjectCssV3 from \"./InjectCssV3\";\nimport type {InjectCssContract, InjectCssOptions} from \"./types\";\n\nexport type {InjectCssContract, InjectCssOptions};\n\nexport default (options: InjectCssOptions): InjectCssContract => {\n return isManifestVersion3() ? new InjectCssV3(options) : new InjectCssV2(options);\n};\n","import {insertCssTab} from \"@addon-core/browser\";\nimport AbstractInjectCss from \"./AbstractInjectCss\";\n\ntype CSSOrigin = chrome.extensionTypes.CSSOrigin;\ntype InjectDetails = chrome.extensionTypes.InjectDetails;\n\nexport default class extends AbstractInjectCss {\n public async insert(code: string): Promise<void> {\n const {tabId, runAt} = this._options;\n\n const details: InjectDetails = {\n code,\n runAt,\n cssOrigin: this.cssOrigin,\n matchAboutBlank: this.matchAboutBlank,\n };\n\n if (this.allFrames) {\n await insertCssTab(tabId, {...details, allFrames: true});\n } else if (this.frameIds) {\n await Promise.all(this.frameIds.map(frameId => insertCssTab(tabId, {...details, frameId})));\n } else {\n await insertCssTab(tabId, details);\n }\n }\n\n public async file(files: string | string[]): Promise<void> {\n const {tabId, runAt} = this._options;\n\n const fileList = typeof files === \"string\" ? [files] : files;\n\n const injectTasks: Promise<any>[] = [];\n\n for (const file of fileList) {\n const details: InjectDetails = {\n file,\n runAt,\n cssOrigin: this.cssOrigin,\n matchAboutBlank: this.matchAboutBlank,\n };\n\n if (this.allFrames) {\n injectTasks.push(insertCssTab(tabId, {...details, allFrames: true}));\n } else if (this.frameIds) {\n injectTasks.push(...this.frameIds.map(frameId => insertCssTab(tabId, {...details, frameId})));\n } else {\n injectTasks.push(insertCssTab(tabId, details));\n }\n }\n\n await Promise.all(injectTasks);\n }\n\n protected get cssOrigin(): CSSOrigin | undefined {\n const {origin} = this._options;\n\n return origin && (origin.toLowerCase() as CSSOrigin);\n }\n}\n","import type {InjectCssContract, InjectCssOptions} from \"./types\";\n\nexport default abstract class implements InjectCssContract {\n constructor(protected _options: InjectCssOptions) {}\n\n public options(options: Partial<InjectCssOptions>): this {\n this._options = {...this._options, ...options, tabId: options.tabId ?? this._options.tabId};\n\n return this;\n }\n\n public abstract insert(css: string): Promise<void>;\n\n public abstract file(files: string | string[]): Promise<void>;\n\n protected get frameIds(): number[] | undefined {\n const {frameId} = this._options;\n\n return typeof frameId === \"number\" ? [frameId] : typeof frameId !== \"boolean\" ? frameId : undefined;\n }\n\n protected get allFrames(): boolean | undefined {\n const {frameId} = this._options;\n\n return typeof frameId === \"boolean\" ? frameId : undefined;\n }\n\n protected get matchAboutBlank(): boolean {\n const {matchAboutBlank} = this._options;\n\n return typeof matchAboutBlank === \"boolean\" ? matchAboutBlank : true;\n }\n}\n","import {insertCss} from \"@addon-core/browser\";\nimport AbstractInjectCss from \"./AbstractInjectCss\";\n\ntype InjectionTarget = chrome.scripting.InjectionTarget;\n\nexport default class extends AbstractInjectCss {\n public async insert(css: string): Promise<void> {\n await insertCss({\n target: this.target,\n origin: this._options.origin,\n css,\n });\n }\n\n public async file(fileList: string | string[]): Promise<void> {\n await insertCss({\n target: this.target,\n origin: this._options.origin,\n files: typeof fileList === \"string\" ? [fileList] : fileList,\n });\n }\n\n protected get target(): InjectionTarget {\n const target = {tabId: this._options.tabId};\n\n if (this.frameIds && this.frameIds.length > 0) {\n return {...target, frameIds: this.frameIds};\n }\n\n if (this.allFrames === true) {\n return {...target, allFrames: true};\n }\n\n // Firefox does not support `documentIds` in the target\n // getBrowserInfo is only available in firefox\n // @ts-expect-error\n const isFirefox = !!browser().runtime.getBrowserInfo;\n\n if (!isFirefox) {\n const documentIds = this.documentIds;\n\n if (documentIds && documentIds.length > 0) {\n return {...target, documentIds};\n }\n }\n\n return target;\n }\n\n protected get documentIds(): string[] | undefined {\n const {documentId} = this._options;\n\n return typeof documentId === \"string\" ? [documentId] : documentId;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@addon-core/inject-css",
3
+ "version": "0.3.0",
4
+ "description": "A lightweight TypeScript-friendly library to inject CSS into browser extensions (Manifest V2 & V3)",
5
+ "keywords": [
6
+ "browser",
7
+ "addon",
8
+ "extension",
9
+ "google",
10
+ "chrome",
11
+ "opera",
12
+ "edge",
13
+ "firefox",
14
+ "safari",
15
+ "api",
16
+ "style",
17
+ "css"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/addon-stack/inject-css"
22
+ },
23
+ "homepage": "https://github.com/addon-stack/inject-css",
24
+ "bugs": {
25
+ "url": "https://github.com/addon-stack/inject-css/issues"
26
+ },
27
+ "license": "MIT",
28
+ "author": "Addon Stack <addonbonedev@gmail.com>",
29
+ "contributors": [
30
+ "Anjey Tsibylskij (https://github.com/atldays)"
31
+ ],
32
+ "type": "module",
33
+ "main": "dist/index.cjs",
34
+ "module": "dist/index.js",
35
+ "types": "dist/index.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "import": "./dist/index.js",
40
+ "require": "./dist/index.cjs"
41
+ }
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "sideEffects": false,
47
+ "scripts": {
48
+ "prepare": "husky",
49
+ "build": "tsup",
50
+ "build:watch": "tsup --watch",
51
+ "prepublishOnly": "npm run build",
52
+ "format": "biome format --write .",
53
+ "format:check": "biome check --formatter-enabled=true --linter-enabled=false .",
54
+ "lint": "biome check .",
55
+ "lint:fix": "biome check --write .",
56
+ "lint:fix:aggressive": "biome check --write --unsafe .",
57
+ "typecheck": "tsc -p tsconfig.json --noEmit",
58
+ "test": "jest --bail --passWithNoTests",
59
+ "test:ci": "jest --ci --passWithNoTests --coverage",
60
+ "release": "release-it"
61
+ },
62
+ "dependencies": {
63
+ "@addon-core/browser": "^0.2.2"
64
+ },
65
+ "devDependencies": {
66
+ "@biomejs/biome": "^2.2.4",
67
+ "@commitlint/cli": "^20.0.0",
68
+ "@commitlint/config-conventional": "^20.0.0",
69
+ "@release-it/conventional-changelog": "^10.0.1",
70
+ "@types/chrome": "^0.1.12",
71
+ "@types/jest": "^30.0.0",
72
+ "husky": "^9.1.7",
73
+ "jest": "^30.1.3",
74
+ "release-it": "^19.0.5",
75
+ "tsup": "^8.5.0",
76
+ "typescript": "^5.9.2"
77
+ },
78
+ "overrides": {
79
+ "glob": "^9.3.5",
80
+ "source-map": "npm:source-map-js@^1.2.0"
81
+ }
82
+ }