本文へ移動

Wakusei Planets惑星

太陽・惑星・衛星を、線画、陰影つきの絵、表面の地図で描きます。実際の大きさ・傾き・自転つきで、任意の日時の衛星の位置も分かります。

「惑星」(わくせい) は、太陽のまわりを回る大きな星のことです。 名前について(英語)

目次

やり方

React・Vue・Svelte・Angularで使う

フレームワークごとのコンポーネントです。ブラウザー専用のimportは、サーバー描画が通らない場所に置きます。

<wakusei-body> はカスタム要素なので、どのフレームワークでも動きます。ただ1つの決まりは、ブラウザーが要るということです。サーバー描画が動かない場所 (エフェクトやマウント後の処理) でimportしてください。下のコンポーネントは、すべてパッケージのテストがビルドして開いています。

React

import { useEffect } from "react";

export function WakuseiBody({ body = "saturn", look = "line" }: { body?: string; look?: "line" | "realistic" }) {
  useEffect(() => {
    // The element needs a browser, so it is imported here, never at the top of the file: a server render never reaches an effect.
    void import("@johnmorrisdotca/wakusei-planets/element");
    void import("@johnmorrisdotca/wakusei-planets/all");
  }, []);
  return <wakusei-body body={body} look={look} />;
}

Reactにはタグの属性を教える必要があります。型ファイルで教えます。

import type { DetailedHTMLProps, HTMLAttributes } from "react";

declare module "react" {
  namespace JSX {
    interface IntrinsicElements {
      "wakusei-body": DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> & { body?: string; look?: string; size?: number | string; time?: string; moons?: boolean };
    }
  }
}

サーバーでは文字列に描画され、ページが読み込まれると要素が中身を作ります。Next.jsも同じです。

Vue

<script setup lang="ts">
import { onMounted } from "vue";

withDefaults(defineProps<{ body?: string; look?: "line" | "realistic" }>(), { body: "saturn", look: "line" });

// The element needs a browser: import it once the component is on the page, never while a server renders it.
onMounted(() => {
  void import("@johnmorrisdotca/wakusei-planets/element");
});
</script>

<template>
  <wakusei-body :body="body" :look="look"></wakusei-body>
</template>

このタグがVueのものでないことを伝えます。

import { createApp } from "vue";
import PlanetView from "./PlanetView.vue";

const app = createApp(PlanetView);
app.config.compilerOptions.isCustomElement = (tag) => tag === "wakusei-body";
app.mount("#app");

Svelte

<script lang="ts">
  import { onMount } from "svelte";

  let { body = "saturn", look = "line" }: { body?: string; look?: "line" | "realistic" } = $props();

  // The element needs a browser: onMount never runs on the server.
  onMount(() => {
    void import("@johnmorrisdotca/wakusei-planets/element");
  });
</script>

<wakusei-body {body} {look}></wakusei-body>

Angular

import { Component, CUSTOM_ELEMENTS_SCHEMA, Input, OnInit } from "@angular/core";

@Component({
  selector: "app-wakusei-body",
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<wakusei-body [attr.body]="body" [attr.look]="look"></wakusei-body>`,
})
export class WakuseiBodyComponent implements OnInit {
  @Input() body = "saturn";
  @Input() look: "line" | "realistic" = "line";

  ngOnInit(): void {
    // The element needs a browser: ngOnInit also runs when a server renders, so the import waits for one.
    if (typeof window !== "undefined") void import("@johnmorrisdotca/wakusei-planets/element");
  }
}

Nuxt、SvelteKit、Next.js

同じコンポーネントが使えます。要素のimportだけは、マウント後の処理、エフェクト、onMount の中に置いてください。

ソースを見るGitHub で編集@johnmorrisdotca/wakusei-planets 0.24.0 のソースから作成しました。

この日本語は、まだ日本語を母語とする方の確認を受けていません。訂正を歓迎します。