SolidJS で Material-UI(SUID)を試してみた
最近話題になりつつある(?)SolidJS 向けの Material-UI ライブラリ SUID を少しだけ試してみました。
SUID
React 用の MUI を SolidJS 向けに port(移植)するライブラリです。
バージョン 0.4.1(2022/5/29 リリース)時点では 41 のコンポーネントが移植されています。
なお、SUID のサイト自体が SUID を使って作成・構築されています。
試したバージョン
- SolidJS : 1.4.3
- SUID : 0.4.1
- supabase-js : 1.35.3
試した内容
Supabase の Quickstart: SolidJS を TypeScript(TSX)と Material-UI で置き換えつつ、Card 表示も追加で試してみました。
また、0.3.0 で追加された Avatar
も試してきました。
サンプルコード(全体)
こちらに置いてあります。タイトルのとおり、2022/5/31 開催予定の 第 33 回 PostgreSQL アンカンファレンス@オンライン 向けに用意したサンプルです。
ここからはサンプルコードでの使用例と気になった点を挙げていきます(当然ですが今後のバージョンで変わる可能性があります)。
TextField
(テキスト入力フィールド)
使用例
- Auth.tsx(91 行目〜)
<TextField
required
id="email"
label="メールアドレス"
helperText="メールアドレスを入力してください"
value={email()}
onChange={(event, value) => {
setEmail(value);
}}
/>
required
指定の場合、未入力で Form を Submit しようとするとアラートが表示されブロックされます。ただし Submit を使わない場合は「*」印の表示のみでブロック動作などは生じません(自前で Validation を実装する必要あり)。
inputRef
に対応していない
React の MUI ではTextField
でref
の代わりにinputRef
が使えますが、SUID では対応していないようです。
今回は画面表示直後のフォーカスの指定に使いたかったのですが、諦めてdocument.getElementById()
を使ってフォーカスを移動しました。
これについては元からref
・inputRef
には対応しない方針なのかもしれません。
- setFocus.ts(3 行目〜)
const element = document.getElementById(elementId);
element?.focus();
- Auth.tsx(23 行目〜)
onMount(() => {
setFocus("email");
})
multiline
に対応していない
SUID では現状TextareaAutosize
に対応していないので代わりにTextField
で Multiline
を使おうと思ったのですが、multiline
・row
などには対応していませんでした。
仕方なく通常のtextarea
タグを使いました。
- EditItem.tsx(210 行目〜)
<textarea
id="note"
aria-label="Note"
placeholder="本文を入力してください"
onchange={(event) => {
setNote(event.currentTarget.value);
}}
>
{note()}
</textarea>
Card
(カード表示)
使用例
- ViewItem.tsx(38 行目〜)
<Card
id="itemCard"
variant="outlined"
>
<CardContent>
<Stack spacing={1} direction="row">
<CardActions sx={{ padding: 0 }}>
<IconButton onClick={() => toggleExpand()} sx={{ padding: 0 }}>
<Switch fallback={<></>}>
<Match when={!expand()}>
<ExpandMoreIcon aria-label="expand more"/>
</Match>
<Match when={expand()}>
<ExpandLessIcon aria-label="expand less"/>
</Match>
</Switch>
</IconButton>
</CardActions>
<Typography variant="h6" gutterBottom>
{props.article.title}
</Typography>
(中略)
</Stack>
<Show when={expand()} fallback={<></>}>
<Fade in={expand()} timeout={500}>
<Box>
<For each={props.article.note?.split("\n")} fallback={<></>}>
{(line) =>
<Typography variant="body1" gutterBottom>
{line}
</Typography>
}
</For>
</Box>
</Fade>
</Show>
<CardActions sx={{ padding: 0 }}>
<IconButton
aria-label="edit"
onClick={() => props.changeArticle(props.article)}
disabled={
props.article.userId !== props.session.user!.id &&
props.article.noteType !== NoteType.Writable
}
>
<EditIcon />
</IconButton>
(中略)
</CardActions>
</CardContent>
</Card>
※ 「新規投稿」の下から続くカードです。なお「新規投稿」もCard
で表示しています。
Collapse
API に対応していない
React 用 MUI にある Collapse API に対応していないため、上に記したコードでも SolidJS 自体が持つ Show API を使って類似の処理をしています(Collapse API とは違い開閉そのもののアニメーション動作はしませんが、Fade
を使って文字の表示をフェードインさせています)。
<Switch fallback={<></>}>
<Match when={!expand()}>
<ExpandMoreIcon aria-label="expand more"/>
</Match>
<Match when={expand()}>
<ExpandLessIcon aria-label="expand less"/>
</Match>
</Switch>
<Show when={expand()} fallback={<></>}>
<Fade in={expand()} timeout={500}>
<Box>
<For each={props.article.note?.split("\n")} fallback={<></>}>
{(line) =>
<Typography variant="body1" gutterBottom>
{line}
</Typography>
}
</For>
</Box>
</Fade>
</Show>
使ってみた感想
バージョン 0.1.0 → 0.2.x → 0.3.x で徐々に対応コンポーネントが増えていますが、まともなプロダクトを作るには足りないコンポーネント・API がまだ少なくない印象です。
今後のバージョンアップに期待、ですね。
参考:その他のサンプル画面
プロフィール編集画面
Avatar
)表示
おまけ:アバター(SUID 0.3.0 で Avatar
に対応したので、一覧表示とタイトルバーで使ってみました。
使用例
- ViewItem.tsx(56 行目〜)
<Avatar
alt={props.article.userName}
src={props.avatar}
sx={{
width: 28,
height: 28
}}
/>
src
で指定した画像のロードに失敗した場合は自動的にフォールバックしてデフォルトのアバターアイコン(Person)が表示されます。
Discussion