Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらも同様です。internalをsparkle-design側から参照する想定はありません。

Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ next-env.d.ts
!.cursor/rules/
!.cursor/skills

# sparkle-design-internal をワークスペース内に置いた場合(スキルは .cursor/skills に同期)
# en: Local clone of internal repo at repo root — avoid accidental commits
/sparkle-design-internal/

# vscode
# .vscode

Expand Down
1 change: 0 additions & 1 deletion package.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要な差分なのでこれが必要ないように作ってほしいです!

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"build:registry:merge": "node scripts/merge-registry.mjs",
"build:registry:vercel": "bash scripts/build-registry-vercel.sh",
"preinstall": "npx only-allow pnpm",
"postinstall": "npx lightningcss --version || true",
"build:package": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
"format": "prettier --config ./.prettierrc -w \"**/*.{js,ts,tsx,css,md,json}\"",
"format:check": "prettier --config ./.prettierrc --check \"**/*.{js,ts,tsx,css,md,json}\"",
Expand Down
55 changes: 55 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,61 @@
height: 0;
}
}

@keyframes sparkle-overlay-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes sparkle-overlay-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}

@keyframes sparkle-modal-in {
from {
opacity: 0;
transform: translateY(8px) scale(0.98);
}
to {
opacity: 1;
transform: translateY(0px) scale(1);
}
}
@keyframes sparkle-modal-out {
from {
opacity: 1;
transform: translateY(0px) scale(1);
}
to {
opacity: 0;
transform: translateY(6px) scale(0.98);
}
}

@keyframes sparkle-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes sparkle-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@utility accordion-down {
animation: accordion-down 0.2s ease-out;
}
Expand Down
9 changes: 5 additions & 4 deletions src/components/ui/link/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import NextLink from "next/link";
import React from "react";
import { Link } from "./index";

Expand Down Expand Up @@ -26,15 +27,15 @@ export const Default: Story = {
args: {
children: "リンクテキスト",
isOpenInNew: false,
href: "#",
href: "/",
},
};

export const ExternalLink: Story = {
args: {
children: "リンクテキスト",
isOpenInNew: true,
href: "#",
href: "https://example.com",
},
};

Expand All @@ -45,7 +46,7 @@ export const ExternalLink: Story = {
export const AsChild: Story = {
render: () => (
<Link asChild>
<a href="#">next/link 等に置き換え可能</a>
<NextLink href="/">next/link 等に置き換え可能</NextLink>
</Link>
),
};
Expand All @@ -71,6 +72,6 @@ export const CustomTypography: Story = {
args: {
children: "カスタムタイポグラフィ",
className: "character-4-bold-pro",
href: "#",
href: "/",
},
};
52 changes: 52 additions & 0 deletions src/components/ui/modal/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,55 @@ export const EnabledOverlayClickToClose: Story = {
);
},
};

/**
* 開閉モーション(オーバーレイフェード+パネル fade/zoom)の確認用。
* en: For verifying open/close motion (overlay fade + panel fade/zoom).
*/
export const MotionPreview: Story = {
parameters: {
layout: "fullscreen",
docs: {
description: {
story:
"全画面レイアウトでスクリムとパネルの動きを確認する。**開く**:トリガーボタン。**閉じる**:×/キャンセル/保存/Esc。オーバーレイクリックは既定で閉じない(仕様確認用)。オーバーレイはフェード(Open 180ms / Close 160ms)、コンテンツは opacity + translateY + scale(Open 240ms / delay 20ms、Close 200ms)で出入りする。\n\nen: Use fullscreen to judge scrim and panel motion. Trigger opens; close via ×, footer buttons, or Esc. Overlay fades (open 180ms, close 160ms). Content enters/leaves with opacity + translateY + scale (open 240ms with 20ms delay, close 200ms).",
},
},
},
render: () => {
const [open, setOpen] = useState(false);
return (
<div className="flex min-h-screen items-center justify-center p-8">
<Modal open={open} onOpenChange={setOpen}>
<ModalTrigger asChild>
<Button>モーダルを開く(モーション確認)</Button>
</ModalTrigger>
<ModalContent>
<ModalHeader>
<ModalTitle>モーション確認</ModalTitle>
<ModalClose />
</ModalHeader>
<ModalBody>
<p className="text-pretty">
開閉を繰り返して、オーバーレイのフェードとパネルのスケール/不透明度の同期を確認してください。
</p>
</ModalBody>
<ModalFooter>
<Button
size="sm"
theme="neutral"
variant="ghost"
onClick={() => setOpen(false)}
>
キャンセル
</Button>
<Button size="sm" onClick={() => setOpen(false)}>
保存
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</div>
);
},
};
43 changes: 31 additions & 12 deletions src/components/ui/modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,13 @@ function ModalOverlay({
<DialogPrimitive.Overlay
data-slot="modal-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
[
"fixed inset-0 z-50 bg-black/50",
"data-[state=open]:animate-[sparkle-overlay-in_180ms_ease-out_0ms_both]",
"data-[state=closed]:animate-[sparkle-overlay-out_160ms_ease-in_0ms_both]",
"motion-reduce:data-[state=open]:animate-[sparkle-fade-in_120ms_ease-out_0ms_both]",
"motion-reduce:data-[state=closed]:animate-[sparkle-fade-out_120ms_ease-in_0ms_both]",
].join(" "),
className
)}
{...props}
Expand Down Expand Up @@ -199,18 +205,31 @@ function ModalContent({
return (
<ModalPortal data-slot="modal-portal">
<ModalOverlay />
<DialogPrimitive.Content
data-slot="modal-content"
className={cn(
sizeClass,
"z-50 flex flex-col gap-0 w-full max-h-[calc(100vh-80px)] bg-white border-divider-low py-4 rounded-modal data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] shadow-lg duration-200",
className
)}
onInteractOutside={handleInteractOutside}
{...props}
<div
data-slot="modal-positioner"
className="fixed inset-0 z-50 flex items-center justify-center p-10 pointer-events-none"
>
{children}
</DialogPrimitive.Content>
<DialogPrimitive.Content
data-slot="modal-content"
className={cn(
sizeClass,
[
"pointer-events-auto",
"flex flex-col gap-0 w-full max-h-[calc(100vh-80px)]",
"bg-white border-divider-low py-4 rounded-modal shadow-lg",
"data-[state=open]:animate-[sparkle-modal-in_240ms_cubic-bezier(0.16,1,0.3,1)_20ms_both]",
"data-[state=closed]:animate-[sparkle-modal-out_200ms_cubic-bezier(0.32,0,0.67,0)_0ms_both]",
"motion-reduce:data-[state=open]:animate-[sparkle-fade-in_120ms_ease-out_0ms_both]",
"motion-reduce:data-[state=closed]:animate-[sparkle-fade-out_120ms_ease-in_0ms_both]",
].join(" "),
className
)}
onInteractOutside={handleInteractOutside}
{...props}
>
{children}
</DialogPrimitive.Content>
</div>
</ModalPortal>
);
}
Expand Down
Loading