From f5c94c7cab421b3ca72217b1b6adcc4efae38918 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:52:13 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=E3=82=BB=E3=83=9E=E3=83=B3?= =?UTF-8?q?=E3=83=86=E3=82=A3=E3=83=83=E3=82=AF=E3=82=AB=E3=83=A9=E3=83=BC?= =?UTF-8?q?=E5=A4=89=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit info / success / warning / danger の各状態色に base / light / dark の3トークンを定義 Co-Authored-By: Claude Fable 5 --- packages/core/src/variables.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/core/src/variables.css b/packages/core/src/variables.css index e9a600d..b9144e2 100644 --- a/packages/core/src/variables.css +++ b/packages/core/src/variables.css @@ -24,6 +24,18 @@ --color-white: #fff; --color-black: #000; --color-background: #fff; + --color-info: #1677ff; + --color-info-light: #e6f4ff; + --color-info-dark: #003eb3; + --color-success: #52c41a; + --color-success-light: #f6ffed; + --color-success-dark: #237804; + --color-warning: #faad14; + --color-warning-light: #fffbe6; + --color-warning-dark: #ad6800; + --color-danger: #ff4d4f; + --color-danger-light: #fff1f0; + --color-danger-dark: #a8071a; --size-radius: 1rem; --width-border: 2px; --font-family: sans-serif; From 71fcebfedaf802303ba79432dab0902c8e5c04ac Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:52:44 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20Alert=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit タイトルと説明文を持つ静的表示コンポーネント。info / success / warning / danger の4バリアントに対応。動的通知を想定しないため role="alert" はデフォルト付与しない Co-Authored-By: Claude Fable 5 --- .../src/components/alert/alert.stories.tsx | 56 +++++++++++++++++++ packages/core/src/components/alert/alert.tsx | 40 +++++++++++++ packages/core/src/components/alert/index.css | 43 ++++++++++++++ packages/core/src/components/alert/index.ts | 1 + packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 142 insertions(+) create mode 100644 packages/core/src/components/alert/alert.stories.tsx create mode 100644 packages/core/src/components/alert/alert.tsx create mode 100644 packages/core/src/components/alert/index.css create mode 100644 packages/core/src/components/alert/index.ts diff --git a/packages/core/src/components/alert/alert.stories.tsx b/packages/core/src/components/alert/alert.stories.tsx new file mode 100644 index 0000000..c7d9392 --- /dev/null +++ b/packages/core/src/components/alert/alert.stories.tsx @@ -0,0 +1,56 @@ +import { Alert, AlertDescription, AlertTitle } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/Alert", + component: Alert, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => ( + + お知らせ + + メンテナンスのため、明日の午前2時から4時までサービスを停止します。 + + + ), +}; + +export const Variants: Story = { + render: () => ( +
+ + 情報 + 新しいバージョンが利用可能です。 + + + 成功 + 変更が保存されました。 + + + 警告 + + ストレージの空き容量が少なくなっています。 + + + + エラー + データの読み込みに失敗しました。 + +
+ ), +}; + +export const DescriptionOnly: Story = { + render: () => ( + + プロフィールを更新しました。 + + ), +}; diff --git a/packages/core/src/components/alert/alert.tsx b/packages/core/src/components/alert/alert.tsx new file mode 100644 index 0000000..d2ba2d3 --- /dev/null +++ b/packages/core/src/components/alert/alert.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import "./index.css"; + +export type AlertProps = React.HTMLAttributes & { + variant?: "info" | "success" | "warning" | "danger"; +}; + +export const Alert: React.FC = ({ + className, + variant = "info", + ...props +}) => { + return ( +
+ ); +}; + +export type AlertTitleProps = React.HTMLAttributes; + +export const AlertTitle: React.FC = ({ + className, + ...props +}) => { + return
; +}; + +export type AlertDescriptionProps = React.HTMLAttributes; + +export const AlertDescription: React.FC = ({ + className, + ...props +}) => { + return

; +}; diff --git a/packages/core/src/components/alert/index.css b/packages/core/src/components/alert/index.css new file mode 100644 index 0000000..be82c6b --- /dev/null +++ b/packages/core/src/components/alert/index.css @@ -0,0 +1,43 @@ +.ginga-alert { + display: flex; + flex-direction: column; + gap: 0.25rem; + padding: 0.75rem 1rem; + font-family: var(--font-family); + border-left: 4px solid; + border-radius: calc(var(--size-radius) * 0.5); + + &[data-variant="info"] { + color: var(--color-info-dark); + background-color: var(--color-info-light); + border-left-color: var(--color-info); + } + + &[data-variant="success"] { + color: var(--color-success-dark); + background-color: var(--color-success-light); + border-left-color: var(--color-success); + } + + &[data-variant="warning"] { + color: var(--color-warning-dark); + background-color: var(--color-warning-light); + border-left-color: var(--color-warning); + } + + &[data-variant="danger"] { + color: var(--color-danger-dark); + background-color: var(--color-danger-light); + border-left-color: var(--color-danger); + } +} + +.ginga-alert-title { + font-size: 1rem; + font-weight: 700; +} + +.ginga-alert-description { + margin: 0; + font-size: 0.875rem; +} diff --git a/packages/core/src/components/alert/index.ts b/packages/core/src/components/alert/index.ts new file mode 100644 index 0000000..6e57847 --- /dev/null +++ b/packages/core/src/components/alert/index.ts @@ -0,0 +1 @@ +export * from "./alert"; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index b169971..8e6912d 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -1,4 +1,5 @@ @import url("./components/accordion/index.css"); +@import url("./components/alert/index.css"); @import url("./components/anchor/index.css"); @import url("./components/box/index.css"); @import url("./components/button/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 75f3fc8..be859fd 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,4 +1,5 @@ export * from "./components/accordion"; +export * from "./components/alert"; export * from "./components/anchor"; export * from "./components/box"; export * from "./components/button"; From dfcb95460ff80b39c0a407b341a3f1a24a4f7907 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:53:02 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20AlertDialog=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit role="alertdialog" を固定したダイアログ。既存の Modal / DialogTrigger と組み合わせて使用し、variant でタイトル色と上部アクセントを変更可能 Co-Authored-By: Claude Fable 5 --- .../alert-dialog/alert-dialog.stories.tsx | 66 +++++++++++++++++++ .../components/alert-dialog/alert-dialog.tsx | 53 +++++++++++++++ .../src/components/alert-dialog/index.css | 53 +++++++++++++++ .../core/src/components/alert-dialog/index.ts | 1 + packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 175 insertions(+) create mode 100644 packages/core/src/components/alert-dialog/alert-dialog.stories.tsx create mode 100644 packages/core/src/components/alert-dialog/alert-dialog.tsx create mode 100644 packages/core/src/components/alert-dialog/index.css create mode 100644 packages/core/src/components/alert-dialog/index.ts diff --git a/packages/core/src/components/alert-dialog/alert-dialog.stories.tsx b/packages/core/src/components/alert-dialog/alert-dialog.stories.tsx new file mode 100644 index 0000000..8470050 --- /dev/null +++ b/packages/core/src/components/alert-dialog/alert-dialog.stories.tsx @@ -0,0 +1,66 @@ +import { Button } from "../button"; +import { DialogTrigger, Modal } from "../dialog"; +import { AlertDialog, AlertDialogTitle } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/AlertDialog", + component: AlertDialog, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => ( + + + + + ファイルの削除 +

この操作は取り消せません。本当に削除しますか?

+
+ + +
+ + + + ), +}; + +export const Warning: Story = { + render: () => ( + + + + + ログアウトの確認 +

保存されていない変更は失われます。ログアウトしますか?

+
+ + +
+
+
+
+ ), +}; diff --git a/packages/core/src/components/alert-dialog/alert-dialog.tsx b/packages/core/src/components/alert-dialog/alert-dialog.tsx new file mode 100644 index 0000000..465d988 --- /dev/null +++ b/packages/core/src/components/alert-dialog/alert-dialog.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import { + Dialog as AriaDialog, + Heading as AriaHeading, +} from "react-aria-components"; +import "./index.css"; + +import type { OmitStrict } from "@ginga-ui/utils"; + +export type AlertDialogProps = OmitStrict< + React.ComponentProps, + "role" +> & { + variant?: "info" | "success" | "warning" | "danger"; +}; + +export const AlertDialog: React.FC = ({ + children, + className, + variant, + ...props +}) => { + return ( + + {children} + + ); +}; + +export type AlertDialogTitleProps = React.ComponentProps; + +export const AlertDialogTitle: React.FC = ({ + children, + className, + ...props +}) => { + return ( + + {children} + + ); +}; diff --git a/packages/core/src/components/alert-dialog/index.css b/packages/core/src/components/alert-dialog/index.css new file mode 100644 index 0000000..35c4a24 --- /dev/null +++ b/packages/core/src/components/alert-dialog/index.css @@ -0,0 +1,53 @@ +.ginga-alert-dialog { + position: relative; + width: 100%; + max-width: 28rem; + padding: 1.5rem; + font-family: var(--font-family); + color: var(--color-secondary-9); + background-color: var(--color-background); + border-top: 4px solid var(--color-secondary-9); + border-radius: calc(var(--size-radius) * 0.5); + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 10%), + 0 2px 4px -1px rgb(0 0 0 / 6%); + + &[data-variant="info"] { + border-top-color: var(--color-info); + + .ginga-alert-dialog-title { + color: var(--color-info-dark); + } + } + + &[data-variant="success"] { + border-top-color: var(--color-success); + + .ginga-alert-dialog-title { + color: var(--color-success-dark); + } + } + + &[data-variant="warning"] { + border-top-color: var(--color-warning); + + .ginga-alert-dialog-title { + color: var(--color-warning-dark); + } + } + + &[data-variant="danger"] { + border-top-color: var(--color-danger); + + .ginga-alert-dialog-title { + color: var(--color-danger-dark); + } + } +} + +.ginga-alert-dialog-title { + margin-bottom: 1rem; + font-family: var(--font-family); + font-size: 1.25rem; + font-weight: 800; +} diff --git a/packages/core/src/components/alert-dialog/index.ts b/packages/core/src/components/alert-dialog/index.ts new file mode 100644 index 0000000..28569ba --- /dev/null +++ b/packages/core/src/components/alert-dialog/index.ts @@ -0,0 +1 @@ +export * from "./alert-dialog"; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index 8e6912d..7ed10ca 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -1,5 +1,6 @@ @import url("./components/accordion/index.css"); @import url("./components/alert/index.css"); +@import url("./components/alert-dialog/index.css"); @import url("./components/anchor/index.css"); @import url("./components/box/index.css"); @import url("./components/button/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index be859fd..8a95c96 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,6 @@ export * from "./components/accordion"; export * from "./components/alert"; +export * from "./components/alert-dialog"; export * from "./components/anchor"; export * from "./components/box"; export * from "./components/button"; From c572b04c0fd97fb077cde0cc846c4c181fb2e86b Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:53:24 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20Badge=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ステータスやラベルを表示する span ベースのバッジ。primary / secondary と状態色4種の計6バリアント Co-Authored-By: Claude Fable 5 --- .../src/components/badge/badge.stories.tsx | 29 +++++++++++++ packages/core/src/components/badge/badge.tsx | 22 ++++++++++ packages/core/src/components/badge/index.css | 42 +++++++++++++++++++ packages/core/src/components/badge/index.ts | 1 + packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 96 insertions(+) create mode 100644 packages/core/src/components/badge/badge.stories.tsx create mode 100644 packages/core/src/components/badge/badge.tsx create mode 100644 packages/core/src/components/badge/index.css create mode 100644 packages/core/src/components/badge/index.ts diff --git a/packages/core/src/components/badge/badge.stories.tsx b/packages/core/src/components/badge/badge.stories.tsx new file mode 100644 index 0000000..026df46 --- /dev/null +++ b/packages/core/src/components/badge/badge.stories.tsx @@ -0,0 +1,29 @@ +import { Badge } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/Badge", + component: Badge, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => New, +}; + +export const Variants: Story = { + render: () => ( +
+ Primary + Secondary + Info + Success + Warning + Danger +
+ ), +}; diff --git a/packages/core/src/components/badge/badge.tsx b/packages/core/src/components/badge/badge.tsx new file mode 100644 index 0000000..b9512ed --- /dev/null +++ b/packages/core/src/components/badge/badge.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import "./index.css"; + +export type BadgeProps = React.HTMLAttributes & { + variant?: "primary" | "secondary" | "info" | "success" | "warning" | "danger"; +}; + +export const Badge: React.FC = ({ + className, + variant = "primary", + ...props +}) => { + return ( + + ); +}; diff --git a/packages/core/src/components/badge/index.css b/packages/core/src/components/badge/index.css new file mode 100644 index 0000000..acafe21 --- /dev/null +++ b/packages/core/src/components/badge/index.css @@ -0,0 +1,42 @@ +.ginga-badge { + display: inline-flex; + gap: 0.25rem; + align-items: center; + padding: 0.125rem 0.5rem; + font-family: var(--font-family); + font-size: 0.75rem; + font-weight: 600; + line-height: 1.25rem; + white-space: nowrap; + border-radius: calc(var(--size-radius) * 0.5); + + &[data-variant="primary"] { + color: var(--color-primary-9); + background-color: var(--color-primary-1); + } + + &[data-variant="secondary"] { + color: var(--color-secondary-9); + background-color: var(--color-secondary-1); + } + + &[data-variant="info"] { + color: var(--color-info-dark); + background-color: var(--color-info-light); + } + + &[data-variant="success"] { + color: var(--color-success-dark); + background-color: var(--color-success-light); + } + + &[data-variant="warning"] { + color: var(--color-warning-dark); + background-color: var(--color-warning-light); + } + + &[data-variant="danger"] { + color: var(--color-danger-dark); + background-color: var(--color-danger-light); + } +} diff --git a/packages/core/src/components/badge/index.ts b/packages/core/src/components/badge/index.ts new file mode 100644 index 0000000..80844a4 --- /dev/null +++ b/packages/core/src/components/badge/index.ts @@ -0,0 +1 @@ +export * from "./badge"; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index 7ed10ca..d8d14a5 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -2,6 +2,7 @@ @import url("./components/alert/index.css"); @import url("./components/alert-dialog/index.css"); @import url("./components/anchor/index.css"); +@import url("./components/badge/index.css"); @import url("./components/box/index.css"); @import url("./components/button/index.css"); @import url("./components/card/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8a95c96..778d1c5 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,6 +2,7 @@ export * from "./components/accordion"; export * from "./components/alert"; export * from "./components/alert-dialog"; export * from "./components/anchor"; +export * from "./components/badge"; export * from "./components/box"; export * from "./components/button"; export * from "./components/card"; From 7f2272a9d71adedd43598930e4e839c594b9459a Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:53:42 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20Drawer=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 画面端からスライドインするドロワー。placement で4方向を指定でき、dismissable で外側クリック時の挙動を制御可能 Co-Authored-By: Claude Fable 5 --- .../src/components/drawer/drawer.stories.tsx | 63 +++++++ .../core/src/components/drawer/drawer.tsx | 71 ++++++++ packages/core/src/components/drawer/index.css | 156 ++++++++++++++++++ packages/core/src/components/drawer/index.ts | 1 + packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 293 insertions(+) create mode 100644 packages/core/src/components/drawer/drawer.stories.tsx create mode 100644 packages/core/src/components/drawer/drawer.tsx create mode 100644 packages/core/src/components/drawer/index.css create mode 100644 packages/core/src/components/drawer/index.ts diff --git a/packages/core/src/components/drawer/drawer.stories.tsx b/packages/core/src/components/drawer/drawer.stories.tsx new file mode 100644 index 0000000..d7957e4 --- /dev/null +++ b/packages/core/src/components/drawer/drawer.stories.tsx @@ -0,0 +1,63 @@ +import { Button } from "../button"; +import { DialogTrigger } from "../dialog"; +import { Drawer, DrawerContent, DrawerTitle } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/Drawer", + component: Drawer, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => ( + + + + + メニュー +

右側からスライドインするドロワーです。

+ +
+
+
+ ), +}; + +export const Placements: Story = { + render: () => ( +
+ {(["left", "right", "top", "bottom"] as const).map((placement) => ( + + + + + {placement} +

{placement} から表示されるドロワーです。

+ +
+
+
+ ))} +
+ ), +}; + +export const NotDismissable: Story = { + render: () => ( + + + + + 確認が必要です +

閉じるボタンを押すまでドロワーは閉じません。

+ +
+
+
+ ), +}; diff --git a/packages/core/src/components/drawer/drawer.tsx b/packages/core/src/components/drawer/drawer.tsx new file mode 100644 index 0000000..a66844c --- /dev/null +++ b/packages/core/src/components/drawer/drawer.tsx @@ -0,0 +1,71 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import { + Dialog as AriaDialog, + Heading as AriaHeading, + Modal as AriaModal, + ModalOverlay as AriaModalOverlay, +} from "react-aria-components"; +import "./index.css"; + +import type { OmitStrict } from "@ginga-ui/utils"; + +export type DrawerProps = OmitStrict< + React.ComponentProps, + "isDismissable" +> & { + placement?: "left" | "right" | "top" | "bottom"; + dismissable?: boolean; +}; + +export const Drawer: React.FC = ({ + children, + className, + placement = "right", + dismissable = true, + ...props +}) => { + return ( + + {children} + + ); +}; + +export type DrawerContentProps = React.ComponentProps; + +export const DrawerContent: React.FC = ({ + children, + className, + ...props +}) => { + return ( + + {children} + + ); +}; + +export type DrawerTitleProps = React.ComponentProps; + +export const DrawerTitle: React.FC = ({ + children, + className, + ...props +}) => { + return ( + + {children} + + ); +}; diff --git a/packages/core/src/components/drawer/index.css b/packages/core/src/components/drawer/index.css new file mode 100644 index 0000000..4937ea5 --- /dev/null +++ b/packages/core/src/components/drawer/index.css @@ -0,0 +1,156 @@ +.ginga-drawer-overlay { + position: fixed; + top: 0; + left: 0; + z-index: 100; + width: 100%; + height: 100%; + background-color: rgb(0 0 0 / 50%); + + &[data-entering] { + animation: ginga-drawer-fade 200ms ease-out; + } + + &[data-exiting] { + animation: ginga-drawer-fade 200ms ease-in reverse; + } + + .ginga-drawer { + position: absolute; + display: flex; + background-color: var(--color-background); + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 10%), + 0 2px 4px -1px rgb(0 0 0 / 6%); + } + + &[data-placement="left"] .ginga-drawer { + top: 0; + left: 0; + width: 20rem; + max-width: 90vw; + height: 100%; + + &[data-entering] { + animation: ginga-drawer-slide-left 200ms ease-out; + } + + &[data-exiting] { + animation: ginga-drawer-slide-left 200ms ease-in reverse; + } + } + + &[data-placement="right"] .ginga-drawer { + top: 0; + right: 0; + width: 20rem; + max-width: 90vw; + height: 100%; + + &[data-entering] { + animation: ginga-drawer-slide-right 200ms ease-out; + } + + &[data-exiting] { + animation: ginga-drawer-slide-right 200ms ease-in reverse; + } + } + + &[data-placement="top"] .ginga-drawer { + top: 0; + left: 0; + width: 100%; + height: 16rem; + max-height: 90vh; + + &[data-entering] { + animation: ginga-drawer-slide-top 200ms ease-out; + } + + &[data-exiting] { + animation: ginga-drawer-slide-top 200ms ease-in reverse; + } + } + + &[data-placement="bottom"] .ginga-drawer { + bottom: 0; + left: 0; + width: 100%; + height: 16rem; + max-height: 90vh; + + &[data-entering] { + animation: ginga-drawer-slide-bottom 200ms ease-out; + } + + &[data-exiting] { + animation: ginga-drawer-slide-bottom 200ms ease-in reverse; + } + } +} + +.ginga-drawer-content { + flex: 1; + padding: 1.5rem; + overflow-y: auto; + font-family: var(--font-family); + color: var(--color-secondary-9); + outline: none; +} + +.ginga-drawer-title { + margin-bottom: 1rem; + font-family: var(--font-family); + font-size: 1.5rem; + font-weight: 800; +} + +@keyframes ginga-drawer-fade { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes ginga-drawer-slide-left { + from { + transform: translateX(-100%); + } + + to { + transform: translateX(0); + } +} + +@keyframes ginga-drawer-slide-right { + from { + transform: translateX(100%); + } + + to { + transform: translateX(0); + } +} + +@keyframes ginga-drawer-slide-top { + from { + transform: translateY(-100%); + } + + to { + transform: translateY(0); + } +} + +@keyframes ginga-drawer-slide-bottom { + from { + transform: translateY(100%); + } + + to { + transform: translateY(0); + } +} diff --git a/packages/core/src/components/drawer/index.ts b/packages/core/src/components/drawer/index.ts new file mode 100644 index 0000000..29c090d --- /dev/null +++ b/packages/core/src/components/drawer/index.ts @@ -0,0 +1 @@ +export * from "./drawer"; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index d8d14a5..59a357e 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -9,6 +9,7 @@ @import url("./components/checkbox/index.css"); @import url("./components/code-block/index.css"); @import url("./components/dialog/index.css"); +@import url("./components/drawer/index.css"); @import url("./components/form-control/index.css"); @import url("./components/heading/index.css"); @import url("./components/image/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 778d1c5..6393164 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -9,6 +9,7 @@ export * from "./components/card"; export * from "./components/checkbox"; export * from "./components/code-block"; export * from "./components/dialog"; +export * from "./components/drawer"; export * from "./components/form-control"; export * from "./components/heading"; export * from "./components/image"; From 57aa267a08d9cb5d785c931e176a1831ca3954c6 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:54:01 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20Popover=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit react-aria の Popover をラップし、非モーダル Dialog と矢印(OverlayArrow)を内蔵。placement と showArrow でカスタマイズ可能 Co-Authored-By: Claude Fable 5 --- .../core/src/components/popover/index.css | 78 +++++++++++++++++++ packages/core/src/components/popover/index.ts | 1 + .../components/popover/popover.stories.tsx | 57 ++++++++++++++ .../core/src/components/popover/popover.tsx | 56 +++++++++++++ packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 194 insertions(+) create mode 100644 packages/core/src/components/popover/index.css create mode 100644 packages/core/src/components/popover/index.ts create mode 100644 packages/core/src/components/popover/popover.stories.tsx create mode 100644 packages/core/src/components/popover/popover.tsx diff --git a/packages/core/src/components/popover/index.css b/packages/core/src/components/popover/index.css new file mode 100644 index 0000000..60df0e5 --- /dev/null +++ b/packages/core/src/components/popover/index.css @@ -0,0 +1,78 @@ +.ginga-popover { + z-index: 50; + min-width: 8rem; + background-color: var(--color-background); + border: var(--width-border) solid var(--color-secondary-9); + border-radius: calc(var(--size-radius) * 0.5); + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 10%), + 0 2px 4px -1px rgb(0 0 0 / 6%); + + &[data-entering] { + animation: ginga-popover-enter 150ms ease-out; + } + + &[data-exiting] { + animation: ginga-popover-exit 150ms ease-in; + } +} + +.ginga-popover-arrow { + svg { + display: block; + fill: var(--color-background); + stroke: var(--color-secondary-9); + stroke-width: var(--width-border); + } + + &[data-placement="top"] svg { + margin-top: calc(var(--width-border) * -1); + } + + &[data-placement="bottom"] svg { + margin-bottom: calc(var(--width-border) * -1); + transform: rotate(180deg); + } + + &[data-placement="left"] svg { + margin-left: calc(var(--width-border) * -1); + transform: rotate(-90deg); + } + + &[data-placement="right"] svg { + margin-right: calc(var(--width-border) * -1); + transform: rotate(90deg); + } +} + +.ginga-popover-dialog { + padding: 1rem; + font-family: var(--font-family); + font-size: 0.875rem; + color: var(--color-secondary-9); + outline: none; +} + +@keyframes ginga-popover-enter { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes ginga-popover-exit { + from { + opacity: 1; + transform: scale(1); + } + + to { + opacity: 0; + transform: scale(0.95); + } +} diff --git a/packages/core/src/components/popover/index.ts b/packages/core/src/components/popover/index.ts new file mode 100644 index 0000000..79c7e29 --- /dev/null +++ b/packages/core/src/components/popover/index.ts @@ -0,0 +1 @@ +export * from "./popover"; diff --git a/packages/core/src/components/popover/popover.stories.tsx b/packages/core/src/components/popover/popover.stories.tsx new file mode 100644 index 0000000..5aa96ed --- /dev/null +++ b/packages/core/src/components/popover/popover.stories.tsx @@ -0,0 +1,57 @@ +import { Button } from "../button"; +import { Popover, PopoverTrigger } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/Popover", + component: Popover, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => ( + + + +

これはポップオーバーの内容です。

+
+
+ ), +}; + +export const Placements: Story = { + render: () => ( +
+ {(["top", "bottom", "left", "right"] as const).map((placement) => ( + + + +

{placement} に表示されます。

+
+
+ ))} +
+ ), +}; + +export const WithoutArrow: Story = { + render: () => ( + + + +

矢印のないポップオーバーです。

+
+
+ ), +}; diff --git a/packages/core/src/components/popover/popover.tsx b/packages/core/src/components/popover/popover.tsx new file mode 100644 index 0000000..8ea5dd4 --- /dev/null +++ b/packages/core/src/components/popover/popover.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import { + Dialog as AriaDialog, + DialogTrigger as AriaDialogTrigger, + OverlayArrow as AriaOverlayArrow, + Popover as AriaPopover, +} from "react-aria-components"; +import "./index.css"; + +import type { OmitStrict } from "@ginga-ui/utils"; + +export type PopoverTriggerProps = React.ComponentProps< + typeof AriaDialogTrigger +>; + +export const PopoverTrigger: React.FC = ({ + children, + ...props +}) => { + return {children}; +}; + +export type PopoverProps = OmitStrict< + React.ComponentProps, + "children" +> & { + children?: React.ReactNode; + showArrow?: boolean; +}; + +export const Popover: React.FC = ({ + children, + className, + placement = "bottom", + showArrow = true, + ...props +}) => { + return ( + + {showArrow && ( + + + + )} + {children} + + ); +}; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index 59a357e..b607a51 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -16,6 +16,7 @@ @import url("./components/input/index.css"); @import url("./components/list/index.css"); @import url("./components/paragraph/index.css"); +@import url("./components/popover/index.css"); @import url("./components/radio/index.css"); @import url("./components/select/index.css"); @import url("./components/slider/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 6393164..ceeaeb6 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,6 +16,7 @@ export * from "./components/image"; export * from "./components/input"; export * from "./components/list"; export * from "./components/paragraph"; +export * from "./components/popover"; export * from "./components/radio"; export * from "./components/select"; export * from "./components/slider"; From 97bf6d5825331b6908072422e5ef9c4dd5926607 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:54:24 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20Toast=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit react-aria の UNSTABLE_ Toast API をラップ。グローバルキューによる toast.show / info / success / warning / danger / close の関数 API と、4隅に配置可能な ToastRegion を提供 Co-Authored-By: Claude Fable 5 --- packages/core/src/components/toast/index.css | 127 ++++++++++++++++++ packages/core/src/components/toast/index.ts | 1 + .../src/components/toast/toast.stories.tsx | 68 ++++++++++ packages/core/src/components/toast/toast.tsx | 110 +++++++++++++++ packages/core/src/index.css | 1 + packages/core/src/index.ts | 1 + 6 files changed, 308 insertions(+) create mode 100644 packages/core/src/components/toast/index.css create mode 100644 packages/core/src/components/toast/index.ts create mode 100644 packages/core/src/components/toast/toast.stories.tsx create mode 100644 packages/core/src/components/toast/toast.tsx diff --git a/packages/core/src/components/toast/index.css b/packages/core/src/components/toast/index.css new file mode 100644 index 0000000..e266981 --- /dev/null +++ b/packages/core/src/components/toast/index.css @@ -0,0 +1,127 @@ +.ginga-toast-region { + position: fixed; + z-index: 150; + display: flex; + flex-direction: column; + gap: 0.5rem; + max-width: calc(100vw - 2rem); + outline: none; + + &[data-placement="top-left"] { + top: 1rem; + left: 1rem; + } + + &[data-placement="top-right"] { + top: 1rem; + right: 1rem; + } + + &[data-placement="bottom-left"] { + bottom: 1rem; + left: 1rem; + } + + &[data-placement="bottom-right"] { + right: 1rem; + bottom: 1rem; + } + + &[data-focus-visible] { + outline: 2px solid var(--color-primary-5); + outline-offset: 2px; + } +} + +.ginga-toast { + display: flex; + gap: 0.75rem; + align-items: flex-start; + width: 20rem; + max-width: 100%; + padding: 0.75rem 1rem; + font-family: var(--font-family); + border-left: 4px solid; + border-radius: calc(var(--size-radius) * 0.5); + box-shadow: + 0 4px 6px -1px rgb(0 0 0 / 10%), + 0 2px 4px -1px rgb(0 0 0 / 6%); + animation: ginga-toast-enter 200ms ease-out; + + &[data-variant="info"] { + color: var(--color-info-dark); + background-color: var(--color-info-light); + border-left-color: var(--color-info); + } + + &[data-variant="success"] { + color: var(--color-success-dark); + background-color: var(--color-success-light); + border-left-color: var(--color-success); + } + + &[data-variant="warning"] { + color: var(--color-warning-dark); + background-color: var(--color-warning-light); + border-left-color: var(--color-warning); + } + + &[data-variant="danger"] { + color: var(--color-danger-dark); + background-color: var(--color-danger-light); + border-left-color: var(--color-danger); + } + + &[data-focus-visible] { + outline: 2px solid var(--color-primary-5); + outline-offset: 2px; + } +} + +.ginga-toast-content { + display: flex; + flex: 1; + flex-direction: column; + gap: 0.25rem; +} + +.ginga-toast-title { + font-size: 0.875rem; + font-weight: 700; +} + +.ginga-toast-description { + font-size: 0.8125rem; +} + +.ginga-toast-close { + padding: 0 0.25rem; + font-size: 1rem; + line-height: 1.25rem; + color: inherit; + cursor: pointer; + background: none; + border: none; + border-radius: calc(var(--size-radius) * 0.25); + + &[data-hovered] { + background-color: rgb(0 0 0 / 8%); + } + + &[data-focus-visible] { + outline: 2px solid var(--color-primary-5); + outline-offset: 1px; + } +} + +@keyframes ginga-toast-enter { + from { + opacity: 0; + transform: translateY(0.5rem); + } + + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/packages/core/src/components/toast/index.ts b/packages/core/src/components/toast/index.ts new file mode 100644 index 0000000..da08986 --- /dev/null +++ b/packages/core/src/components/toast/index.ts @@ -0,0 +1 @@ +export * from "./toast"; diff --git a/packages/core/src/components/toast/toast.stories.tsx b/packages/core/src/components/toast/toast.stories.tsx new file mode 100644 index 0000000..85a0196 --- /dev/null +++ b/packages/core/src/components/toast/toast.stories.tsx @@ -0,0 +1,68 @@ +import { Button } from "../button"; +import { toast, ToastRegion } from "./index"; + +import type { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Display/Toast", + component: ToastRegion, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + render: () => ( + <> + + + + ), +}; + +export const Variants: Story = { + render: () => ( + <> + +
+ + + + +
+ + ), +}; + +export const WithDescriptionAndTimeout: Story = { + render: () => ( + <> + + + + ), +}; diff --git a/packages/core/src/components/toast/toast.tsx b/packages/core/src/components/toast/toast.tsx new file mode 100644 index 0000000..e96aed0 --- /dev/null +++ b/packages/core/src/components/toast/toast.tsx @@ -0,0 +1,110 @@ +"use client"; + +import { cn } from "@ginga-ui/utils"; +import { + Button as AriaButton, + Text as AriaText, + UNSTABLE_Toast as AriaToast, + UNSTABLE_ToastContent as AriaToastContent, + UNSTABLE_ToastQueue as AriaToastQueue, + UNSTABLE_ToastRegion as AriaToastRegion, +} from "react-aria-components"; +import "./index.css"; + +import type { OmitStrict } from "@ginga-ui/utils"; +import type { ToastRegionProps as AriaToastRegionProps } from "react-aria-components"; + +export type ToastVariant = "info" | "success" | "warning" | "danger"; + +export type ToastContentValue = { + title: string; + description?: string; + variant?: ToastVariant; +}; + +export type ToastOptions = { + description?: string; + timeout?: number; + onClose?: () => void; +}; + +const defaultQueue = new AriaToastQueue({ + maxVisibleToasts: 5, +}); + +const show = ( + title: string, + options: ToastOptions & { variant?: ToastVariant } = {} +): string => { + const { description, variant, timeout, onClose } = options; + return defaultQueue.add( + { title, description, variant }, + { + timeout, + onClose, + } + ); +}; + +export const toast = { + show, + info: (title: string, options: ToastOptions = {}): string => + show(title, { ...options, variant: "info" }), + success: (title: string, options: ToastOptions = {}): string => + show(title, { ...options, variant: "success" }), + warning: (title: string, options: ToastOptions = {}): string => + show(title, { ...options, variant: "warning" }), + danger: (title: string, options: ToastOptions = {}): string => + show(title, { ...options, variant: "danger" }), + close: (key: string): void => defaultQueue.close(key), +}; + +export type ToastRegionProps = OmitStrict< + AriaToastRegionProps, + "queue" | "children" +> & { + queue?: AriaToastQueue; + placement?: "top-left" | "top-right" | "bottom-left" | "bottom-right"; +}; + +export const ToastRegion: React.FC = ({ + className, + queue = defaultQueue, + placement = "bottom-right", + ...props +}) => { + return ( + + {({ toast: queuedToast }) => ( + + + + {queuedToast.content.title} + + {queuedToast.content.description && ( + + {queuedToast.content.description} + + )} + + + × + + + )} + + ); +}; diff --git a/packages/core/src/index.css b/packages/core/src/index.css index b607a51..b40fd2d 100644 --- a/packages/core/src/index.css +++ b/packages/core/src/index.css @@ -23,3 +23,4 @@ @import url("./components/switch/index.css"); @import url("./components/tab/index.css"); @import url("./components/table/index.css"); +@import url("./components/toast/index.css"); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ceeaeb6..ba3eb27 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -23,3 +23,4 @@ export * from "./components/slider"; export * from "./components/switch"; export * from "./components/tab"; export * from "./components/table"; +export * from "./components/toast"; From 5921835a7e2c5cb272670236e978cd07822259bc Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:54:35 +0900 Subject: [PATCH 08/11] =?UTF-8?q?docs:=20=E6=96=B0=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=886=E7=A8=AE?= =?UTF-8?q?=E3=81=AE=E3=83=89=E3=82=AD=E3=83=A5=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AlertDialog / Drawer / Popover / Alert / Badge / Toast のメタデータ・デモ・MDXページを追加し、コンポーネント総数の表記を25個に更新 Co-Authored-By: Claude Fable 5 --- .../src/app/components/alert-dialog/page.mdx | 18 +++ .../src/app/components/alert/page.mdx | 18 +++ .../src/app/components/badge/page.mdx | 18 +++ .../src/app/components/drawer/page.mdx | 18 +++ app/ginga-ui.com/src/app/components/page.tsx | 2 +- .../src/app/components/popover/page.mdx | 18 +++ .../src/app/components/toast/page.mdx | 18 +++ app/ginga-ui.com/src/data/components.ts | 41 +++++++ app/ginga-ui.com/src/data/configs.ts | 113 ++++++++++++++++++ .../src/examples/alert-dialog.tsx | 75 ++++++++++++ app/ginga-ui.com/src/examples/alert.tsx | 47 ++++++++ app/ginga-ui.com/src/examples/badge.tsx | 29 +++++ app/ginga-ui.com/src/examples/drawer.tsx | 64 ++++++++++ app/ginga-ui.com/src/examples/popover.tsx | 40 +++++++ app/ginga-ui.com/src/examples/toast.tsx | 63 ++++++++++ 15 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 app/ginga-ui.com/src/app/components/alert-dialog/page.mdx create mode 100644 app/ginga-ui.com/src/app/components/alert/page.mdx create mode 100644 app/ginga-ui.com/src/app/components/badge/page.mdx create mode 100644 app/ginga-ui.com/src/app/components/drawer/page.mdx create mode 100644 app/ginga-ui.com/src/app/components/popover/page.mdx create mode 100644 app/ginga-ui.com/src/app/components/toast/page.mdx create mode 100644 app/ginga-ui.com/src/examples/alert-dialog.tsx create mode 100644 app/ginga-ui.com/src/examples/alert.tsx create mode 100644 app/ginga-ui.com/src/examples/badge.tsx create mode 100644 app/ginga-ui.com/src/examples/drawer.tsx create mode 100644 app/ginga-ui.com/src/examples/popover.tsx create mode 100644 app/ginga-ui.com/src/examples/toast.tsx diff --git a/app/ginga-ui.com/src/app/components/alert-dialog/page.mdx b/app/ginga-ui.com/src/app/components/alert-dialog/page.mdx new file mode 100644 index 0000000..ee5491e --- /dev/null +++ b/app/ginga-ui.com/src/app/components/alert-dialog/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + WarningExample, + PlainExample, +} from "#/examples/alert-dialog"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/app/components/alert/page.mdx b/app/ginga-ui.com/src/app/components/alert/page.mdx new file mode 100644 index 0000000..8d8ebaa --- /dev/null +++ b/app/ginga-ui.com/src/app/components/alert/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + VariantsExample, + DescriptionOnlyExample, +} from "#/examples/alert"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/app/components/badge/page.mdx b/app/ginga-ui.com/src/app/components/badge/page.mdx new file mode 100644 index 0000000..04131b5 --- /dev/null +++ b/app/ginga-ui.com/src/app/components/badge/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + VariantsExample, + WithTextExample, +} from "#/examples/badge"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/app/components/drawer/page.mdx b/app/ginga-ui.com/src/app/components/drawer/page.mdx new file mode 100644 index 0000000..d382e34 --- /dev/null +++ b/app/ginga-ui.com/src/app/components/drawer/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + PlacementsExample, + NotDismissableExample, +} from "#/examples/drawer"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/app/components/page.tsx b/app/ginga-ui.com/src/app/components/page.tsx index da6a52b..f89b831 100644 --- a/app/ginga-ui.com/src/app/components/page.tsx +++ b/app/ginga-ui.com/src/app/components/page.tsx @@ -25,7 +25,7 @@ export default function ComponentsPage() { 全コンポーネント Ginga - UIが提供する全19個のコンポーネントを確認できます。タブでカテゴリを切り替えて、各コンポーネントの詳細ページにアクセスできます。 + UIが提供する全25個のコンポーネントを確認できます。タブでカテゴリを切り替えて、各コンポーネントの詳細ページにアクセスできます。
diff --git a/app/ginga-ui.com/src/app/components/popover/page.mdx b/app/ginga-ui.com/src/app/components/popover/page.mdx new file mode 100644 index 0000000..6f0064f --- /dev/null +++ b/app/ginga-ui.com/src/app/components/popover/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + PlacementsExample, + WithoutArrowExample, +} from "#/examples/popover"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/app/components/toast/page.mdx b/app/ginga-ui.com/src/app/components/toast/page.mdx new file mode 100644 index 0000000..fb13aae --- /dev/null +++ b/app/ginga-ui.com/src/app/components/toast/page.mdx @@ -0,0 +1,18 @@ +import { ComponentDoc, Example } from "#/components/component-doc"; +import { + BasicExample, + VariantsExample, + TimeoutExample, +} from "#/examples/toast"; + + + + + + + + + + + + diff --git a/app/ginga-ui.com/src/data/components.ts b/app/ginga-ui.com/src/data/components.ts index f78dd9f..02153a1 100644 --- a/app/ginga-ui.com/src/data/components.ts +++ b/app/ginga-ui.com/src/data/components.ts @@ -85,6 +85,26 @@ const COMPONENTS: ComponentMetadata[] = [ category: "display", description: "展開/折りたたみ可能なコンテンツセクション。", }, + { + id: "alert", + name: "Alert", + category: "display", + description: + "重要な情報をユーザーに伝えるアラート。4種類のバリアント(info、success、warning、danger)をサポート。", + }, + { + id: "alert-dialog", + name: "AlertDialog", + category: "display", + description: + "ユーザーの確認を必須とするアラートダイアログ。破壊的な操作の確認などに使用。", + }, + { + id: "badge", + name: "Badge", + category: "display", + description: "ステータスやラベルを表示する小さなバッジ。", + }, { id: "card", name: "Card", @@ -98,6 +118,13 @@ const COMPONENTS: ComponentMetadata[] = [ description: "モーダルダイアログ。ユーザーの注意を引く重要な情報や操作を表示。", }, + { + id: "drawer", + name: "Drawer", + category: "display", + description: + "画面の端からスライドインするドロワー。4方向(left、right、top、bottom)に対応。", + }, { id: "image", name: "Image", @@ -110,6 +137,13 @@ const COMPONENTS: ComponentMetadata[] = [ category: "display", description: "順序付きリストと順序なしリストを表示。", }, + { + id: "popover", + name: "Popover", + category: "display", + description: + "トリガー要素に紐づけて表示されるポップオーバー。配置方向と矢印表示をカスタマイズ可能。", + }, { id: "table", name: "Table", @@ -123,6 +157,13 @@ const COMPONENTS: ComponentMetadata[] = [ description: "タブで切り替え可能なコンテンツパネル。水平・垂直レイアウトに対応。", }, + { + id: "toast", + name: "Toast", + category: "display", + description: + "一時的な通知を表示するトースト。プログラマティックなAPI(toast.success等)で呼び出し可能。", + }, // Typography { diff --git a/app/ginga-ui.com/src/data/configs.ts b/app/ginga-ui.com/src/data/configs.ts index a00f4a6..243c489 100644 --- a/app/ginga-ui.com/src/data/configs.ts +++ b/app/ginga-ui.com/src/data/configs.ts @@ -27,6 +27,43 @@ export const EXAMPLE_CONFIGS: Record = { description: "状態を外部から制御するアコーディオンです。", }, ], + alert: [ + { + name: "BasicExample", + title: "基本的な使い方", + description: "タイトルと説明文を持つシンプルなアラートです。", + }, + { + name: "VariantsExample", + title: "バリアント", + description: + "info、success、warning、dangerの4種類のバリアントを指定できます。", + }, + { + name: "DescriptionOnlyExample", + title: "説明文のみ", + description: + "タイトルを省略して説明文だけを表示できます。動的に挿入して通知する場合はrole属性にalertを渡すか、Toastの利用を検討してください。", + }, + ], + "alert-dialog": [ + { + name: "BasicExample", + title: "基本的な使い方", + description: + "破壊的な操作の確認を求めるアラートダイアログです。外側をクリックしても閉じず、明示的な選択を求めます。", + }, + { + name: "WarningExample", + title: "警告バリアント", + description: "variantプロップでタイトル色とアクセントを変更できます。", + }, + { + name: "PlainExample", + title: "バリアントなし", + description: "variantを指定しない場合は通常の配色で表示されます。", + }, + ], anchor: [ { name: "BasicExample", @@ -49,6 +86,24 @@ export const EXAMPLE_CONFIGS: Record = { description: "ボタンのようなスタイルでリンクを表示します。", }, ], + badge: [ + { + name: "BasicExample", + title: "基本的な使い方", + description: "シンプルなバッジの使用例です。", + }, + { + name: "VariantsExample", + title: "バリアント", + description: + "primary、secondary、info、success、warning、dangerの6種類のバリアントを指定できます。", + }, + { + name: "WithTextExample", + title: "テキストと組み合わせる", + description: "テキストの横に件数などを表示できます。", + }, + ], box: [ { name: "BasicExample", @@ -160,6 +215,25 @@ export const EXAMPLE_CONFIGS: Record = { description: "シンプルなアラートダイアログです。", }, ], + drawer: [ + { + name: "BasicExample", + title: "基本的な使い方", + description: "画面の右端からスライドインするドロワーです。", + }, + { + name: "PlacementsExample", + title: "表示位置", + description: + "placementプロップでleft、right、top、bottomの4方向を指定できます。", + }, + { + name: "NotDismissableExample", + title: "外側クリックで閉じない", + description: + "dismissableプロップにfalseを渡すと、外側のクリックやESCキーでは閉じなくなります。", + }, + ], "form-control": [ { name: "BasicExample", @@ -293,6 +367,25 @@ export const EXAMPLE_CONFIGS: Record = { description: "カスタムスタイルを適用した段落です。", }, ], + popover: [ + { + name: "BasicExample", + title: "基本的な使い方", + description: + "トリガーの下に表示されるシンプルなポップオーバーです。フォーカス管理とキーボード操作に対応しています。", + }, + { + name: "PlacementsExample", + title: "表示位置", + description: + "placementプロップでtop、bottom、left、rightなどの表示位置を指定できます。", + }, + { + name: "WithoutArrowExample", + title: "矢印なし", + description: "showArrowプロップにfalseを渡すと矢印を非表示にできます。", + }, + ], radio: [ { name: "BasicExample", @@ -403,6 +496,26 @@ export const EXAMPLE_CONFIGS: Record = { description: "状態を外部から制御するタブです。", }, ], + toast: [ + { + name: "BasicExample", + title: "基本的な使い方", + description: + "ToastRegionをアプリのルートに1回だけ設置し、toast.showで通知を表示します。toast関数はクライアントのイベントハンドラから呼び出してください。", + }, + { + name: "VariantsExample", + title: "バリアント", + description: + "toast.info、toast.success、toast.warning、toast.dangerで状態に応じた通知を表示できます。", + }, + { + name: "TimeoutExample", + title: "自動クローズ", + description: + "timeoutオプションを指定すると自動的に閉じます。ホバーやフォーカス中はタイマーが一時停止します。", + }, + ], table: [ { name: "BasicExample", diff --git a/app/ginga-ui.com/src/examples/alert-dialog.tsx b/app/ginga-ui.com/src/examples/alert-dialog.tsx new file mode 100644 index 0000000..ff3e362 --- /dev/null +++ b/app/ginga-ui.com/src/examples/alert-dialog.tsx @@ -0,0 +1,75 @@ +"use client"; + +import { + AlertDialog, + AlertDialogTitle, + Button, + DialogTrigger, + Modal, +} from "@ginga-ui/core"; + +export function BasicExample() { + return ( + + + + + ファイルの削除 +

この操作は取り消せません。本当に削除しますか?

+
+ + +
+
+
+
+ ); +} + +export function WarningExample() { + return ( + + + + + ログアウトの確認 +

保存されていない変更は失われます。ログアウトしますか?

+
+ + +
+
+
+
+ ); +} + +export function PlainExample() { + return ( + + + + + 利用規約の更新 +

利用規約が更新されました。続行するには同意が必要です。

+
+ + +
+
+
+
+ ); +} diff --git a/app/ginga-ui.com/src/examples/alert.tsx b/app/ginga-ui.com/src/examples/alert.tsx new file mode 100644 index 0000000..08457a1 --- /dev/null +++ b/app/ginga-ui.com/src/examples/alert.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { Alert, AlertDescription, AlertTitle } from "@ginga-ui/core"; + +export function BasicExample() { + return ( + + お知らせ + + メンテナンスのため、明日の午前2時から4時までサービスを停止します。 + + + ); +} + +export function VariantsExample() { + return ( +
+ + 情報 + 新しいバージョンが利用可能です。 + + + 成功 + 変更が保存されました。 + + + 警告 + + ストレージの空き容量が少なくなっています。 + + + + エラー + データの読み込みに失敗しました。 + +
+ ); +} + +export function DescriptionOnlyExample() { + return ( + + プロフィールを更新しました。 + + ); +} diff --git a/app/ginga-ui.com/src/examples/badge.tsx b/app/ginga-ui.com/src/examples/badge.tsx new file mode 100644 index 0000000..20b0388 --- /dev/null +++ b/app/ginga-ui.com/src/examples/badge.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { Badge } from "@ginga-ui/core"; + +export function BasicExample() { + return New; +} + +export function VariantsExample() { + return ( +
+ Primary + Secondary + Info + Success + Warning + Danger +
+ ); +} + +export function WithTextExample() { + return ( +

+ 通知が届いています + 3 +

+ ); +} diff --git a/app/ginga-ui.com/src/examples/drawer.tsx b/app/ginga-ui.com/src/examples/drawer.tsx new file mode 100644 index 0000000..bfaf026 --- /dev/null +++ b/app/ginga-ui.com/src/examples/drawer.tsx @@ -0,0 +1,64 @@ +"use client"; + +import { + Button, + DialogTrigger, + Drawer, + DrawerContent, + DrawerTitle, +} from "@ginga-ui/core"; + +export function BasicExample() { + return ( + + + + + メニュー +

右側からスライドインするドロワーです。

+ +
+
+
+ ); +} + +export function PlacementsExample() { + return ( +
+ {(["left", "right", "top", "bottom"] as const).map((placement) => ( + + + + + {placement} +

{placement} から表示されるドロワーです。

+ +
+
+
+ ))} +
+ ); +} + +export function NotDismissableExample() { + return ( + + + + + 確認が必要です +

閉じるボタンを押すまでドロワーは閉じません。

+ +
+
+
+ ); +} diff --git a/app/ginga-ui.com/src/examples/popover.tsx b/app/ginga-ui.com/src/examples/popover.tsx new file mode 100644 index 0000000..4bb364c --- /dev/null +++ b/app/ginga-ui.com/src/examples/popover.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { Button, Popover, PopoverTrigger } from "@ginga-ui/core"; + +export function BasicExample() { + return ( + + + +

これはポップオーバーの内容です。

+
+
+ ); +} + +export function PlacementsExample() { + return ( +
+ {(["top", "bottom", "left", "right"] as const).map((placement) => ( + + + +

{placement} に表示されます。

+
+
+ ))} +
+ ); +} + +export function WithoutArrowExample() { + return ( + + + +

矢印のないポップオーバーです。

+
+
+ ); +} diff --git a/app/ginga-ui.com/src/examples/toast.tsx b/app/ginga-ui.com/src/examples/toast.tsx new file mode 100644 index 0000000..7c10e7c --- /dev/null +++ b/app/ginga-ui.com/src/examples/toast.tsx @@ -0,0 +1,63 @@ +"use client"; + +import { Button, toast, ToastRegion } from "@ginga-ui/core"; + +export function BasicExample() { + return ( + <> + + + + ); +} + +export function VariantsExample() { + return ( +
+ + + + +
+ ); +} + +export function TimeoutExample() { + return ( + + ); +} From b2040deae47c38bc5243b80ac0bfa41d4cc5c471 Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 16:55:14 +0900 Subject: [PATCH 09/11] =?UTF-8?q?chore:=20changeset=20=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=81=97=20CHANGELOG=20=E3=81=AB=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E5=86=85=E5=AE=B9=E3=82=92=E8=BF=BD=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .changeset/six-feedback-overlay-components.md | 13 +++++++++++++ CHANGELOG.md | 5 +++++ 2 files changed, 18 insertions(+) create mode 100644 .changeset/six-feedback-overlay-components.md diff --git a/.changeset/six-feedback-overlay-components.md b/.changeset/six-feedback-overlay-components.md new file mode 100644 index 0000000..7731da4 --- /dev/null +++ b/.changeset/six-feedback-overlay-components.md @@ -0,0 +1,13 @@ +--- +"@ginga-ui/core": minor +--- + +AlertDialog / Drawer / Popover / Alert / Badge / Toast コンポーネントを追加 + +- variables.css にセマンティックカラー変数(`--color-info` / `--color-success` / `--color-warning` / `--color-danger` とそれぞれの `-light` / `-dark`)を追加 +- Alert: タイトルと説明文を持つ静的表示コンポーネント。info / success / warning / danger の4バリアント +- Badge: primary / secondary と状態色4種の計6バリアントを持つバッジ +- AlertDialog: `role="alertdialog"` 固定のダイアログ。既存の Modal / DialogTrigger と組み合わせて使用 +- Drawer: placement で4方向(left / right / top / bottom)のスライドインに対応。dismissable prop で外側クリック時の挙動を制御 +- Popover: react-aria の Popover をラップし、非モーダル Dialog と矢印(OverlayArrow)を内蔵。placement / showArrow でカスタマイズ可能 +- Toast: react-aria の UNSTABLE_ Toast API をラップ。`toast.show` / `info` / `success` / `warning` / `danger` / `close` の関数 API と、4隅に配置可能な ToastRegion を提供 diff --git a/CHANGELOG.md b/CHANGELOG.md index c737764..393ecf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## v0.14.0 + +- feat: AlertDialog / Drawer / Popover / Alert / Badge / Toast コンポーネントを追加 +- feat: セマンティックカラー変数(`--color-info` / `--color-success` / `--color-warning` / `--color-danger`)を追加 + ## v0.11.0 - remove: CSS Modules From 636d919f122fb7b7fe103f8ccd51c5d3c4fd5efd Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 17:05:31 +0900 Subject: [PATCH 10/11] =?UTF-8?q?style:=20=E6=96=B0=E8=A6=8F=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=81=AE?= =?UTF-8?q?px=E6=8C=87=E5=AE=9A=E3=82=92rem=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .changeset/six-feedback-overlay-components.md | 13 ------------- .../core/src/components/alert-dialog/index.css | 6 +++--- packages/core/src/components/alert/index.css | 2 +- packages/core/src/components/drawer/index.css | 4 ++-- packages/core/src/components/popover/index.css | 4 ++-- packages/core/src/components/toast/index.css | 18 +++++++++--------- 6 files changed, 17 insertions(+), 30 deletions(-) delete mode 100644 .changeset/six-feedback-overlay-components.md diff --git a/.changeset/six-feedback-overlay-components.md b/.changeset/six-feedback-overlay-components.md deleted file mode 100644 index 7731da4..0000000 --- a/.changeset/six-feedback-overlay-components.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@ginga-ui/core": minor ---- - -AlertDialog / Drawer / Popover / Alert / Badge / Toast コンポーネントを追加 - -- variables.css にセマンティックカラー変数(`--color-info` / `--color-success` / `--color-warning` / `--color-danger` とそれぞれの `-light` / `-dark`)を追加 -- Alert: タイトルと説明文を持つ静的表示コンポーネント。info / success / warning / danger の4バリアント -- Badge: primary / secondary と状態色4種の計6バリアントを持つバッジ -- AlertDialog: `role="alertdialog"` 固定のダイアログ。既存の Modal / DialogTrigger と組み合わせて使用 -- Drawer: placement で4方向(left / right / top / bottom)のスライドインに対応。dismissable prop で外側クリック時の挙動を制御 -- Popover: react-aria の Popover をラップし、非モーダル Dialog と矢印(OverlayArrow)を内蔵。placement / showArrow でカスタマイズ可能 -- Toast: react-aria の UNSTABLE_ Toast API をラップ。`toast.show` / `info` / `success` / `warning` / `danger` / `close` の関数 API と、4隅に配置可能な ToastRegion を提供 diff --git a/packages/core/src/components/alert-dialog/index.css b/packages/core/src/components/alert-dialog/index.css index 35c4a24..d0a7c83 100644 --- a/packages/core/src/components/alert-dialog/index.css +++ b/packages/core/src/components/alert-dialog/index.css @@ -6,11 +6,11 @@ font-family: var(--font-family); color: var(--color-secondary-9); background-color: var(--color-background); - border-top: 4px solid var(--color-secondary-9); + border-top: 0.25rem solid var(--color-secondary-9); border-radius: calc(var(--size-radius) * 0.5); box-shadow: - 0 4px 6px -1px rgb(0 0 0 / 10%), - 0 2px 4px -1px rgb(0 0 0 / 6%); + 0 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 10%), + 0 0.125rem 0.25rem -0.0625rem rgb(0 0 0 / 6%); &[data-variant="info"] { border-top-color: var(--color-info); diff --git a/packages/core/src/components/alert/index.css b/packages/core/src/components/alert/index.css index be82c6b..e2d4ec1 100644 --- a/packages/core/src/components/alert/index.css +++ b/packages/core/src/components/alert/index.css @@ -4,7 +4,7 @@ gap: 0.25rem; padding: 0.75rem 1rem; font-family: var(--font-family); - border-left: 4px solid; + border-left: 0.25rem solid; border-radius: calc(var(--size-radius) * 0.5); &[data-variant="info"] { diff --git a/packages/core/src/components/drawer/index.css b/packages/core/src/components/drawer/index.css index 4937ea5..b5f39ec 100644 --- a/packages/core/src/components/drawer/index.css +++ b/packages/core/src/components/drawer/index.css @@ -20,8 +20,8 @@ display: flex; background-color: var(--color-background); box-shadow: - 0 4px 6px -1px rgb(0 0 0 / 10%), - 0 2px 4px -1px rgb(0 0 0 / 6%); + 0 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 10%), + 0 0.125rem 0.25rem -0.0625rem rgb(0 0 0 / 6%); } &[data-placement="left"] .ginga-drawer { diff --git a/packages/core/src/components/popover/index.css b/packages/core/src/components/popover/index.css index 60df0e5..7895ed5 100644 --- a/packages/core/src/components/popover/index.css +++ b/packages/core/src/components/popover/index.css @@ -5,8 +5,8 @@ border: var(--width-border) solid var(--color-secondary-9); border-radius: calc(var(--size-radius) * 0.5); box-shadow: - 0 4px 6px -1px rgb(0 0 0 / 10%), - 0 2px 4px -1px rgb(0 0 0 / 6%); + 0 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 10%), + 0 0.125rem 0.25rem -0.0625rem rgb(0 0 0 / 6%); &[data-entering] { animation: ginga-popover-enter 150ms ease-out; diff --git a/packages/core/src/components/toast/index.css b/packages/core/src/components/toast/index.css index e266981..510b5ee 100644 --- a/packages/core/src/components/toast/index.css +++ b/packages/core/src/components/toast/index.css @@ -28,8 +28,8 @@ } &[data-focus-visible] { - outline: 2px solid var(--color-primary-5); - outline-offset: 2px; + outline: 0.125rem solid var(--color-primary-5); + outline-offset: 0.125rem; } } @@ -41,11 +41,11 @@ max-width: 100%; padding: 0.75rem 1rem; font-family: var(--font-family); - border-left: 4px solid; + border-left: 0.25rem solid; border-radius: calc(var(--size-radius) * 0.5); box-shadow: - 0 4px 6px -1px rgb(0 0 0 / 10%), - 0 2px 4px -1px rgb(0 0 0 / 6%); + 0 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 10%), + 0 0.125rem 0.25rem -0.0625rem rgb(0 0 0 / 6%); animation: ginga-toast-enter 200ms ease-out; &[data-variant="info"] { @@ -73,8 +73,8 @@ } &[data-focus-visible] { - outline: 2px solid var(--color-primary-5); - outline-offset: 2px; + outline: 0.125rem solid var(--color-primary-5); + outline-offset: 0.125rem; } } @@ -109,8 +109,8 @@ } &[data-focus-visible] { - outline: 2px solid var(--color-primary-5); - outline-offset: 1px; + outline: 0.125rem solid var(--color-primary-5); + outline-offset: 0.0625rem; } } From 9ac96fd1a5aef422feb7db44fb6712935ae42c7f Mon Sep 17 00:00:00 2001 From: newt Date: Wed, 8 Jul 2026 17:05:31 +0900 Subject: [PATCH 11/11] =?UTF-8?q?chore:=20changeset=E3=82=92=E6=97=A2?= =?UTF-8?q?=E5=AD=98=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AB=E7=B5=B1?= =?UTF-8?q?=E5=90=88=E3=81=97CHANGELOG=E3=81=B8=E6=9C=AA=E8=A8=98=E8=BC=89?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新コンポーネントの変更内容を plenty-moons-shake.md へ統合し、重複していた changeset を削除 - CHANGELOG.md に v0.12.0〜v0.13.3 の未記載バージョンを追記し、v0.14.0 に未リリースの CodeBlock 追加分を追加 Co-Authored-By: Claude Fable 5 --- .changeset/plenty-moons-shake.md | 10 ++++++++++ CHANGELOG.md | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/.changeset/plenty-moons-shake.md b/.changeset/plenty-moons-shake.md index 810ba9c..29d93b1 100644 --- a/.changeset/plenty-moons-shake.md +++ b/.changeset/plenty-moons-shake.md @@ -7,3 +7,13 @@ CodeBlock コンポーネントを追加し、Card と Anchor のスタイルを - CodeBlock コンポーネントを新規追加。クリップボードコピー機能を内蔵し、シンタックスハイライト済みの React 要素を children で注入可能(shiki 等は非内包) - Card の視覚変更: CodeBlock と同じ外観に統一(border を `--color-primary-2` に、padding 1rem を Card 本体に移動し各セクションの間隔は gap で管理)し、box-shadow を削除 - Anchor `variant="button"` の視覚変更: Button と統一(角丸を `calc(var(--size-radius) * 0.5)` に、フォーカスリングを outline 方式に、disabled 表現と transition を Button と同一に) + +AlertDialog / Drawer / Popover / Alert / Badge / Toast コンポーネントを追加 + +- variables.css にセマンティックカラー変数(`--color-info` / `--color-success` / `--color-warning` / `--color-danger` とそれぞれの `-light` / `-dark`)を追加 +- Alert: タイトルと説明文を持つ静的表示コンポーネント。info / success / warning / danger の4バリアント +- Badge: primary / secondary と状態色4種の計6バリアントを持つバッジ +- AlertDialog: `role="alertdialog"` 固定のダイアログ。既存の Modal / DialogTrigger と組み合わせて使用 +- Drawer: placement で4方向(left / right / top / bottom)のスライドインに対応。dismissable prop で外側クリック時の挙動を制御 +- Popover: react-aria の Popover をラップし、非モーダル Dialog と矢印(OverlayArrow)を内蔵。placement / showArrow でカスタマイズ可能 +- Toast: react-aria の UNSTABLE\_ Toast API をラップ。`toast.show` / `info` / `success` / `warning` / `danger` / `close` の関数 API と、4隅に配置可能な ToastRegion を提供 diff --git a/CHANGELOG.md b/CHANGELOG.md index 393ecf0..dda5288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,25 @@ - feat: AlertDialog / Drawer / Popover / Alert / Badge / Toast コンポーネントを追加 - feat: セマンティックカラー変数(`--color-info` / `--color-success` / `--color-warning` / `--color-danger`)を追加 +- feat: CodeBlock コンポーネントを追加 +- improve: Card と Anchor のスタイルを CodeBlock / Button と統一 + +## v0.13.3 + +- chore: changesets の fixed 設定で `@ginga-ui/core`・`@ginga-ui/utils`・`ginga-ui.com` のバージョンを 0.13.3 に統一 +- fix: tsdown を unbundle 化し、`"use client"` バナーの保持と CSS の自動付随に対応 + +## v0.12.2 + +- change: ビルドツールを tsup から tsdown(Rolldown ベース)へ移行 + +## v0.12.1 + +- fix: デプロイワークフローを修正 + +## v0.12.0 + +- change: パッケージスキーマを変更 ## v0.11.0