TypeScript で CSS Houdini の Painting API の worklet を npm に公開する

CDS を見ていたら、CSS Houdini の紹介がされていた。
Extending CSS with Houdini - YouTube

気になったので、Painting API を使ったパッケージを 2 つ作った。
css-houdini/packages at v0.2.0 · tyankatsu0105/css-houdini · GitHub

サイトも用意した。
tyankatsu css houdini

この記事では

  • CSS Houdini について
  • TypeScript での作り方
  • 公開したあとの使い方

の 3 つを解説する。

CSS Houdini について

CSS Houdini はいくつかの API によって、JS で CSS の拡張を実現するというもの。
MDN に解説がある。CSS Houdini | MDN
各ブラウザの実装状況は CDS でも紹介されていたHoudini.howで確認が可能。

TypeScript での作り方

Painting API で使用する CSS.paintWorklet.addModule registerPaintは現状型が提供されていない。
そのため自分で型定義ファイルを書いて拡張する必要がある。

type PaintRenderingContext2D = Omit<
  CanvasRenderingContext2D,
  | keyof CanvasImageData
  | keyof CanvasUserInterface
  | keyof CanvasText
  | keyof CanvasTextDrawingStyles
>;
type PaintSize = {
  readonly height: number;
  readonly width: number;
};

type StylePropertyMap = {
  get(property: string): any;
  getAll(property: string): ReturnType<StylePropertyMap["get"]>[];
  has(property: string): boolean;
  size: number;
};

type PaintCtorInputProperties = string[];
type PaintCtorPaint = (
  ctx: PaintRenderingContext2D,
  geom: PaintSize,
  properties: StylePropertyMap
) => void;

interface PaintCtor {
  inputProperties?: PaintCtorInputProperties;
  paint?: PaintCtorPaint;
}

declare function registerPaint(name: string, paintCtor: PaintCtor): undefined;
declare namespace CSS {
  export let paintWorklet: {
    addModule: (moduleURL: string) => Promise<void>;
  };

  export let registerProperty: (propertyDefinition: {
    inherits: boolean;
    initialValue?: any;
    name: string;
    syntax?: string;
  }) => undefined;
}

型を作るためには、CSS-TAG Houdini Editor DraftsCSS Painting API Level 1を見るといい。

公開したあとの使い方

npm に公開すると、unpkg.com で対象ファイルを取得できるようになるので、

window.CSS.paintWorklet.addModule(
  "https://unpkg.com/@tyankatsu0105/css-houdini-ripple/worklet.js"
);

みたいに worklet ファイルを addModule の url 引数に指定すれば使えるようになる。

ローカルで開発中に確認したい場合は、webpack の raw-loader でファイルの中身をテキストで取得して、URL.createObjectURL で url を生成して window.CSS.paintWorklet.addModule にわたすといい。

詳しくはここに書いてある。
Houdini.how usage