@charcoal-ui/icons 6.0.0-beta.0 → 6.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/css/icon.css +44 -0
- package/css/v1/index.css +10 -0
- package/css/v1/index.html +9 -0
- package/css/v1/index.story.tsx +10 -1
- package/dist/index.cjs +58 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +34 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -28
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/react/v1/16/Description.d.ts +4 -0
- package/react/v1/16/Description.d.ts.map +1 -0
- package/react/v1/16/Description.js +5 -0
- package/react/v1/index.d.ts +1 -0
- package/react/v1/index.d.ts.map +1 -1
- package/react/v1/index.js +1 -0
- package/src/PixivIcon.story.tsx +33 -2
- package/src/PixivIcon.test.tsx +215 -52
- package/src/PixivIcon.ts +38 -55
- package/src/README.mdx +7 -2
- package/src/SSR.mdx +127 -43
- package/src/calcActualSize.ts +115 -0
- package/src/index.ts +1 -0
- package/src/react/v1/16/Description.tsx +28 -0
- package/src/react/v1/index.story.tsx +6 -0
- package/src/react/v1/index.tsx +1 -0
package/dist/index.cjs
CHANGED
|
@@ -183,12 +183,58 @@ function resolveIconLoader(name) {
|
|
|
183
183
|
const __SERVER__ = typeof window === "undefined";
|
|
184
184
|
if (__SERVER__ || !(typeof HTMLElement !== "undefined")) globalThis.HTMLElement = class {};
|
|
185
185
|
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/calcActualSize.ts
|
|
188
|
+
const isPositiveFinite = (value) => typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
189
|
+
const parseIconName = (name) => {
|
|
190
|
+
if (!name.includes("/")) throw new TypeError(`"${name}" is not a valid icon name. "name" must be named like [size]/[Name].`);
|
|
191
|
+
const [size] = name.split("/");
|
|
192
|
+
if (size === "Inline") return {
|
|
193
|
+
size,
|
|
194
|
+
baseSize: 16
|
|
195
|
+
};
|
|
196
|
+
const baseSize = parseInt(size, 10);
|
|
197
|
+
if (Number.isNaN(baseSize) || baseSize <= 0) throw new TypeError(`"${name}" has invalid size prefix "${size}". Must be "Inline" or a positive number.`);
|
|
198
|
+
return {
|
|
199
|
+
size,
|
|
200
|
+
baseSize
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
function inlineSize(scale) {
|
|
204
|
+
switch (scale) {
|
|
205
|
+
case 2: return 32;
|
|
206
|
+
default: return 16;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function guidelineSize24(scale) {
|
|
210
|
+
return 24 * scale;
|
|
211
|
+
}
|
|
212
|
+
const resolveSize = ({ name, scale, unsafeNonGuidelineScale, fixedSize }) => {
|
|
213
|
+
if (isPositiveFinite(fixedSize)) return fixedSize;
|
|
214
|
+
if (fixedSize !== void 0) throw new TypeError(`fixedSize must be a positive finite number, got ${fixedSize}`);
|
|
215
|
+
const { size, baseSize } = parseIconName(name);
|
|
216
|
+
if (isPositiveFinite(unsafeNonGuidelineScale)) return baseSize * unsafeNonGuidelineScale;
|
|
217
|
+
if (unsafeNonGuidelineScale !== void 0) throw new TypeError(`unsafeNonGuidelineScale must be a positive finite number, got ${unsafeNonGuidelineScale}`);
|
|
218
|
+
const numericScale = parseInt(`${scale ?? "1"}`, 10);
|
|
219
|
+
switch (size) {
|
|
220
|
+
case "Inline": return inlineSize(numericScale);
|
|
221
|
+
case "24": return guidelineSize24(numericScale);
|
|
222
|
+
default: return baseSize;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const calcActualSize = (params) => {
|
|
226
|
+
const actualSize = resolveSize(params);
|
|
227
|
+
if (!isPositiveFinite(actualSize)) throw new TypeError(`icon size must be a positive finite number, got ${actualSize}`);
|
|
228
|
+
return actualSize;
|
|
229
|
+
};
|
|
230
|
+
|
|
186
231
|
//#endregion
|
|
187
232
|
//#region src/PixivIcon.ts
|
|
188
233
|
const attributes = [
|
|
189
234
|
"name",
|
|
190
235
|
"scale",
|
|
191
|
-
"unsafe-non-guideline-scale"
|
|
236
|
+
"unsafe-non-guideline-scale",
|
|
237
|
+
"fixed-size"
|
|
192
238
|
];
|
|
193
239
|
const ROOT_MARGIN = 50;
|
|
194
240
|
var PixivIcon = class extends HTMLElement {
|
|
@@ -224,27 +270,6 @@ var PixivIcon = class extends HTMLElement {
|
|
|
224
270
|
name
|
|
225
271
|
};
|
|
226
272
|
}
|
|
227
|
-
get forceResizedSize() {
|
|
228
|
-
if (this.props["unsafe-non-guideline-scale"] === null) return null;
|
|
229
|
-
const [size] = this.props.name.split("/");
|
|
230
|
-
const scale = Number(this.props["unsafe-non-guideline-scale"]);
|
|
231
|
-
switch (size) {
|
|
232
|
-
case "Inline": return 16 * scale;
|
|
233
|
-
default: return Number(size) * scale;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
get scaledSize() {
|
|
237
|
-
const [size] = this.props.name.split("/");
|
|
238
|
-
const scale = Number(this.props.scale ?? "1");
|
|
239
|
-
switch (size) {
|
|
240
|
-
case "Inline": switch (scale) {
|
|
241
|
-
case 2: return 32;
|
|
242
|
-
default: return 16;
|
|
243
|
-
}
|
|
244
|
-
case "24": return Number(size) * scale;
|
|
245
|
-
default: return Number(size);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
273
|
constructor() {
|
|
249
274
|
super();
|
|
250
275
|
this.attachShadow({ mode: "open" });
|
|
@@ -273,17 +298,22 @@ var PixivIcon = class extends HTMLElement {
|
|
|
273
298
|
this.loadSvg(this.props.name);
|
|
274
299
|
}
|
|
275
300
|
render() {
|
|
276
|
-
const
|
|
277
|
-
|
|
301
|
+
const { name, scale, ...rest } = this.props;
|
|
302
|
+
const unsafeNonGuidelineScale = rest["unsafe-non-guideline-scale"];
|
|
303
|
+
const fixedSize = rest["fixed-size"];
|
|
304
|
+
const size = calcActualSize({
|
|
305
|
+
name,
|
|
306
|
+
...fixedSize !== null ? { fixedSize: parseFloat(fixedSize) } : unsafeNonGuidelineScale !== null ? { unsafeNonGuidelineScale: parseFloat(unsafeNonGuidelineScale) } : { scale: scale ?? void 0 }
|
|
307
|
+
});
|
|
308
|
+
this.style.setProperty("--charcoal-icon-size", `${size}px`);
|
|
278
309
|
const style = `<style>
|
|
279
310
|
:host {
|
|
280
311
|
display: inline-flex;
|
|
281
|
-
--size: ${size}px;
|
|
282
312
|
}
|
|
283
313
|
|
|
284
314
|
svg {
|
|
285
|
-
width: var(--size);
|
|
286
|
-
height: var(--size);
|
|
315
|
+
width: var(--charcoal-icon-size);
|
|
316
|
+
height: var(--charcoal-icon-size);
|
|
287
317
|
}
|
|
288
318
|
</style>`;
|
|
289
319
|
const svg = this.svgContent !== void 0 ? this.svgContent : `<svg viewBox="0 0 ${size} ${size}"></svg>`;
|
|
@@ -320,4 +350,5 @@ if (!__SERVER__) {
|
|
|
320
350
|
exports.KNOWN_ICON_FILES = KNOWN_ICON_FILES;
|
|
321
351
|
exports.PixivIcon = PixivIcon;
|
|
322
352
|
exports.PixivIconLoadError = PixivIconLoadError;
|
|
353
|
+
exports.calcActualSize = calcActualSize;
|
|
323
354
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["charcoalIconFiles","charcoalIconFiles"],"sources":["../src/charcoalIconFiles.ts","../src/loaders/PixivIconLoadError.ts","../src/loaders/CharcoalIconFilesLoader.ts","../src/loaders/CustomRawFileLoader.ts","../src/loaders/CustomIconLoader.ts","../src/loaders/index.ts","../src/ssr.ts","../src/PixivIcon.ts","../src/index.ts"],"sourcesContent":["import charcoalIconFiles from '@charcoal-ui/icon-files'\nimport type charcoalIconFilesV2 from '@charcoal-ui/icon-files/v2'\n\nexport default charcoalIconFiles\nexport type KnownIconFile = keyof typeof charcoalIconFiles\nexport type KnownIconFileV2 = keyof typeof charcoalIconFilesV2\nexport const KNOWN_ICON_FILES = Object.keys(\n charcoalIconFiles,\n) as KnownIconFile[]\n\nexport function isKnownIconFile(name: string): name is KnownIconFile {\n return name in charcoalIconFiles\n}\n","export class PixivIconLoadError extends Error {\n constructor(name: string, cause: unknown) {\n const message = formatMessage(name, cause)\n\n super(message, { cause })\n this.name = 'PixivIconLoadError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nfunction formatMessage(name: string, cause: unknown) {\n const message = `Failed to fetch <pixiv-icon name=\"${name}\">`\n if (cause == null) {\n return message\n }\n\n if (cause instanceof Error) {\n return `${message}: ${cause.toString()})`\n }\n\n return `${message}: ${JSON.stringify(cause)})`\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\nimport charcoalIconFiles, { KnownIconFile } from '../charcoalIconFiles'\n\n/**\n * `@charcoal-ui/icon-files` に収録されているアイコンを取ってくる\n */\nexport class CharcoalIconFilesLoader implements Loadable {\n protected _name: KnownIconFile\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: KnownIconFile) {\n this._name = name\n }\n\n get importIconFile(): () => Promise<string> {\n return charcoalIconFiles[this._name]\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = this.importIconFile()\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { KnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\n\nexport class CustomRawFileLoader extends CharcoalIconFilesLoader {\n /**\n * icons-filesと同じ型のアイコンをしまっとくところ\n */\n static filePackages: Map<string, () => Promise<string>> = new Map()\n\n get importIconFile(): () => Promise<string> {\n const icon = CustomRawFileLoader.filePackages.get(this._name)\n if (icon !== undefined) return icon\n\n throw new Error('Custom icon file was not found')\n }\n}\n\nexport function addRawFile(\n name: string,\n importFn: () => Promise<string>,\n): void {\n CustomRawFileLoader.filePackages.set(name, importFn)\n}\n\n/**\n * 登録されているfile packagesにiconがあればtrue\n */\nexport function isKnownRawIconFile(name: string): name is KnownIconFile {\n return CustomRawFileLoader.filePackages.has(name)\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\n\n/**\n * `PixivIcon.extend()` で登録されたカスタムのアイコンを取得する\n */\nexport class CustomIconLoader implements Loadable {\n private _name: string\n private _filePathOrUrl: string\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: string, filePathOrUrl: string) {\n this._name = name\n this._filePathOrUrl = filePathOrUrl\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = fetch(this._filePathOrUrl)\n .then((response) => {\n if (!response.ok) {\n throw new PixivIconLoadError(this._name, 'Response is not ok')\n }\n\n return response.text()\n })\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { isKnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\nimport { CustomRawFileLoader, isKnownRawIconFile } from './CustomRawFileLoader'\nimport { CustomIconLoader } from './CustomIconLoader'\nimport { Loadable } from './Loadable'\nimport { PixivIconLoadError } from './PixivIconLoadError'\n\n/**\n * icon をロードするオブジェクトのプール。Loader のインスタンスは作り次第ここに入れる\n *\n * 同じアイコンへの複数回のリクエストが起きないためには、Loader がこの中でユニークでないと行けない\n */\nconst loaders = new Map<string, Loadable>()\n\nexport function addCustomIcon(name: string, filePathOrUrl: string): void {\n loaders.set(name, new CustomIconLoader(name, filePathOrUrl))\n}\n\nexport async function getIcon(name: string): Promise<string> {\n const loader = resolveIconLoader(name)\n if (loader == null) {\n throw new PixivIconLoadError(name, 'Loader was not found')\n }\n\n try {\n const svg = await loader.fetch()\n if (typeof svg !== 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `${name}: Expected load result to be a string, but received an unexpected type.`,\n )\n }\n\n return svg\n } catch (e) {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(name, e)\n }\n}\n\nfunction resolveIconLoader(name: string) {\n // 登録済み or キャッシュ済みの場合\n // addCustomIcon で登録された CustomIconLoader は常にこっちを通る\n const registeredLoader = loaders.get(name)\n if (registeredLoader) {\n return registeredLoader\n }\n\n // addRawFile で登録されたもの\n if (isKnownRawIconFile(name)) {\n const customFilePackageLoader = new CustomRawFileLoader(name)\n loaders.set(name, customFilePackageLoader)\n return customFilePackageLoader\n }\n\n if (isKnownIconFile(name)) {\n // `@charcoal-ui/icon-files` に収録されているアイコンにはこれを返す\n const charcoalIconFilesLoader = new CharcoalIconFilesLoader(name)\n loaders.set(name, charcoalIconFilesLoader)\n return charcoalIconFilesLoader\n }\n\n // 存在しないアイコンにはこれを返す\n return null\n}\n","export const __SERVER__: boolean = typeof window === 'undefined'\n\nconst CAN_USE_DOM = typeof HTMLElement !== 'undefined'\n\n// Workaround: `extends HTMLElement` の形式でないとbabelのトランスパイルがおかしくなる\nif (__SERVER__ || !CAN_USE_DOM) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n globalThis.HTMLElement = class {} as any\n}\n","import type React from 'react'\nimport { KnownIconFile } from './charcoalIconFiles'\nimport { getIcon, addCustomIcon } from './loaders'\nimport { addRawFile } from './loaders/CustomRawFileLoader'\nimport { __SERVER__ } from './ssr'\n\nconst attributes = ['name', 'scale', 'unsafe-non-guideline-scale'] as const\n\nconst ROOT_MARGIN = 50\n\nexport interface KnownIconType extends Record<KnownIconFile, unknown> {}\n\nexport interface Props\n extends Omit<\n React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>,\n 'className' | 'css'\n > {\n name: keyof KnownIconType\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n 'unsafe-non-guideline-scale'?: number | string\n\n // CustomElements は className が使えない。class と書く必要がある\n // https://ja.reactjs.org/docs/web-components.html#using-web-components-in-react\n class?: string\n}\n\ntype ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>\ntype Extended = [ExtendedIconFile] extends [never] // NOTE: ExtendedIconFileがneverならKnownIconTypeは拡張されていない\n ? false\n : true\n\nexport class PixivIcon extends HTMLElement {\n static readonly tagName = 'pixiv-icon'\n\n /**\n * NOTE: icon content should be sanitized before pass to extend()\n *\n * XSSに注意すること。\n * 登録したファイルの中身が直接domに反映されるため、XSSに繋がる可能性があります。\n * 信用していないソースからアイコンを追加する場合dom-purifyなどを経由してください。\n */\n static extend(\n map: Extended extends true\n ? Record<ExtendedIconFile, string | (() => Promise<string>)>\n : Record<string, string | (() => Promise<string>)>,\n ): void {\n if (__SERVER__) {\n return\n }\n\n Object.entries(map).forEach(([name, filePathOrUrlOrImportFn]) => {\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n if (typeof filePathOrUrlOrImportFn === 'string') {\n addCustomIcon(name, filePathOrUrlOrImportFn)\n }\n\n if (typeof filePathOrUrlOrImportFn === 'function') {\n addRawFile(name, filePathOrUrlOrImportFn)\n }\n })\n }\n\n static get observedAttributes(): typeof attributes {\n return attributes\n }\n\n private svgContent?: string\n private observer?: IntersectionObserver\n private isVisible = false\n\n get props(): {\n name: string\n scale: string | null\n 'unsafe-non-guideline-scale': string | null\n } {\n const partial = Object.fromEntries(\n attributes.map((attribute) => [attribute, this.getAttribute(attribute)]),\n ) as Record<(typeof attributes)[number], string | null>\n\n const name = partial.name\n\n if (name === null) {\n throw new TypeError('property \"name\" is required.')\n }\n\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n return {\n ...partial,\n name,\n }\n }\n\n get forceResizedSize(): number | null {\n if (this.props['unsafe-non-guideline-scale'] === null) {\n return null\n }\n\n const [size] = this.props.name.split('/')\n const scale = Number(this.props['unsafe-non-guideline-scale'])\n\n switch (size) {\n case 'Inline': {\n return 16 * scale\n }\n\n default: {\n return Number(size) * scale\n }\n }\n }\n\n get scaledSize(): number {\n const [size] = this.props.name.split('/')\n\n const scale = Number(this.props.scale ?? '1')\n\n switch (size) {\n case 'Inline': {\n switch (scale) {\n case 2: {\n return 32\n }\n\n default: {\n return 16\n }\n }\n }\n\n case '24': {\n return Number(size) * scale\n }\n\n default: {\n return Number(size)\n }\n }\n }\n\n constructor() {\n super()\n this.attachShadow({ mode: 'open' })\n }\n\n async connectedCallback(): Promise<void> {\n this.render()\n await this.waitUntilVisible()\n this.isVisible = true\n await this.loadSvg(this.props.name)\n }\n\n disconnectedCallback(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.isVisible = false\n }\n\n attributeChangedCallback(\n attr: string,\n _oldValue: string | null,\n newValue: string,\n ): void {\n // 非表示の場合はロードしない\n if (!this.isVisible) {\n return\n }\n\n // name が変更された場合必ず再読み込みを試みる\n if (attr === 'name') {\n void this.loadSvg(newValue)\n return\n }\n\n // SVG が読み込み済み && scale などの変更だけならそこだけ反映すればいい\n if (this.svgContent !== undefined) {\n this.render()\n return\n }\n\n // まだ SVG が読み込めてないなら load\n void this.loadSvg(this.props.name)\n }\n\n render(): void {\n const size = this.forceResizedSize ?? this.scaledSize\n\n if (!Number.isFinite(size)) {\n throw new TypeError(`icon size must not be NaN`)\n }\n\n const style = `<style>\n :host {\n display: inline-flex;\n --size: ${size}px;\n }\n\n svg {\n width: var(--size);\n height: var(--size);\n }\n</style>`\n\n const svg =\n this.svgContent !== undefined\n ? this.svgContent\n : `<svg viewBox=\"0 0 ${size} ${size}\"></svg>`\n\n // NOTE: User should sanitize the svg content before passing to charcoal.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.shadowRoot!.innerHTML = style + svg\n }\n\n private async loadSvg(name: string) {\n this.svgContent = await getIcon(name)\n this.render()\n }\n\n private waitUntilVisible() {\n return new Promise<void>((resolve) => {\n this.observer = new IntersectionObserver(\n (entries) => {\n // In Chromium based browsers, multiple entries can be returned even only observe once.\n // Here, we don't care about the entry time but only if isIntersecting happened.\n const isIntersecting = entries.some((entry) => entry.isIntersecting)\n if (isIntersecting) {\n this.observer?.disconnect()\n this.observer = undefined\n resolve()\n }\n },\n { rootMargin: `${ROOT_MARGIN}px` },\n )\n\n this.observer.observe(this)\n })\n }\n}\n","import { PixivIcon } from './PixivIcon'\nimport { __SERVER__ } from './ssr'\nexport { PixivIcon, type KnownIconType, type Props } from './PixivIcon'\nexport { KNOWN_ICON_FILES } from './charcoalIconFiles'\nexport { PixivIconLoadError } from './loaders/PixivIconLoadError'\n\ndeclare global {\n interface Window {\n PixivIcon: typeof PixivIcon\n }\n}\n\ndeclare module 'react' {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n export namespace JSX {\n interface IntrinsicElements {\n 'pixiv-icon': import('./PixivIcon').Props\n }\n }\n}\n\nif (!__SERVER__) {\n // TODO: HMR対応\n if (!window.customElements.get(PixivIcon.tagName)) {\n window.PixivIcon = PixivIcon\n window.customElements.define(PixivIcon.tagName, PixivIcon)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["charcoalIconFiles","charcoalIconFiles"],"sources":["../src/charcoalIconFiles.ts","../src/loaders/PixivIconLoadError.ts","../src/loaders/CharcoalIconFilesLoader.ts","../src/loaders/CustomRawFileLoader.ts","../src/loaders/CustomIconLoader.ts","../src/loaders/index.ts","../src/ssr.ts","../src/calcActualSize.ts","../src/PixivIcon.ts","../src/index.ts"],"sourcesContent":["import charcoalIconFiles from '@charcoal-ui/icon-files'\nimport type charcoalIconFilesV2 from '@charcoal-ui/icon-files/v2'\n\nexport default charcoalIconFiles\nexport type KnownIconFile = keyof typeof charcoalIconFiles\nexport type KnownIconFileV2 = keyof typeof charcoalIconFilesV2\nexport const KNOWN_ICON_FILES = Object.keys(\n charcoalIconFiles,\n) as KnownIconFile[]\n\nexport function isKnownIconFile(name: string): name is KnownIconFile {\n return name in charcoalIconFiles\n}\n","export class PixivIconLoadError extends Error {\n constructor(name: string, cause: unknown) {\n const message = formatMessage(name, cause)\n\n super(message, { cause })\n this.name = 'PixivIconLoadError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nfunction formatMessage(name: string, cause: unknown) {\n const message = `Failed to fetch <pixiv-icon name=\"${name}\">`\n if (cause == null) {\n return message\n }\n\n if (cause instanceof Error) {\n return `${message}: ${cause.toString()})`\n }\n\n return `${message}: ${JSON.stringify(cause)})`\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\nimport charcoalIconFiles, { KnownIconFile } from '../charcoalIconFiles'\n\n/**\n * `@charcoal-ui/icon-files` に収録されているアイコンを取ってくる\n */\nexport class CharcoalIconFilesLoader implements Loadable {\n protected _name: KnownIconFile\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: KnownIconFile) {\n this._name = name\n }\n\n get importIconFile(): () => Promise<string> {\n return charcoalIconFiles[this._name]\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = this.importIconFile()\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { KnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\n\nexport class CustomRawFileLoader extends CharcoalIconFilesLoader {\n /**\n * icons-filesと同じ型のアイコンをしまっとくところ\n */\n static filePackages: Map<string, () => Promise<string>> = new Map()\n\n get importIconFile(): () => Promise<string> {\n const icon = CustomRawFileLoader.filePackages.get(this._name)\n if (icon !== undefined) return icon\n\n throw new Error('Custom icon file was not found')\n }\n}\n\nexport function addRawFile(\n name: string,\n importFn: () => Promise<string>,\n): void {\n CustomRawFileLoader.filePackages.set(name, importFn)\n}\n\n/**\n * 登録されているfile packagesにiconがあればtrue\n */\nexport function isKnownRawIconFile(name: string): name is KnownIconFile {\n return CustomRawFileLoader.filePackages.has(name)\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\n\n/**\n * `PixivIcon.extend()` で登録されたカスタムのアイコンを取得する\n */\nexport class CustomIconLoader implements Loadable {\n private _name: string\n private _filePathOrUrl: string\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: string, filePathOrUrl: string) {\n this._name = name\n this._filePathOrUrl = filePathOrUrl\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = fetch(this._filePathOrUrl)\n .then((response) => {\n if (!response.ok) {\n throw new PixivIconLoadError(this._name, 'Response is not ok')\n }\n\n return response.text()\n })\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { isKnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\nimport { CustomRawFileLoader, isKnownRawIconFile } from './CustomRawFileLoader'\nimport { CustomIconLoader } from './CustomIconLoader'\nimport { Loadable } from './Loadable'\nimport { PixivIconLoadError } from './PixivIconLoadError'\n\n/**\n * icon をロードするオブジェクトのプール。Loader のインスタンスは作り次第ここに入れる\n *\n * 同じアイコンへの複数回のリクエストが起きないためには、Loader がこの中でユニークでないと行けない\n */\nconst loaders = new Map<string, Loadable>()\n\nexport function addCustomIcon(name: string, filePathOrUrl: string): void {\n loaders.set(name, new CustomIconLoader(name, filePathOrUrl))\n}\n\nexport async function getIcon(name: string): Promise<string> {\n const loader = resolveIconLoader(name)\n if (loader == null) {\n throw new PixivIconLoadError(name, 'Loader was not found')\n }\n\n try {\n const svg = await loader.fetch()\n if (typeof svg !== 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `${name}: Expected load result to be a string, but received an unexpected type.`,\n )\n }\n\n return svg\n } catch (e) {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(name, e)\n }\n}\n\nfunction resolveIconLoader(name: string) {\n // 登録済み or キャッシュ済みの場合\n // addCustomIcon で登録された CustomIconLoader は常にこっちを通る\n const registeredLoader = loaders.get(name)\n if (registeredLoader) {\n return registeredLoader\n }\n\n // addRawFile で登録されたもの\n if (isKnownRawIconFile(name)) {\n const customFilePackageLoader = new CustomRawFileLoader(name)\n loaders.set(name, customFilePackageLoader)\n return customFilePackageLoader\n }\n\n if (isKnownIconFile(name)) {\n // `@charcoal-ui/icon-files` に収録されているアイコンにはこれを返す\n const charcoalIconFilesLoader = new CharcoalIconFilesLoader(name)\n loaders.set(name, charcoalIconFilesLoader)\n return charcoalIconFilesLoader\n }\n\n // 存在しないアイコンにはこれを返す\n return null\n}\n","export const __SERVER__: boolean = typeof window === 'undefined'\n\nconst CAN_USE_DOM = typeof HTMLElement !== 'undefined'\n\n// Workaround: `extends HTMLElement` の形式でないとbabelのトランスパイルがおかしくなる\nif (__SERVER__ || !CAN_USE_DOM) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n globalThis.HTMLElement = class {} as any\n}\n","export type IconSizing =\n | {\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale?: never\n fixedSize?: never\n }\n | {\n scale?: never\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale: number\n fixedSize?: never\n }\n | {\n scale?: never\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale?: never\n fixedSize: number\n }\n\nconst isPositiveFinite = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value) && value > 0\n\nconst parseIconName = (name: string): { size: string; baseSize: number } => {\n if (!name.includes('/')) {\n throw new TypeError(\n `\"${name}\" is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n const [size] = name.split('/')\n\n if (size === 'Inline') {\n return { size, baseSize: 16 }\n }\n\n const baseSize = parseInt(size, 10)\n if (Number.isNaN(baseSize) || baseSize <= 0) {\n throw new TypeError(\n `\"${name}\" has invalid size prefix \"${size}\". Must be \"Inline\" or a positive number.`,\n )\n }\n\n return { size, baseSize }\n}\n\nfunction inlineSize(scale: number): number {\n switch (scale) {\n case 2:\n return 32\n default:\n return 16\n }\n}\n\nfunction guidelineSize24(scale: number): number {\n return 24 * scale\n}\n\n// fixedSize > unsafeNonGuidelineScale > scale の優先順位で生のサイズを算出する。\n// 戻り値の最終 validation は呼び出し元 (calcActualSize) で行う。\nconst resolveSize = ({\n name,\n scale,\n unsafeNonGuidelineScale,\n fixedSize,\n}: { name: string } & IconSizing): number => {\n // fixedSize (px 直接指定) が最優先\n if (isPositiveFinite(fixedSize)) {\n return fixedSize\n }\n if (fixedSize !== undefined) {\n throw new TypeError(\n `fixedSize must be a positive finite number, got ${fixedSize}`,\n )\n }\n\n const { size, baseSize } = parseIconName(name)\n\n // unsafeNonGuidelineScale (deprecated) が次に優先\n if (isPositiveFinite(unsafeNonGuidelineScale)) {\n return baseSize * unsafeNonGuidelineScale\n }\n if (unsafeNonGuidelineScale !== undefined) {\n throw new TypeError(\n `unsafeNonGuidelineScale must be a positive finite number, got ${unsafeNonGuidelineScale}`,\n )\n }\n\n // ガイドライン scale\n const numericScale = parseInt(`${scale ?? '1'}`, 10)\n switch (size) {\n case 'Inline':\n return inlineSize(numericScale)\n case '24':\n return guidelineSize24(numericScale)\n default:\n return baseSize\n }\n}\n\nexport const calcActualSize = (\n params: { name: string } & IconSizing,\n): number => {\n const actualSize = resolveSize(params)\n\n // 全 return パスの結果が正の有限数であることを Single Source of Truth として保証する\n if (!isPositiveFinite(actualSize)) {\n throw new TypeError(\n `icon size must be a positive finite number, got ${actualSize}`,\n )\n }\n\n return actualSize\n}\n","import type React from 'react'\nimport { KnownIconFile } from './charcoalIconFiles'\nimport { getIcon, addCustomIcon } from './loaders'\nimport { addRawFile } from './loaders/CustomRawFileLoader'\nimport { __SERVER__ } from './ssr'\nimport { calcActualSize } from './calcActualSize'\n\nconst attributes = [\n 'name',\n 'scale',\n 'unsafe-non-guideline-scale',\n 'fixed-size',\n] as const\n\nconst ROOT_MARGIN = 50\n\nexport interface KnownIconType extends Record<KnownIconFile, unknown> {}\n\nexport interface Props\n extends Omit<\n React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>,\n 'className' | 'css'\n > {\n name: keyof KnownIconType\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n /**\n * @deprecated `fixed-size` を利用してください。\n * `attr()` の数値解釈サポートが限定的なため、リセット CSS だけではレイアウトシフトが防げません。\n */\n 'unsafe-non-guideline-scale'?: number | string\n /**\n * 固定 px サイズで描画します。ガイドライン外のサイズを利用する場合に推奨される指定方法で、\n * 他のサイズ指定 (`scale` / `unsafe-non-guideline-scale`) よりも常に優先されます。\n *\n * Web Component の upgrade 前 (= SSR 直後の CSS-only 状態) でも CLS を防ぐには、\n * 同じ値を `style=\"--charcoal-icon-size: Npx\"` としてインラインに指定してください。\n * React の `<Icon fixedSize>` 経由で利用する場合はインラインスタイルが自動的に付与されます。\n */\n 'fixed-size'?: number | string\n\n // CustomElements は className が使えない。class と書く必要がある\n // https://ja.reactjs.org/docs/web-components.html#using-web-components-in-react\n class?: string\n}\n\ntype ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>\ntype Extended = [ExtendedIconFile] extends [never] // NOTE: ExtendedIconFileがneverならKnownIconTypeは拡張されていない\n ? false\n : true\n\nexport class PixivIcon extends HTMLElement {\n static readonly tagName = 'pixiv-icon'\n\n /**\n * NOTE: icon content should be sanitized before pass to extend()\n *\n * XSSに注意すること。\n * 登録したファイルの中身が直接domに反映されるため、XSSに繋がる可能性があります。\n * 信用していないソースからアイコンを追加する場合dom-purifyなどを経由してください。\n */\n static extend(\n map: Extended extends true\n ? Record<ExtendedIconFile, string | (() => Promise<string>)>\n : Record<string, string | (() => Promise<string>)>,\n ): void {\n if (__SERVER__) {\n return\n }\n\n Object.entries(map).forEach(([name, filePathOrUrlOrImportFn]) => {\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n if (typeof filePathOrUrlOrImportFn === 'string') {\n addCustomIcon(name, filePathOrUrlOrImportFn)\n }\n\n if (typeof filePathOrUrlOrImportFn === 'function') {\n addRawFile(name, filePathOrUrlOrImportFn)\n }\n })\n }\n\n static get observedAttributes(): typeof attributes {\n return attributes\n }\n\n private svgContent?: string\n private observer?: IntersectionObserver\n private isVisible = false\n\n get props(): {\n name: string\n scale: string | null\n 'unsafe-non-guideline-scale': string | null\n 'fixed-size': string | null\n } {\n const partial = Object.fromEntries(\n attributes.map((attribute) => [attribute, this.getAttribute(attribute)]),\n ) as Record<(typeof attributes)[number], string | null>\n\n const name = partial.name\n\n if (name === null) {\n throw new TypeError('property \"name\" is required.')\n }\n\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n return {\n ...partial,\n name,\n }\n }\n\n constructor() {\n super()\n this.attachShadow({ mode: 'open' })\n }\n\n async connectedCallback(): Promise<void> {\n this.render()\n await this.waitUntilVisible()\n this.isVisible = true\n await this.loadSvg(this.props.name)\n }\n\n disconnectedCallback(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.isVisible = false\n }\n\n attributeChangedCallback(\n attr: string,\n _oldValue: string | null,\n newValue: string,\n ): void {\n // 非表示の場合はロードしない\n if (!this.isVisible) {\n return\n }\n\n // name が変更された場合必ず再読み込みを試みる\n if (attr === 'name') {\n void this.loadSvg(newValue)\n return\n }\n\n // SVG が読み込み済み && scale などの変更だけならそこだけ反映すればいい\n if (this.svgContent !== undefined) {\n this.render()\n return\n }\n\n // まだ SVG が読み込めてないなら load\n void this.loadSvg(this.props.name)\n }\n\n render(): void {\n const { name, scale, ...rest } = this.props\n const unsafeNonGuidelineScale = rest['unsafe-non-guideline-scale']\n const fixedSize = rest['fixed-size']\n\n const size = calcActualSize({\n name,\n ...(fixedSize !== null\n ? { fixedSize: parseFloat(fixedSize) }\n : unsafeNonGuidelineScale !== null\n ? { unsafeNonGuidelineScale: parseFloat(unsafeNonGuidelineScale) }\n : { scale: scale ?? undefined }),\n } as Parameters<typeof calcActualSize>[0])\n\n // icon.css の pixiv-icon:not(:defined) ルールと同じ CSS variable に\n // 計算結果を流し込むことで、hydrate 前後で width / height が揺れないようにする\n this.style.setProperty('--charcoal-icon-size', `${size}px`)\n\n const style = `<style>\n :host {\n display: inline-flex;\n }\n\n svg {\n width: var(--charcoal-icon-size);\n height: var(--charcoal-icon-size);\n }\n</style>`\n\n const svg =\n this.svgContent !== undefined\n ? this.svgContent\n : `<svg viewBox=\"0 0 ${size} ${size}\"></svg>`\n\n // NOTE: User should sanitize the svg content before passing to charcoal.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.shadowRoot!.innerHTML = style + svg\n }\n\n private async loadSvg(name: string) {\n this.svgContent = await getIcon(name)\n this.render()\n }\n\n private waitUntilVisible() {\n return new Promise<void>((resolve) => {\n this.observer = new IntersectionObserver(\n (entries) => {\n // In Chromium based browsers, multiple entries can be returned even only observe once.\n // Here, we don't care about the entry time but only if isIntersecting happened.\n const isIntersecting = entries.some((entry) => entry.isIntersecting)\n if (isIntersecting) {\n this.observer?.disconnect()\n this.observer = undefined\n resolve()\n }\n },\n { rootMargin: `${ROOT_MARGIN}px` },\n )\n\n this.observer.observe(this)\n })\n }\n}\n","import { PixivIcon } from './PixivIcon'\nimport { __SERVER__ } from './ssr'\nexport { PixivIcon, type KnownIconType, type Props } from './PixivIcon'\nexport { calcActualSize, type IconSizing } from './calcActualSize'\nexport { KNOWN_ICON_FILES } from './charcoalIconFiles'\nexport { PixivIconLoadError } from './loaders/PixivIconLoadError'\n\ndeclare global {\n interface Window {\n PixivIcon: typeof PixivIcon\n }\n}\n\ndeclare module 'react' {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n export namespace JSX {\n interface IntrinsicElements {\n 'pixiv-icon': import('./PixivIcon').Props\n }\n }\n}\n\nif (!__SERVER__) {\n // TODO: HMR対応\n if (!window.customElements.get(PixivIcon.tagName)) {\n window.PixivIcon = PixivIcon\n window.customElements.define(PixivIcon.tagName, PixivIcon)\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -5,12 +5,25 @@ type KnownIconFile = keyof typeof charcoalIconFiles;
|
|
|
5
5
|
declare const KNOWN_ICON_FILES: KnownIconFile[];
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/PixivIcon.d.ts
|
|
8
|
-
declare const attributes: readonly ["name", "scale", "unsafe-non-guideline-scale"];
|
|
8
|
+
declare const attributes: readonly ["name", "scale", "unsafe-non-guideline-scale", "fixed-size"];
|
|
9
9
|
interface KnownIconType extends Record<KnownIconFile, unknown> {}
|
|
10
10
|
interface Props extends Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "className" | "css"> {
|
|
11
11
|
name: keyof KnownIconType;
|
|
12
12
|
scale?: 1 | 2 | 3 | "1" | "2" | "3";
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated `fixed-size` を利用してください。
|
|
15
|
+
* `attr()` の数値解釈サポートが限定的なため、リセット CSS だけではレイアウトシフトが防げません。
|
|
16
|
+
*/
|
|
13
17
|
"unsafe-non-guideline-scale"?: number | string;
|
|
18
|
+
/**
|
|
19
|
+
* 固定 px サイズで描画します。ガイドライン外のサイズを利用する場合に推奨される指定方法で、
|
|
20
|
+
* 他のサイズ指定 (`scale` / `unsafe-non-guideline-scale`) よりも常に優先されます。
|
|
21
|
+
*
|
|
22
|
+
* Web Component の upgrade 前 (= SSR 直後の CSS-only 状態) でも CLS を防ぐには、
|
|
23
|
+
* 同じ値を `style="--charcoal-icon-size: Npx"` としてインラインに指定してください。
|
|
24
|
+
* React の `<Icon fixedSize>` 経由で利用する場合はインラインスタイルが自動的に付与されます。
|
|
25
|
+
*/
|
|
26
|
+
"fixed-size"?: number | string;
|
|
14
27
|
class?: string;
|
|
15
28
|
}
|
|
16
29
|
type ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>;
|
|
@@ -33,9 +46,8 @@ declare class PixivIcon extends HTMLElement {
|
|
|
33
46
|
name: string;
|
|
34
47
|
scale: string | null;
|
|
35
48
|
"unsafe-non-guideline-scale": string | null;
|
|
49
|
+
"fixed-size": string | null;
|
|
36
50
|
};
|
|
37
|
-
get forceResizedSize(): number | null;
|
|
38
|
-
get scaledSize(): number;
|
|
39
51
|
constructor();
|
|
40
52
|
connectedCallback(): Promise<void>;
|
|
41
53
|
disconnectedCallback(): void;
|
|
@@ -45,6 +57,24 @@ declare class PixivIcon extends HTMLElement {
|
|
|
45
57
|
private waitUntilVisible;
|
|
46
58
|
}
|
|
47
59
|
//#endregion
|
|
60
|
+
//#region src/calcActualSize.d.ts
|
|
61
|
+
type IconSizing = {
|
|
62
|
+
scale?: 1 | 2 | 3 | "1" | "2" | "3"; /** @deprecated `fixedSize` を利用してください。 */
|
|
63
|
+
unsafeNonGuidelineScale?: never;
|
|
64
|
+
fixedSize?: never;
|
|
65
|
+
} | {
|
|
66
|
+
scale?: never; /** @deprecated `fixedSize` を利用してください。 */
|
|
67
|
+
unsafeNonGuidelineScale: number;
|
|
68
|
+
fixedSize?: never;
|
|
69
|
+
} | {
|
|
70
|
+
scale?: never; /** @deprecated `fixedSize` を利用してください。 */
|
|
71
|
+
unsafeNonGuidelineScale?: never;
|
|
72
|
+
fixedSize: number;
|
|
73
|
+
};
|
|
74
|
+
declare const calcActualSize: (params: {
|
|
75
|
+
name: string;
|
|
76
|
+
} & IconSizing) => number;
|
|
77
|
+
//#endregion
|
|
48
78
|
//#region src/loaders/PixivIconLoadError.d.ts
|
|
49
79
|
declare class PixivIconLoadError extends Error {
|
|
50
80
|
constructor(name: string, cause: unknown);
|
|
@@ -64,5 +94,5 @@ declare module "react" {
|
|
|
64
94
|
}
|
|
65
95
|
}
|
|
66
96
|
//#endregion
|
|
67
|
-
export { KNOWN_ICON_FILES, type KnownIconType, PixivIcon, PixivIconLoadError, type Props };
|
|
97
|
+
export { type IconSizing, KNOWN_ICON_FILES, type KnownIconType, PixivIcon, PixivIconLoadError, type Props, calcActualSize };
|
|
68
98
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/charcoalIconFiles.ts","../src/PixivIcon.ts","../src/loaders/PixivIconLoadError.ts","../src/index.ts"],"mappings":";;;KAIY,aAAA,gBAA6B,iBAAA;AAAA,cAE5B,gBAAA,EAER,aAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/charcoalIconFiles.ts","../src/PixivIcon.ts","../src/calcActualSize.ts","../src/loaders/PixivIconLoadError.ts","../src/index.ts"],"mappings":";;;KAIY,aAAA,gBAA6B,iBAAA;AAAA,cAE5B,gBAAA,EAER,aAAA;;;cCDC,UAAA;AAAA,UASW,aAAA,SAAsB,MAAA,CAAO,aAAA;AAAA,UAE7B,KAAA,SACP,IAAA,CACN,KAAA,CAAM,iBAAA,CAAkB,KAAA,CAAM,cAAA,CAAe,WAAA,GAAc,WAAA;EAG7D,IAAA,QAAY,aAAA;EACZ,KAAA;;;;ADlBF;ECuBE,4BAAA;;;;;;;AA5B4B;;EAqC5B,YAAA;EAIA,KAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,OAAA,OAAc,aAAA,EAAe,aAAA;AAAA,KAChD,QAAA,IAAY,gBAAA;AAAA,cAIJ,SAAA,SAAkB,WAAA;EAAA,gBACb,OAAA;EAnC4B;AAE9C;;;;;;EAF8C,OA4CrC,MAAA,CACL,GAAA,EAAK,QAAA,gBACD,MAAA,CAAO,gBAAA,kBAAkC,OAAA,aACzC,MAAA,yBAA+B,OAAA;EAAA,WAuB1B,kBAAA,CAAA,UAA6B,UAAA;EAAA,QAIhC,UAAA;EAAA,QACA,QAAA;EAAA,QACA,SAAA;EAAA,IAEJ,KAAA,CAAA;IACF,IAAA;IACA,KAAA;IACA,4BAAA;IACA,YAAA;EAAA;EAwBF,WAAA,CAAA;EAKA,iBAAA,CAAA,GAA2B,OAAA;EAO3B,oBAAA,CAAA;EAMA,wBAAA,CACE,IAAA,UACA,SAAA,iBACA,QAAA;EAuBF,MAAA,CAAA;EAAA,QAuCc,OAAA;EAAA,QAKN,gBAAA;AAAA;;;KClNE,UAAA;EAEN,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;EAGA,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;EAGA,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;AAAA,cAoFO,cAAA,GACX,MAAA;EAAU,IAAA;AAAA,IAAiB,UAAA;;;cCtGhB,kBAAA,SAA2B,KAAA;EACtC,WAAA,CAAY,IAAA,UAAc,KAAA;AAAA;;;;YCOhB,MAAA;IACR,SAAA,SAAkB,SAAA;EAAA;AAAA;AAAA;EAAA,UAMH,GAAA;IAAA,UACL,iBAAA;MACR,YAAA,EARgB,KAAA;IAAA;EAAA;AAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,12 +5,25 @@ type KnownIconFile = keyof typeof charcoalIconFiles$1;
|
|
|
5
5
|
declare const KNOWN_ICON_FILES: KnownIconFile[];
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/PixivIcon.d.ts
|
|
8
|
-
declare const attributes: readonly ["name", "scale", "unsafe-non-guideline-scale"];
|
|
8
|
+
declare const attributes: readonly ["name", "scale", "unsafe-non-guideline-scale", "fixed-size"];
|
|
9
9
|
interface KnownIconType extends Record<KnownIconFile, unknown> {}
|
|
10
10
|
interface Props extends Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "className" | "css"> {
|
|
11
11
|
name: keyof KnownIconType;
|
|
12
12
|
scale?: 1 | 2 | 3 | "1" | "2" | "3";
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated `fixed-size` を利用してください。
|
|
15
|
+
* `attr()` の数値解釈サポートが限定的なため、リセット CSS だけではレイアウトシフトが防げません。
|
|
16
|
+
*/
|
|
13
17
|
"unsafe-non-guideline-scale"?: number | string;
|
|
18
|
+
/**
|
|
19
|
+
* 固定 px サイズで描画します。ガイドライン外のサイズを利用する場合に推奨される指定方法で、
|
|
20
|
+
* 他のサイズ指定 (`scale` / `unsafe-non-guideline-scale`) よりも常に優先されます。
|
|
21
|
+
*
|
|
22
|
+
* Web Component の upgrade 前 (= SSR 直後の CSS-only 状態) でも CLS を防ぐには、
|
|
23
|
+
* 同じ値を `style="--charcoal-icon-size: Npx"` としてインラインに指定してください。
|
|
24
|
+
* React の `<Icon fixedSize>` 経由で利用する場合はインラインスタイルが自動的に付与されます。
|
|
25
|
+
*/
|
|
26
|
+
"fixed-size"?: number | string;
|
|
14
27
|
class?: string;
|
|
15
28
|
}
|
|
16
29
|
type ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>;
|
|
@@ -33,9 +46,8 @@ declare class PixivIcon extends HTMLElement {
|
|
|
33
46
|
name: string;
|
|
34
47
|
scale: string | null;
|
|
35
48
|
"unsafe-non-guideline-scale": string | null;
|
|
49
|
+
"fixed-size": string | null;
|
|
36
50
|
};
|
|
37
|
-
get forceResizedSize(): number | null;
|
|
38
|
-
get scaledSize(): number;
|
|
39
51
|
constructor();
|
|
40
52
|
connectedCallback(): Promise<void>;
|
|
41
53
|
disconnectedCallback(): void;
|
|
@@ -45,6 +57,24 @@ declare class PixivIcon extends HTMLElement {
|
|
|
45
57
|
private waitUntilVisible;
|
|
46
58
|
}
|
|
47
59
|
//#endregion
|
|
60
|
+
//#region src/calcActualSize.d.ts
|
|
61
|
+
type IconSizing = {
|
|
62
|
+
scale?: 1 | 2 | 3 | "1" | "2" | "3"; /** @deprecated `fixedSize` を利用してください。 */
|
|
63
|
+
unsafeNonGuidelineScale?: never;
|
|
64
|
+
fixedSize?: never;
|
|
65
|
+
} | {
|
|
66
|
+
scale?: never; /** @deprecated `fixedSize` を利用してください。 */
|
|
67
|
+
unsafeNonGuidelineScale: number;
|
|
68
|
+
fixedSize?: never;
|
|
69
|
+
} | {
|
|
70
|
+
scale?: never; /** @deprecated `fixedSize` を利用してください。 */
|
|
71
|
+
unsafeNonGuidelineScale?: never;
|
|
72
|
+
fixedSize: number;
|
|
73
|
+
};
|
|
74
|
+
declare const calcActualSize: (params: {
|
|
75
|
+
name: string;
|
|
76
|
+
} & IconSizing) => number;
|
|
77
|
+
//#endregion
|
|
48
78
|
//#region src/loaders/PixivIconLoadError.d.ts
|
|
49
79
|
declare class PixivIconLoadError extends Error {
|
|
50
80
|
constructor(name: string, cause: unknown);
|
|
@@ -64,5 +94,5 @@ declare module "react" {
|
|
|
64
94
|
}
|
|
65
95
|
}
|
|
66
96
|
//#endregion
|
|
67
|
-
export { KNOWN_ICON_FILES, type KnownIconType, PixivIcon, PixivIconLoadError, type Props };
|
|
97
|
+
export { type IconSizing, KNOWN_ICON_FILES, type KnownIconType, PixivIcon, PixivIconLoadError, type Props, calcActualSize };
|
|
68
98
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/charcoalIconFiles.ts","../src/PixivIcon.ts","../src/loaders/PixivIconLoadError.ts","../src/index.ts"],"mappings":";;;KAIY,aAAA,gBAA6B,mBAAA;AAAA,cAE5B,gBAAA,EAER,aAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/charcoalIconFiles.ts","../src/PixivIcon.ts","../src/calcActualSize.ts","../src/loaders/PixivIconLoadError.ts","../src/index.ts"],"mappings":";;;KAIY,aAAA,gBAA6B,mBAAA;AAAA,cAE5B,gBAAA,EAER,aAAA;;;cCDC,UAAA;AAAA,UASW,aAAA,SAAsB,MAAA,CAAO,aAAA;AAAA,UAE7B,KAAA,SACP,IAAA,CACN,KAAA,CAAM,iBAAA,CAAkB,KAAA,CAAM,cAAA,CAAe,WAAA,GAAc,WAAA;EAG7D,IAAA,QAAY,aAAA;EACZ,KAAA;;;;ADlBF;ECuBE,4BAAA;;;;;;;AA5B4B;;EAqC5B,YAAA;EAIA,KAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,OAAA,OAAc,aAAA,EAAe,aAAA;AAAA,KAChD,QAAA,IAAY,gBAAA;AAAA,cAIJ,SAAA,SAAkB,WAAA;EAAA,gBACb,OAAA;EAnC4B;AAE9C;;;;;;EAF8C,OA4CrC,MAAA,CACL,GAAA,EAAK,QAAA,gBACD,MAAA,CAAO,gBAAA,kBAAkC,OAAA,aACzC,MAAA,yBAA+B,OAAA;EAAA,WAuB1B,kBAAA,CAAA,UAA6B,UAAA;EAAA,QAIhC,UAAA;EAAA,QACA,QAAA;EAAA,QACA,SAAA;EAAA,IAEJ,KAAA,CAAA;IACF,IAAA;IACA,KAAA;IACA,4BAAA;IACA,YAAA;EAAA;EAwBF,WAAA,CAAA;EAKA,iBAAA,CAAA,GAA2B,OAAA;EAO3B,oBAAA,CAAA;EAMA,wBAAA,CACE,IAAA,UACA,SAAA,iBACA,QAAA;EAuBF,MAAA,CAAA;EAAA,QAuCc,OAAA;EAAA,QAKN,gBAAA;AAAA;;;KClNE,UAAA;EAEN,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;EAGA,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;EAGA,KAAA;EAEA,uBAAA;EACA,SAAA;AAAA;AAAA,cAoFO,cAAA,GACX,MAAA;EAAU,IAAA;AAAA,IAAiB,UAAA;;;cCtGhB,kBAAA,SAA2B,KAAA;EACtC,WAAA,CAAY,IAAA,UAAc,KAAA;AAAA;;;;YCOhB,MAAA;IACR,SAAA,SAAkB,SAAA;EAAA;AAAA;AAAA;EAAA,UAMH,GAAA;IAAA,UACL,iBAAA;MACR,YAAA,EARgB,KAAA;IAAA;EAAA;AAAA"}
|
package/dist/index.js
CHANGED
|
@@ -154,12 +154,58 @@ function resolveIconLoader(name) {
|
|
|
154
154
|
const __SERVER__ = typeof window === "undefined";
|
|
155
155
|
if (__SERVER__ || !(typeof HTMLElement !== "undefined")) globalThis.HTMLElement = class {};
|
|
156
156
|
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/calcActualSize.ts
|
|
159
|
+
const isPositiveFinite = (value) => typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
160
|
+
const parseIconName = (name) => {
|
|
161
|
+
if (!name.includes("/")) throw new TypeError(`"${name}" is not a valid icon name. "name" must be named like [size]/[Name].`);
|
|
162
|
+
const [size] = name.split("/");
|
|
163
|
+
if (size === "Inline") return {
|
|
164
|
+
size,
|
|
165
|
+
baseSize: 16
|
|
166
|
+
};
|
|
167
|
+
const baseSize = parseInt(size, 10);
|
|
168
|
+
if (Number.isNaN(baseSize) || baseSize <= 0) throw new TypeError(`"${name}" has invalid size prefix "${size}". Must be "Inline" or a positive number.`);
|
|
169
|
+
return {
|
|
170
|
+
size,
|
|
171
|
+
baseSize
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
function inlineSize(scale) {
|
|
175
|
+
switch (scale) {
|
|
176
|
+
case 2: return 32;
|
|
177
|
+
default: return 16;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function guidelineSize24(scale) {
|
|
181
|
+
return 24 * scale;
|
|
182
|
+
}
|
|
183
|
+
const resolveSize = ({ name, scale, unsafeNonGuidelineScale, fixedSize }) => {
|
|
184
|
+
if (isPositiveFinite(fixedSize)) return fixedSize;
|
|
185
|
+
if (fixedSize !== void 0) throw new TypeError(`fixedSize must be a positive finite number, got ${fixedSize}`);
|
|
186
|
+
const { size, baseSize } = parseIconName(name);
|
|
187
|
+
if (isPositiveFinite(unsafeNonGuidelineScale)) return baseSize * unsafeNonGuidelineScale;
|
|
188
|
+
if (unsafeNonGuidelineScale !== void 0) throw new TypeError(`unsafeNonGuidelineScale must be a positive finite number, got ${unsafeNonGuidelineScale}`);
|
|
189
|
+
const numericScale = parseInt(`${scale ?? "1"}`, 10);
|
|
190
|
+
switch (size) {
|
|
191
|
+
case "Inline": return inlineSize(numericScale);
|
|
192
|
+
case "24": return guidelineSize24(numericScale);
|
|
193
|
+
default: return baseSize;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const calcActualSize = (params) => {
|
|
197
|
+
const actualSize = resolveSize(params);
|
|
198
|
+
if (!isPositiveFinite(actualSize)) throw new TypeError(`icon size must be a positive finite number, got ${actualSize}`);
|
|
199
|
+
return actualSize;
|
|
200
|
+
};
|
|
201
|
+
|
|
157
202
|
//#endregion
|
|
158
203
|
//#region src/PixivIcon.ts
|
|
159
204
|
const attributes = [
|
|
160
205
|
"name",
|
|
161
206
|
"scale",
|
|
162
|
-
"unsafe-non-guideline-scale"
|
|
207
|
+
"unsafe-non-guideline-scale",
|
|
208
|
+
"fixed-size"
|
|
163
209
|
];
|
|
164
210
|
const ROOT_MARGIN = 50;
|
|
165
211
|
var PixivIcon = class extends HTMLElement {
|
|
@@ -195,27 +241,6 @@ var PixivIcon = class extends HTMLElement {
|
|
|
195
241
|
name
|
|
196
242
|
};
|
|
197
243
|
}
|
|
198
|
-
get forceResizedSize() {
|
|
199
|
-
if (this.props["unsafe-non-guideline-scale"] === null) return null;
|
|
200
|
-
const [size] = this.props.name.split("/");
|
|
201
|
-
const scale = Number(this.props["unsafe-non-guideline-scale"]);
|
|
202
|
-
switch (size) {
|
|
203
|
-
case "Inline": return 16 * scale;
|
|
204
|
-
default: return Number(size) * scale;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
get scaledSize() {
|
|
208
|
-
const [size] = this.props.name.split("/");
|
|
209
|
-
const scale = Number(this.props.scale ?? "1");
|
|
210
|
-
switch (size) {
|
|
211
|
-
case "Inline": switch (scale) {
|
|
212
|
-
case 2: return 32;
|
|
213
|
-
default: return 16;
|
|
214
|
-
}
|
|
215
|
-
case "24": return Number(size) * scale;
|
|
216
|
-
default: return Number(size);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
244
|
constructor() {
|
|
220
245
|
super();
|
|
221
246
|
this.attachShadow({ mode: "open" });
|
|
@@ -244,17 +269,22 @@ var PixivIcon = class extends HTMLElement {
|
|
|
244
269
|
this.loadSvg(this.props.name);
|
|
245
270
|
}
|
|
246
271
|
render() {
|
|
247
|
-
const
|
|
248
|
-
|
|
272
|
+
const { name, scale, ...rest } = this.props;
|
|
273
|
+
const unsafeNonGuidelineScale = rest["unsafe-non-guideline-scale"];
|
|
274
|
+
const fixedSize = rest["fixed-size"];
|
|
275
|
+
const size = calcActualSize({
|
|
276
|
+
name,
|
|
277
|
+
...fixedSize !== null ? { fixedSize: parseFloat(fixedSize) } : unsafeNonGuidelineScale !== null ? { unsafeNonGuidelineScale: parseFloat(unsafeNonGuidelineScale) } : { scale: scale ?? void 0 }
|
|
278
|
+
});
|
|
279
|
+
this.style.setProperty("--charcoal-icon-size", `${size}px`);
|
|
249
280
|
const style = `<style>
|
|
250
281
|
:host {
|
|
251
282
|
display: inline-flex;
|
|
252
|
-
--size: ${size}px;
|
|
253
283
|
}
|
|
254
284
|
|
|
255
285
|
svg {
|
|
256
|
-
width: var(--size);
|
|
257
|
-
height: var(--size);
|
|
286
|
+
width: var(--charcoal-icon-size);
|
|
287
|
+
height: var(--charcoal-icon-size);
|
|
258
288
|
}
|
|
259
289
|
</style>`;
|
|
260
290
|
const svg = this.svgContent !== void 0 ? this.svgContent : `<svg viewBox="0 0 ${size} ${size}"></svg>`;
|
|
@@ -288,5 +318,5 @@ if (!__SERVER__) {
|
|
|
288
318
|
}
|
|
289
319
|
|
|
290
320
|
//#endregion
|
|
291
|
-
export { KNOWN_ICON_FILES, PixivIcon, PixivIconLoadError };
|
|
321
|
+
export { KNOWN_ICON_FILES, PixivIcon, PixivIconLoadError, calcActualSize };
|
|
292
322
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["charcoalIconFiles"],"sources":["../src/charcoalIconFiles.ts","../src/loaders/PixivIconLoadError.ts","../src/loaders/CharcoalIconFilesLoader.ts","../src/loaders/CustomRawFileLoader.ts","../src/loaders/CustomIconLoader.ts","../src/loaders/index.ts","../src/ssr.ts","../src/PixivIcon.ts","../src/index.ts"],"sourcesContent":["import charcoalIconFiles from '@charcoal-ui/icon-files'\nimport type charcoalIconFilesV2 from '@charcoal-ui/icon-files/v2'\n\nexport default charcoalIconFiles\nexport type KnownIconFile = keyof typeof charcoalIconFiles\nexport type KnownIconFileV2 = keyof typeof charcoalIconFilesV2\nexport const KNOWN_ICON_FILES = Object.keys(\n charcoalIconFiles,\n) as KnownIconFile[]\n\nexport function isKnownIconFile(name: string): name is KnownIconFile {\n return name in charcoalIconFiles\n}\n","export class PixivIconLoadError extends Error {\n constructor(name: string, cause: unknown) {\n const message = formatMessage(name, cause)\n\n super(message, { cause })\n this.name = 'PixivIconLoadError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nfunction formatMessage(name: string, cause: unknown) {\n const message = `Failed to fetch <pixiv-icon name=\"${name}\">`\n if (cause == null) {\n return message\n }\n\n if (cause instanceof Error) {\n return `${message}: ${cause.toString()})`\n }\n\n return `${message}: ${JSON.stringify(cause)})`\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\nimport charcoalIconFiles, { KnownIconFile } from '../charcoalIconFiles'\n\n/**\n * `@charcoal-ui/icon-files` に収録されているアイコンを取ってくる\n */\nexport class CharcoalIconFilesLoader implements Loadable {\n protected _name: KnownIconFile\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: KnownIconFile) {\n this._name = name\n }\n\n get importIconFile(): () => Promise<string> {\n return charcoalIconFiles[this._name]\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = this.importIconFile()\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { KnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\n\nexport class CustomRawFileLoader extends CharcoalIconFilesLoader {\n /**\n * icons-filesと同じ型のアイコンをしまっとくところ\n */\n static filePackages: Map<string, () => Promise<string>> = new Map()\n\n get importIconFile(): () => Promise<string> {\n const icon = CustomRawFileLoader.filePackages.get(this._name)\n if (icon !== undefined) return icon\n\n throw new Error('Custom icon file was not found')\n }\n}\n\nexport function addRawFile(\n name: string,\n importFn: () => Promise<string>,\n): void {\n CustomRawFileLoader.filePackages.set(name, importFn)\n}\n\n/**\n * 登録されているfile packagesにiconがあればtrue\n */\nexport function isKnownRawIconFile(name: string): name is KnownIconFile {\n return CustomRawFileLoader.filePackages.has(name)\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\n\n/**\n * `PixivIcon.extend()` で登録されたカスタムのアイコンを取得する\n */\nexport class CustomIconLoader implements Loadable {\n private _name: string\n private _filePathOrUrl: string\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: string, filePathOrUrl: string) {\n this._name = name\n this._filePathOrUrl = filePathOrUrl\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = fetch(this._filePathOrUrl)\n .then((response) => {\n if (!response.ok) {\n throw new PixivIconLoadError(this._name, 'Response is not ok')\n }\n\n return response.text()\n })\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { isKnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\nimport { CustomRawFileLoader, isKnownRawIconFile } from './CustomRawFileLoader'\nimport { CustomIconLoader } from './CustomIconLoader'\nimport { Loadable } from './Loadable'\nimport { PixivIconLoadError } from './PixivIconLoadError'\n\n/**\n * icon をロードするオブジェクトのプール。Loader のインスタンスは作り次第ここに入れる\n *\n * 同じアイコンへの複数回のリクエストが起きないためには、Loader がこの中でユニークでないと行けない\n */\nconst loaders = new Map<string, Loadable>()\n\nexport function addCustomIcon(name: string, filePathOrUrl: string): void {\n loaders.set(name, new CustomIconLoader(name, filePathOrUrl))\n}\n\nexport async function getIcon(name: string): Promise<string> {\n const loader = resolveIconLoader(name)\n if (loader == null) {\n throw new PixivIconLoadError(name, 'Loader was not found')\n }\n\n try {\n const svg = await loader.fetch()\n if (typeof svg !== 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `${name}: Expected load result to be a string, but received an unexpected type.`,\n )\n }\n\n return svg\n } catch (e) {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(name, e)\n }\n}\n\nfunction resolveIconLoader(name: string) {\n // 登録済み or キャッシュ済みの場合\n // addCustomIcon で登録された CustomIconLoader は常にこっちを通る\n const registeredLoader = loaders.get(name)\n if (registeredLoader) {\n return registeredLoader\n }\n\n // addRawFile で登録されたもの\n if (isKnownRawIconFile(name)) {\n const customFilePackageLoader = new CustomRawFileLoader(name)\n loaders.set(name, customFilePackageLoader)\n return customFilePackageLoader\n }\n\n if (isKnownIconFile(name)) {\n // `@charcoal-ui/icon-files` に収録されているアイコンにはこれを返す\n const charcoalIconFilesLoader = new CharcoalIconFilesLoader(name)\n loaders.set(name, charcoalIconFilesLoader)\n return charcoalIconFilesLoader\n }\n\n // 存在しないアイコンにはこれを返す\n return null\n}\n","export const __SERVER__: boolean = typeof window === 'undefined'\n\nconst CAN_USE_DOM = typeof HTMLElement !== 'undefined'\n\n// Workaround: `extends HTMLElement` の形式でないとbabelのトランスパイルがおかしくなる\nif (__SERVER__ || !CAN_USE_DOM) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n globalThis.HTMLElement = class {} as any\n}\n","import type React from 'react'\nimport { KnownIconFile } from './charcoalIconFiles'\nimport { getIcon, addCustomIcon } from './loaders'\nimport { addRawFile } from './loaders/CustomRawFileLoader'\nimport { __SERVER__ } from './ssr'\n\nconst attributes = ['name', 'scale', 'unsafe-non-guideline-scale'] as const\n\nconst ROOT_MARGIN = 50\n\nexport interface KnownIconType extends Record<KnownIconFile, unknown> {}\n\nexport interface Props\n extends Omit<\n React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>,\n 'className' | 'css'\n > {\n name: keyof KnownIconType\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n 'unsafe-non-guideline-scale'?: number | string\n\n // CustomElements は className が使えない。class と書く必要がある\n // https://ja.reactjs.org/docs/web-components.html#using-web-components-in-react\n class?: string\n}\n\ntype ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>\ntype Extended = [ExtendedIconFile] extends [never] // NOTE: ExtendedIconFileがneverならKnownIconTypeは拡張されていない\n ? false\n : true\n\nexport class PixivIcon extends HTMLElement {\n static readonly tagName = 'pixiv-icon'\n\n /**\n * NOTE: icon content should be sanitized before pass to extend()\n *\n * XSSに注意すること。\n * 登録したファイルの中身が直接domに反映されるため、XSSに繋がる可能性があります。\n * 信用していないソースからアイコンを追加する場合dom-purifyなどを経由してください。\n */\n static extend(\n map: Extended extends true\n ? Record<ExtendedIconFile, string | (() => Promise<string>)>\n : Record<string, string | (() => Promise<string>)>,\n ): void {\n if (__SERVER__) {\n return\n }\n\n Object.entries(map).forEach(([name, filePathOrUrlOrImportFn]) => {\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n if (typeof filePathOrUrlOrImportFn === 'string') {\n addCustomIcon(name, filePathOrUrlOrImportFn)\n }\n\n if (typeof filePathOrUrlOrImportFn === 'function') {\n addRawFile(name, filePathOrUrlOrImportFn)\n }\n })\n }\n\n static get observedAttributes(): typeof attributes {\n return attributes\n }\n\n private svgContent?: string\n private observer?: IntersectionObserver\n private isVisible = false\n\n get props(): {\n name: string\n scale: string | null\n 'unsafe-non-guideline-scale': string | null\n } {\n const partial = Object.fromEntries(\n attributes.map((attribute) => [attribute, this.getAttribute(attribute)]),\n ) as Record<(typeof attributes)[number], string | null>\n\n const name = partial.name\n\n if (name === null) {\n throw new TypeError('property \"name\" is required.')\n }\n\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n return {\n ...partial,\n name,\n }\n }\n\n get forceResizedSize(): number | null {\n if (this.props['unsafe-non-guideline-scale'] === null) {\n return null\n }\n\n const [size] = this.props.name.split('/')\n const scale = Number(this.props['unsafe-non-guideline-scale'])\n\n switch (size) {\n case 'Inline': {\n return 16 * scale\n }\n\n default: {\n return Number(size) * scale\n }\n }\n }\n\n get scaledSize(): number {\n const [size] = this.props.name.split('/')\n\n const scale = Number(this.props.scale ?? '1')\n\n switch (size) {\n case 'Inline': {\n switch (scale) {\n case 2: {\n return 32\n }\n\n default: {\n return 16\n }\n }\n }\n\n case '24': {\n return Number(size) * scale\n }\n\n default: {\n return Number(size)\n }\n }\n }\n\n constructor() {\n super()\n this.attachShadow({ mode: 'open' })\n }\n\n async connectedCallback(): Promise<void> {\n this.render()\n await this.waitUntilVisible()\n this.isVisible = true\n await this.loadSvg(this.props.name)\n }\n\n disconnectedCallback(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.isVisible = false\n }\n\n attributeChangedCallback(\n attr: string,\n _oldValue: string | null,\n newValue: string,\n ): void {\n // 非表示の場合はロードしない\n if (!this.isVisible) {\n return\n }\n\n // name が変更された場合必ず再読み込みを試みる\n if (attr === 'name') {\n void this.loadSvg(newValue)\n return\n }\n\n // SVG が読み込み済み && scale などの変更だけならそこだけ反映すればいい\n if (this.svgContent !== undefined) {\n this.render()\n return\n }\n\n // まだ SVG が読み込めてないなら load\n void this.loadSvg(this.props.name)\n }\n\n render(): void {\n const size = this.forceResizedSize ?? this.scaledSize\n\n if (!Number.isFinite(size)) {\n throw new TypeError(`icon size must not be NaN`)\n }\n\n const style = `<style>\n :host {\n display: inline-flex;\n --size: ${size}px;\n }\n\n svg {\n width: var(--size);\n height: var(--size);\n }\n</style>`\n\n const svg =\n this.svgContent !== undefined\n ? this.svgContent\n : `<svg viewBox=\"0 0 ${size} ${size}\"></svg>`\n\n // NOTE: User should sanitize the svg content before passing to charcoal.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.shadowRoot!.innerHTML = style + svg\n }\n\n private async loadSvg(name: string) {\n this.svgContent = await getIcon(name)\n this.render()\n }\n\n private waitUntilVisible() {\n return new Promise<void>((resolve) => {\n this.observer = new IntersectionObserver(\n (entries) => {\n // In Chromium based browsers, multiple entries can be returned even only observe once.\n // Here, we don't care about the entry time but only if isIntersecting happened.\n const isIntersecting = entries.some((entry) => entry.isIntersecting)\n if (isIntersecting) {\n this.observer?.disconnect()\n this.observer = undefined\n resolve()\n }\n },\n { rootMargin: `${ROOT_MARGIN}px` },\n )\n\n this.observer.observe(this)\n })\n }\n}\n","import { PixivIcon } from './PixivIcon'\nimport { __SERVER__ } from './ssr'\nexport { PixivIcon, type KnownIconType, type Props } from './PixivIcon'\nexport { KNOWN_ICON_FILES } from './charcoalIconFiles'\nexport { PixivIconLoadError } from './loaders/PixivIconLoadError'\n\ndeclare global {\n interface Window {\n PixivIcon: typeof PixivIcon\n }\n}\n\ndeclare module 'react' {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n export namespace JSX {\n interface IntrinsicElements {\n 'pixiv-icon': import('./PixivIcon').Props\n }\n }\n}\n\nif (!__SERVER__) {\n // TODO: HMR対応\n if (!window.customElements.get(PixivIcon.tagName)) {\n window.PixivIcon = PixivIcon\n window.customElements.define(PixivIcon.tagName, PixivIcon)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["charcoalIconFiles"],"sources":["../src/charcoalIconFiles.ts","../src/loaders/PixivIconLoadError.ts","../src/loaders/CharcoalIconFilesLoader.ts","../src/loaders/CustomRawFileLoader.ts","../src/loaders/CustomIconLoader.ts","../src/loaders/index.ts","../src/ssr.ts","../src/calcActualSize.ts","../src/PixivIcon.ts","../src/index.ts"],"sourcesContent":["import charcoalIconFiles from '@charcoal-ui/icon-files'\nimport type charcoalIconFilesV2 from '@charcoal-ui/icon-files/v2'\n\nexport default charcoalIconFiles\nexport type KnownIconFile = keyof typeof charcoalIconFiles\nexport type KnownIconFileV2 = keyof typeof charcoalIconFilesV2\nexport const KNOWN_ICON_FILES = Object.keys(\n charcoalIconFiles,\n) as KnownIconFile[]\n\nexport function isKnownIconFile(name: string): name is KnownIconFile {\n return name in charcoalIconFiles\n}\n","export class PixivIconLoadError extends Error {\n constructor(name: string, cause: unknown) {\n const message = formatMessage(name, cause)\n\n super(message, { cause })\n this.name = 'PixivIconLoadError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nfunction formatMessage(name: string, cause: unknown) {\n const message = `Failed to fetch <pixiv-icon name=\"${name}\">`\n if (cause == null) {\n return message\n }\n\n if (cause instanceof Error) {\n return `${message}: ${cause.toString()})`\n }\n\n return `${message}: ${JSON.stringify(cause)})`\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\nimport charcoalIconFiles, { KnownIconFile } from '../charcoalIconFiles'\n\n/**\n * `@charcoal-ui/icon-files` に収録されているアイコンを取ってくる\n */\nexport class CharcoalIconFilesLoader implements Loadable {\n protected _name: KnownIconFile\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: KnownIconFile) {\n this._name = name\n }\n\n get importIconFile(): () => Promise<string> {\n return charcoalIconFiles[this._name]\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = this.importIconFile()\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { KnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\n\nexport class CustomRawFileLoader extends CharcoalIconFilesLoader {\n /**\n * icons-filesと同じ型のアイコンをしまっとくところ\n */\n static filePackages: Map<string, () => Promise<string>> = new Map()\n\n get importIconFile(): () => Promise<string> {\n const icon = CustomRawFileLoader.filePackages.get(this._name)\n if (icon !== undefined) return icon\n\n throw new Error('Custom icon file was not found')\n }\n}\n\nexport function addRawFile(\n name: string,\n importFn: () => Promise<string>,\n): void {\n CustomRawFileLoader.filePackages.set(name, importFn)\n}\n\n/**\n * 登録されているfile packagesにiconがあればtrue\n */\nexport function isKnownRawIconFile(name: string): name is KnownIconFile {\n return CustomRawFileLoader.filePackages.has(name)\n}\n","import { PixivIconLoadError } from './PixivIconLoadError'\nimport { Loadable } from './Loadable'\n\n/**\n * `PixivIcon.extend()` で登録されたカスタムのアイコンを取得する\n */\nexport class CustomIconLoader implements Loadable {\n private _name: string\n private _filePathOrUrl: string\n private _resultSvg: string | undefined = undefined\n private _promise: Promise<string> | undefined = undefined\n\n constructor(name: string, filePathOrUrl: string) {\n this._name = name\n this._filePathOrUrl = filePathOrUrl\n }\n\n async fetch(): Promise<string> {\n if (this._resultSvg !== undefined) {\n return this._resultSvg\n }\n\n if (this._promise) {\n return this._promise\n }\n\n this._promise = fetch(this._filePathOrUrl)\n .then((response) => {\n if (!response.ok) {\n throw new PixivIconLoadError(this._name, 'Response is not ok')\n }\n\n return response.text()\n })\n .then((svg) => {\n this._resultSvg = svg\n return this._resultSvg\n })\n .catch((e) => {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(this._name, e)\n })\n .finally(() => {\n this._promise = undefined\n })\n\n return this._promise\n }\n}\n","import { isKnownIconFile } from '../charcoalIconFiles'\nimport { CharcoalIconFilesLoader } from './CharcoalIconFilesLoader'\nimport { CustomRawFileLoader, isKnownRawIconFile } from './CustomRawFileLoader'\nimport { CustomIconLoader } from './CustomIconLoader'\nimport { Loadable } from './Loadable'\nimport { PixivIconLoadError } from './PixivIconLoadError'\n\n/**\n * icon をロードするオブジェクトのプール。Loader のインスタンスは作り次第ここに入れる\n *\n * 同じアイコンへの複数回のリクエストが起きないためには、Loader がこの中でユニークでないと行けない\n */\nconst loaders = new Map<string, Loadable>()\n\nexport function addCustomIcon(name: string, filePathOrUrl: string): void {\n loaders.set(name, new CustomIconLoader(name, filePathOrUrl))\n}\n\nexport async function getIcon(name: string): Promise<string> {\n const loader = resolveIconLoader(name)\n if (loader == null) {\n throw new PixivIconLoadError(name, 'Loader was not found')\n }\n\n try {\n const svg = await loader.fetch()\n if (typeof svg !== 'string') {\n // eslint-disable-next-line no-console\n console.warn(\n `${name}: Expected load result to be a string, but received an unexpected type.`,\n )\n }\n\n return svg\n } catch (e) {\n if (e instanceof PixivIconLoadError) {\n throw e\n }\n throw new PixivIconLoadError(name, e)\n }\n}\n\nfunction resolveIconLoader(name: string) {\n // 登録済み or キャッシュ済みの場合\n // addCustomIcon で登録された CustomIconLoader は常にこっちを通る\n const registeredLoader = loaders.get(name)\n if (registeredLoader) {\n return registeredLoader\n }\n\n // addRawFile で登録されたもの\n if (isKnownRawIconFile(name)) {\n const customFilePackageLoader = new CustomRawFileLoader(name)\n loaders.set(name, customFilePackageLoader)\n return customFilePackageLoader\n }\n\n if (isKnownIconFile(name)) {\n // `@charcoal-ui/icon-files` に収録されているアイコンにはこれを返す\n const charcoalIconFilesLoader = new CharcoalIconFilesLoader(name)\n loaders.set(name, charcoalIconFilesLoader)\n return charcoalIconFilesLoader\n }\n\n // 存在しないアイコンにはこれを返す\n return null\n}\n","export const __SERVER__: boolean = typeof window === 'undefined'\n\nconst CAN_USE_DOM = typeof HTMLElement !== 'undefined'\n\n// Workaround: `extends HTMLElement` の形式でないとbabelのトランスパイルがおかしくなる\nif (__SERVER__ || !CAN_USE_DOM) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n globalThis.HTMLElement = class {} as any\n}\n","export type IconSizing =\n | {\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale?: never\n fixedSize?: never\n }\n | {\n scale?: never\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale: number\n fixedSize?: never\n }\n | {\n scale?: never\n /** @deprecated `fixedSize` を利用してください。 */\n unsafeNonGuidelineScale?: never\n fixedSize: number\n }\n\nconst isPositiveFinite = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value) && value > 0\n\nconst parseIconName = (name: string): { size: string; baseSize: number } => {\n if (!name.includes('/')) {\n throw new TypeError(\n `\"${name}\" is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n const [size] = name.split('/')\n\n if (size === 'Inline') {\n return { size, baseSize: 16 }\n }\n\n const baseSize = parseInt(size, 10)\n if (Number.isNaN(baseSize) || baseSize <= 0) {\n throw new TypeError(\n `\"${name}\" has invalid size prefix \"${size}\". Must be \"Inline\" or a positive number.`,\n )\n }\n\n return { size, baseSize }\n}\n\nfunction inlineSize(scale: number): number {\n switch (scale) {\n case 2:\n return 32\n default:\n return 16\n }\n}\n\nfunction guidelineSize24(scale: number): number {\n return 24 * scale\n}\n\n// fixedSize > unsafeNonGuidelineScale > scale の優先順位で生のサイズを算出する。\n// 戻り値の最終 validation は呼び出し元 (calcActualSize) で行う。\nconst resolveSize = ({\n name,\n scale,\n unsafeNonGuidelineScale,\n fixedSize,\n}: { name: string } & IconSizing): number => {\n // fixedSize (px 直接指定) が最優先\n if (isPositiveFinite(fixedSize)) {\n return fixedSize\n }\n if (fixedSize !== undefined) {\n throw new TypeError(\n `fixedSize must be a positive finite number, got ${fixedSize}`,\n )\n }\n\n const { size, baseSize } = parseIconName(name)\n\n // unsafeNonGuidelineScale (deprecated) が次に優先\n if (isPositiveFinite(unsafeNonGuidelineScale)) {\n return baseSize * unsafeNonGuidelineScale\n }\n if (unsafeNonGuidelineScale !== undefined) {\n throw new TypeError(\n `unsafeNonGuidelineScale must be a positive finite number, got ${unsafeNonGuidelineScale}`,\n )\n }\n\n // ガイドライン scale\n const numericScale = parseInt(`${scale ?? '1'}`, 10)\n switch (size) {\n case 'Inline':\n return inlineSize(numericScale)\n case '24':\n return guidelineSize24(numericScale)\n default:\n return baseSize\n }\n}\n\nexport const calcActualSize = (\n params: { name: string } & IconSizing,\n): number => {\n const actualSize = resolveSize(params)\n\n // 全 return パスの結果が正の有限数であることを Single Source of Truth として保証する\n if (!isPositiveFinite(actualSize)) {\n throw new TypeError(\n `icon size must be a positive finite number, got ${actualSize}`,\n )\n }\n\n return actualSize\n}\n","import type React from 'react'\nimport { KnownIconFile } from './charcoalIconFiles'\nimport { getIcon, addCustomIcon } from './loaders'\nimport { addRawFile } from './loaders/CustomRawFileLoader'\nimport { __SERVER__ } from './ssr'\nimport { calcActualSize } from './calcActualSize'\n\nconst attributes = [\n 'name',\n 'scale',\n 'unsafe-non-guideline-scale',\n 'fixed-size',\n] as const\n\nconst ROOT_MARGIN = 50\n\nexport interface KnownIconType extends Record<KnownIconFile, unknown> {}\n\nexport interface Props\n extends Omit<\n React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>,\n 'className' | 'css'\n > {\n name: keyof KnownIconType\n scale?: 1 | 2 | 3 | '1' | '2' | '3'\n /**\n * @deprecated `fixed-size` を利用してください。\n * `attr()` の数値解釈サポートが限定的なため、リセット CSS だけではレイアウトシフトが防げません。\n */\n 'unsafe-non-guideline-scale'?: number | string\n /**\n * 固定 px サイズで描画します。ガイドライン外のサイズを利用する場合に推奨される指定方法で、\n * 他のサイズ指定 (`scale` / `unsafe-non-guideline-scale`) よりも常に優先されます。\n *\n * Web Component の upgrade 前 (= SSR 直後の CSS-only 状態) でも CLS を防ぐには、\n * 同じ値を `style=\"--charcoal-icon-size: Npx\"` としてインラインに指定してください。\n * React の `<Icon fixedSize>` 経由で利用する場合はインラインスタイルが自動的に付与されます。\n */\n 'fixed-size'?: number | string\n\n // CustomElements は className が使えない。class と書く必要がある\n // https://ja.reactjs.org/docs/web-components.html#using-web-components-in-react\n class?: string\n}\n\ntype ExtendedIconFile = Exclude<keyof KnownIconType, KnownIconFile>\ntype Extended = [ExtendedIconFile] extends [never] // NOTE: ExtendedIconFileがneverならKnownIconTypeは拡張されていない\n ? false\n : true\n\nexport class PixivIcon extends HTMLElement {\n static readonly tagName = 'pixiv-icon'\n\n /**\n * NOTE: icon content should be sanitized before pass to extend()\n *\n * XSSに注意すること。\n * 登録したファイルの中身が直接domに反映されるため、XSSに繋がる可能性があります。\n * 信用していないソースからアイコンを追加する場合dom-purifyなどを経由してください。\n */\n static extend(\n map: Extended extends true\n ? Record<ExtendedIconFile, string | (() => Promise<string>)>\n : Record<string, string | (() => Promise<string>)>,\n ): void {\n if (__SERVER__) {\n return\n }\n\n Object.entries(map).forEach(([name, filePathOrUrlOrImportFn]) => {\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n if (typeof filePathOrUrlOrImportFn === 'string') {\n addCustomIcon(name, filePathOrUrlOrImportFn)\n }\n\n if (typeof filePathOrUrlOrImportFn === 'function') {\n addRawFile(name, filePathOrUrlOrImportFn)\n }\n })\n }\n\n static get observedAttributes(): typeof attributes {\n return attributes\n }\n\n private svgContent?: string\n private observer?: IntersectionObserver\n private isVisible = false\n\n get props(): {\n name: string\n scale: string | null\n 'unsafe-non-guideline-scale': string | null\n 'fixed-size': string | null\n } {\n const partial = Object.fromEntries(\n attributes.map((attribute) => [attribute, this.getAttribute(attribute)]),\n ) as Record<(typeof attributes)[number], string | null>\n\n const name = partial.name\n\n if (name === null) {\n throw new TypeError('property \"name\" is required.')\n }\n\n if (!name.includes('/')) {\n throw new TypeError(\n `${name} is not a valid icon name. \"name\" must be named like [size]/[Name].`,\n )\n }\n\n return {\n ...partial,\n name,\n }\n }\n\n constructor() {\n super()\n this.attachShadow({ mode: 'open' })\n }\n\n async connectedCallback(): Promise<void> {\n this.render()\n await this.waitUntilVisible()\n this.isVisible = true\n await this.loadSvg(this.props.name)\n }\n\n disconnectedCallback(): void {\n this.observer?.disconnect()\n this.observer = undefined\n this.isVisible = false\n }\n\n attributeChangedCallback(\n attr: string,\n _oldValue: string | null,\n newValue: string,\n ): void {\n // 非表示の場合はロードしない\n if (!this.isVisible) {\n return\n }\n\n // name が変更された場合必ず再読み込みを試みる\n if (attr === 'name') {\n void this.loadSvg(newValue)\n return\n }\n\n // SVG が読み込み済み && scale などの変更だけならそこだけ反映すればいい\n if (this.svgContent !== undefined) {\n this.render()\n return\n }\n\n // まだ SVG が読み込めてないなら load\n void this.loadSvg(this.props.name)\n }\n\n render(): void {\n const { name, scale, ...rest } = this.props\n const unsafeNonGuidelineScale = rest['unsafe-non-guideline-scale']\n const fixedSize = rest['fixed-size']\n\n const size = calcActualSize({\n name,\n ...(fixedSize !== null\n ? { fixedSize: parseFloat(fixedSize) }\n : unsafeNonGuidelineScale !== null\n ? { unsafeNonGuidelineScale: parseFloat(unsafeNonGuidelineScale) }\n : { scale: scale ?? undefined }),\n } as Parameters<typeof calcActualSize>[0])\n\n // icon.css の pixiv-icon:not(:defined) ルールと同じ CSS variable に\n // 計算結果を流し込むことで、hydrate 前後で width / height が揺れないようにする\n this.style.setProperty('--charcoal-icon-size', `${size}px`)\n\n const style = `<style>\n :host {\n display: inline-flex;\n }\n\n svg {\n width: var(--charcoal-icon-size);\n height: var(--charcoal-icon-size);\n }\n</style>`\n\n const svg =\n this.svgContent !== undefined\n ? this.svgContent\n : `<svg viewBox=\"0 0 ${size} ${size}\"></svg>`\n\n // NOTE: User should sanitize the svg content before passing to charcoal.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.shadowRoot!.innerHTML = style + svg\n }\n\n private async loadSvg(name: string) {\n this.svgContent = await getIcon(name)\n this.render()\n }\n\n private waitUntilVisible() {\n return new Promise<void>((resolve) => {\n this.observer = new IntersectionObserver(\n (entries) => {\n // In Chromium based browsers, multiple entries can be returned even only observe once.\n // Here, we don't care about the entry time but only if isIntersecting happened.\n const isIntersecting = entries.some((entry) => entry.isIntersecting)\n if (isIntersecting) {\n this.observer?.disconnect()\n this.observer = undefined\n resolve()\n }\n },\n { rootMargin: `${ROOT_MARGIN}px` },\n )\n\n this.observer.observe(this)\n })\n }\n}\n","import { PixivIcon } from './PixivIcon'\nimport { __SERVER__ } from './ssr'\nexport { PixivIcon, type KnownIconType, type Props } from './PixivIcon'\nexport { calcActualSize, type IconSizing } from './calcActualSize'\nexport { KNOWN_ICON_FILES } from './charcoalIconFiles'\nexport { PixivIconLoadError } from './loaders/PixivIconLoadError'\n\ndeclare global {\n interface Window {\n PixivIcon: typeof PixivIcon\n }\n}\n\ndeclare module 'react' {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n export namespace JSX {\n interface IntrinsicElements {\n 'pixiv-icon': import('./PixivIcon').Props\n }\n }\n}\n\nif (!__SERVER__) {\n // TODO: HMR対応\n if (!window.customElements.get(PixivIcon.tagName)) {\n window.PixivIcon = PixivIcon\n window.customElements.define(PixivIcon.tagName, PixivIcon)\n }\n}\n"],"mappings":"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"}
|