sparkle-design 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +5 -0
- package/README.en.md +275 -0
- package/README.md +328 -0
- package/dist/components/ui/badge/index.d.ts +67 -0
- package/dist/components/ui/badge/index.figma.d.ts +1 -0
- package/dist/components/ui/badge/index.figma.js +28 -0
- package/dist/components/ui/badge/index.js +129 -0
- package/dist/components/ui/breadcrumb/index.d.ts +70 -0
- package/dist/components/ui/breadcrumb/index.figma.d.ts +1 -0
- package/dist/components/ui/breadcrumb/index.figma.js +28 -0
- package/dist/components/ui/breadcrumb/index.js +96 -0
- package/dist/components/ui/button/index.d.ts +145 -0
- package/dist/components/ui/button/index.figma.d.ts +1 -0
- package/dist/components/ui/button/index.figma.js +59 -0
- package/dist/components/ui/button/index.js +375 -0
- package/dist/components/ui/card/index.d.ts +193 -0
- package/dist/components/ui/card/index.figma.d.ts +1 -0
- package/dist/components/ui/card/index.figma.js +28 -0
- package/dist/components/ui/card/index.js +219 -0
- package/dist/components/ui/checkbox/index.d.ts +62 -0
- package/dist/components/ui/checkbox/index.figma.d.ts +1 -0
- package/dist/components/ui/checkbox/index.figma.js +34 -0
- package/dist/components/ui/checkbox/index.js +192 -0
- package/dist/components/ui/dialog/index.d.ts +106 -0
- package/dist/components/ui/dialog/index.figma.d.ts +1 -0
- package/dist/components/ui/dialog/index.figma.js +21 -0
- package/dist/components/ui/dialog/index.js +157 -0
- package/dist/components/ui/divider/index.d.ts +44 -0
- package/dist/components/ui/divider/index.figma.d.ts +1 -0
- package/dist/components/ui/divider/index.figma.js +39 -0
- package/dist/components/ui/divider/index.js +81 -0
- package/dist/components/ui/form/index.d.ts +171 -0
- package/dist/components/ui/form/index.figma.d.ts +1 -0
- package/dist/components/ui/form/index.figma.js +129 -0
- package/dist/components/ui/form/index.js +214 -0
- package/dist/components/ui/form/label.d.ts +4 -0
- package/dist/components/ui/form/label.js +20 -0
- package/dist/components/ui/icon/index.d.ts +71 -0
- package/dist/components/ui/icon/index.figma.d.ts +1 -0
- package/dist/components/ui/icon/index.figma.js +1858 -0
- package/dist/components/ui/icon/index.js +57 -0
- package/dist/components/ui/icon-button/index.d.ts +77 -0
- package/dist/components/ui/icon-button/index.figma.d.ts +1 -0
- package/dist/components/ui/icon-button/index.figma.js +43 -0
- package/dist/components/ui/icon-button/index.js +341 -0
- package/dist/components/ui/inline-message/index.d.ts +83 -0
- package/dist/components/ui/inline-message/index.figma.d.ts +1 -0
- package/dist/components/ui/inline-message/index.figma.js +26 -0
- package/dist/components/ui/inline-message/index.js +154 -0
- package/dist/components/ui/input/index.d.ts +118 -0
- package/dist/components/ui/input/index.figma.d.ts +1 -0
- package/dist/components/ui/input/index.figma.js +36 -0
- package/dist/components/ui/input/index.js +256 -0
- package/dist/components/ui/input-password/index.d.ts +27 -0
- package/dist/components/ui/input-password/index.figma.d.ts +1 -0
- package/dist/components/ui/input-password/index.figma.js +36 -0
- package/dist/components/ui/input-password/index.js +35 -0
- package/dist/components/ui/link/index.d.ts +68 -0
- package/dist/components/ui/link/index.figma.d.ts +1 -0
- package/dist/components/ui/link/index.figma.js +22 -0
- package/dist/components/ui/link/index.js +92 -0
- package/dist/components/ui/modal/index.d.ts +83 -0
- package/dist/components/ui/modal/index.figma.d.ts +1 -0
- package/dist/components/ui/modal/index.figma.js +61 -0
- package/dist/components/ui/modal/index.js +143 -0
- package/dist/components/ui/overlay/index.d.ts +19 -0
- package/dist/components/ui/overlay/index.figma.d.ts +1 -0
- package/dist/components/ui/overlay/index.figma.js +14 -0
- package/dist/components/ui/overlay/index.js +39 -0
- package/dist/components/ui/radio/index.d.ts +94 -0
- package/dist/components/ui/radio/index.figma.d.ts +1 -0
- package/dist/components/ui/radio/index.figma.js +63 -0
- package/dist/components/ui/radio/index.js +204 -0
- package/dist/components/ui/select/index.d.ts +175 -0
- package/dist/components/ui/select/index.figma.d.ts +1 -0
- package/dist/components/ui/select/index.figma.js +30 -0
- package/dist/components/ui/select/index.js +281 -0
- package/dist/components/ui/skeleton/index.d.ts +21 -0
- package/dist/components/ui/skeleton/index.figma.d.ts +1 -0
- package/dist/components/ui/skeleton/index.figma.js +14 -0
- package/dist/components/ui/skeleton/index.js +32 -0
- package/dist/components/ui/slider/index.d.ts +75 -0
- package/dist/components/ui/slider/index.figma.d.ts +1 -0
- package/dist/components/ui/slider/index.figma.js +28 -0
- package/dist/components/ui/slider/index.js +113 -0
- package/dist/components/ui/slider/utils.d.ts +16 -0
- package/dist/components/ui/slider/utils.js +56 -0
- package/dist/components/ui/spinner/index.d.ts +42 -0
- package/dist/components/ui/spinner/index.figma.d.ts +1 -0
- package/dist/components/ui/spinner/index.figma.js +16 -0
- package/dist/components/ui/spinner/index.js +51 -0
- package/dist/components/ui/switch/index.d.ts +46 -0
- package/dist/components/ui/switch/index.figma.d.ts +1 -0
- package/dist/components/ui/switch/index.figma.js +27 -0
- package/dist/components/ui/switch/index.js +75 -0
- package/dist/components/ui/tabs/index.d.ts +53 -0
- package/dist/components/ui/tabs/index.figma.d.ts +1 -0
- package/dist/components/ui/tabs/index.figma.js +55 -0
- package/dist/components/ui/tabs/index.js +164 -0
- package/dist/components/ui/tag/index.d.ts +50 -0
- package/dist/components/ui/tag/index.figma.d.ts +1 -0
- package/dist/components/ui/tag/index.figma.js +32 -0
- package/dist/components/ui/tag/index.js +177 -0
- package/dist/components/ui/textarea/index.d.ts +49 -0
- package/dist/components/ui/textarea/index.figma.d.ts +1 -0
- package/dist/components/ui/textarea/index.figma.js +27 -0
- package/dist/components/ui/textarea/index.js +94 -0
- package/dist/components/ui/toast/index.d.ts +60 -0
- package/dist/components/ui/toast/index.figma.d.ts +1 -0
- package/dist/components/ui/toast/index.figma.js +26 -0
- package/dist/components/ui/toast/index.js +57 -0
- package/dist/components/ui/tooltip/index.d.ts +52 -0
- package/dist/components/ui/tooltip/index.figma.d.ts +1 -0
- package/dist/components/ui/tooltip/index.figma.js +23 -0
- package/dist/components/ui/tooltip/index.js +65 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +27 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/test/helpers.d.ts +56 -0
- package/dist/test/helpers.js +182 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +38 -0
- package/package.json +253 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
/**
|
|
14
|
+
* Copyright 2026 Goodpatch Inc.
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
*/
|
|
17
|
+
import * as React from "react";
|
|
18
|
+
import { cn } from "../../../lib/utils.js";
|
|
19
|
+
/**
|
|
20
|
+
* **概要 / Overview**
|
|
21
|
+
*
|
|
22
|
+
* - アイコンはテキスト情報を視覚表現でユーザーに提示するために使用するコンポーネントです。
|
|
23
|
+
* - en: The Icon component is used to present textual information to users through visual representation.
|
|
24
|
+
*
|
|
25
|
+
* **アンチパターン / Anti-patterns**
|
|
26
|
+
*
|
|
27
|
+
* - `material-symbols-rounded` を `span` に直書きせず、`Icon` を使ってください。
|
|
28
|
+
* en: Use `Icon` instead of writing `material-symbols-rounded` directly on a span.
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* // ✅ Correct
|
|
32
|
+
* <Icon icon="content_copy" size={4} />
|
|
33
|
+
*
|
|
34
|
+
* // ❌ Wrong - className を直書きしない
|
|
35
|
+
* <span className="material-symbols-rounded text-sm">content_copy</span>
|
|
36
|
+
* ```
|
|
37
|
+
|
|
38
|
+
* **使用例 / Usage Example**
|
|
39
|
+
*
|
|
40
|
+
* ```tsx
|
|
41
|
+
* <Icon icon="check" size={6} fill={true} />
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @param {IconProps} props
|
|
45
|
+
*/
|
|
46
|
+
export const Icon = React.forwardRef((_a, ref) => {
|
|
47
|
+
var { className, icon, size = 3, fill = false } = _a, props = __rest(_a, ["className", "icon", "size", "fill"]);
|
|
48
|
+
// 既存のclassNameにicon-X-fill-0の形式が含まれているかチェック
|
|
49
|
+
const hasIconTypographyClass = className === null || className === void 0 ? void 0 : className.match(/icon-\d+-fill-\d+/);
|
|
50
|
+
// サイズクラスの生成(既存のサイズクラスがない場合のみ)
|
|
51
|
+
const fillValue = fill ? 1 : 0;
|
|
52
|
+
const iconTypographyClass = hasIconTypographyClass
|
|
53
|
+
? ""
|
|
54
|
+
: `icon-${size}-fill-${fillValue}`;
|
|
55
|
+
return (_jsx("span", Object.assign({ ref: ref, className: cn(iconTypographyClass, "select-none", className), "aria-hidden": "true" }, props, { children: icon })));
|
|
56
|
+
});
|
|
57
|
+
Icon.displayName = "Icon";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const iconButtonVariants: (props?: ({
|
|
4
|
+
variant?: "solid" | "outline" | "ghost" | null | undefined;
|
|
5
|
+
size?: "xs" | "sm" | "md" | "lg" | null | undefined;
|
|
6
|
+
theme?: "primary" | "neutral" | "negative" | null | undefined;
|
|
7
|
+
isLoading?: boolean | null | undefined;
|
|
8
|
+
isDisabled?: boolean | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
type IconButtonVariants = VariantProps<typeof iconButtonVariants>;
|
|
11
|
+
export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
12
|
+
/**
|
|
13
|
+
* アイコンボタンのバリエーション
|
|
14
|
+
* en: Variation of the icon button
|
|
15
|
+
*/
|
|
16
|
+
variant?: IconButtonVariants["variant"];
|
|
17
|
+
/**
|
|
18
|
+
* アイコンボタンのサイズ
|
|
19
|
+
* en: Size of the icon button
|
|
20
|
+
*/
|
|
21
|
+
size?: IconButtonVariants["size"];
|
|
22
|
+
/**
|
|
23
|
+
* アイコンボタンのテーマ
|
|
24
|
+
* en: Theme of the icon button
|
|
25
|
+
*/
|
|
26
|
+
theme?: IconButtonVariants["theme"];
|
|
27
|
+
/**
|
|
28
|
+
* ボタンを別コンポーネントの子としてレンダリングするか
|
|
29
|
+
* en: Whether to render the button as a child component
|
|
30
|
+
*/
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* 表示するアイコン名
|
|
34
|
+
* en: Icon name to display
|
|
35
|
+
*/
|
|
36
|
+
icon: string;
|
|
37
|
+
/**
|
|
38
|
+
* ローディング状態かどうか
|
|
39
|
+
* en: Whether the button is in a loading state
|
|
40
|
+
*/
|
|
41
|
+
isLoading?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* ボタンを無効化するかどうか
|
|
44
|
+
* en: Whether the button is disabled
|
|
45
|
+
*/
|
|
46
|
+
isDisabled?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* **概要 / Overview**
|
|
50
|
+
*
|
|
51
|
+
* - アイコンボタンはフォームの送信、ダイアログの展開、アクションのキャンセル、削除の実行など、アクションやイベントのトリガーとして使用するコンポーネントです。
|
|
52
|
+
* - en: The IconButton component is used as a trigger for actions and events such as form submission, dialog expansion, action cancellation, and deletion execution.
|
|
53
|
+
*
|
|
54
|
+
* **使用例 / Usage Example**
|
|
55
|
+
*
|
|
56
|
+
* ```tsx
|
|
57
|
+
* <IconButton variant="solid" size="md" theme="primary" icon="edit" />
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* **アンチパターン / Anti-patterns**
|
|
61
|
+
*
|
|
62
|
+
* - アイコンだけのアクションでは `Button` + `prefixIcon` ではなく `IconButton` を使ってください。
|
|
63
|
+
* en: Use `IconButton` for icon-only actions instead of `Button` with `prefixIcon`.
|
|
64
|
+
*
|
|
65
|
+
* ```tsx
|
|
66
|
+
* // ✅ Correct
|
|
67
|
+
* <IconButton icon="content_copy" aria-label="コピー" />
|
|
68
|
+
*
|
|
69
|
+
* // ❌ Wrong - Icon-only action を Button で表現しない
|
|
70
|
+
* <Button prefixIcon="content_copy" aria-label="コピー" />
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
|
|
74
|
+
* @param {IconButtonProps} props
|
|
75
|
+
*/
|
|
76
|
+
declare const IconButton: React.ForwardRefExoticComponent<IconButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
77
|
+
export { IconButton, iconButtonVariants };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import figma from "@figma/code-connect";
|
|
3
|
+
import { IconButton } from "./index.js";
|
|
4
|
+
/**
|
|
5
|
+
* -- This file was auto-generated by Code Connect --
|
|
6
|
+
* `props` includes a mapping from your code props to Figma properties.
|
|
7
|
+
* You should check this is correct, and update the `example` function
|
|
8
|
+
* to return the code example you'd like to see in Figma
|
|
9
|
+
*/
|
|
10
|
+
figma.connect(IconButton, "https://www.figma.com/design/7alBZXZf65YgcII41TWT0r/Sparkle-Design?node-id=25%3A906", {
|
|
11
|
+
props: {
|
|
12
|
+
// These props were automatically mapped based on your linked code:
|
|
13
|
+
isLoading: figma.enum("state", {
|
|
14
|
+
loading: true,
|
|
15
|
+
}),
|
|
16
|
+
isDisabled: figma.enum("state", {
|
|
17
|
+
disabled: true,
|
|
18
|
+
}),
|
|
19
|
+
disabled: figma.enum("state", {
|
|
20
|
+
disabled: true,
|
|
21
|
+
}),
|
|
22
|
+
variant: figma.enum("variant", {
|
|
23
|
+
solid: "solid",
|
|
24
|
+
outline: "outline",
|
|
25
|
+
ghost: "ghost",
|
|
26
|
+
}),
|
|
27
|
+
size: figma.enum("size", {
|
|
28
|
+
xs: "xs",
|
|
29
|
+
sm: "sm",
|
|
30
|
+
md: "md",
|
|
31
|
+
lg: "lg",
|
|
32
|
+
}),
|
|
33
|
+
theme: figma.enum("theme", {
|
|
34
|
+
primary: "primary",
|
|
35
|
+
negative: "negative",
|
|
36
|
+
neutral: "neutral",
|
|
37
|
+
}),
|
|
38
|
+
// No matching props could be found for these Figma properties:
|
|
39
|
+
icon: figma.instance("icon").getProps(),
|
|
40
|
+
// "isFocused": figma.boolean('isFocused')
|
|
41
|
+
},
|
|
42
|
+
example: props => (_jsx(IconButton, { icon: props.icon.icon, isLoading: props.isLoading, isDisabled: props.isDisabled, disabled: props.disabled, variant: props.variant, size: props.size, theme: props.theme })),
|
|
43
|
+
});
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Goodpatch Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
"use client";
|
|
6
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
7
|
+
var t = {};
|
|
8
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
9
|
+
t[p] = s[p];
|
|
10
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
11
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
12
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
13
|
+
t[p[i]] = s[p[i]];
|
|
14
|
+
}
|
|
15
|
+
return t;
|
|
16
|
+
};
|
|
17
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { Slot as SlotPrimitive } from "radix-ui";
|
|
20
|
+
import { cva } from "class-variance-authority";
|
|
21
|
+
import { cn } from "../../../lib/utils.js";
|
|
22
|
+
import { Icon } from "../../../components/ui/icon/index.js";
|
|
23
|
+
import { Spinner } from "../../../components/ui/spinner/index.js";
|
|
24
|
+
const iconButtonVariants = cva([
|
|
25
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-action",
|
|
26
|
+
"ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-[var(--color-ring-normal)] focus-visible:ring-offset-2",
|
|
27
|
+
"relative cursor-pointer",
|
|
28
|
+
].join(" "), {
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
solid: "border",
|
|
32
|
+
outline: "border",
|
|
33
|
+
ghost: "",
|
|
34
|
+
},
|
|
35
|
+
size: {
|
|
36
|
+
xs: "w-6 h-6 p-1",
|
|
37
|
+
sm: "w-8 h-8 p-1.5",
|
|
38
|
+
md: "w-10 h-10 p-2",
|
|
39
|
+
lg: "w-12 h-12 p-2",
|
|
40
|
+
},
|
|
41
|
+
theme: {
|
|
42
|
+
primary: "",
|
|
43
|
+
neutral: "",
|
|
44
|
+
negative: "",
|
|
45
|
+
},
|
|
46
|
+
isLoading: {
|
|
47
|
+
true: "cursor-not-allowed",
|
|
48
|
+
false: "",
|
|
49
|
+
},
|
|
50
|
+
isDisabled: {
|
|
51
|
+
true: "cursor-not-allowed",
|
|
52
|
+
false: "",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
compoundVariants: [
|
|
56
|
+
// Solid Primary バリアント
|
|
57
|
+
{
|
|
58
|
+
variant: "solid",
|
|
59
|
+
theme: "primary",
|
|
60
|
+
isLoading: false,
|
|
61
|
+
isDisabled: false,
|
|
62
|
+
className: [
|
|
63
|
+
"bg-primary-500 text-white border-primary-600",
|
|
64
|
+
"hover:bg-primary-600 hover:border-primary-700",
|
|
65
|
+
"active:bg-primary-700 active:border-primary-800",
|
|
66
|
+
].join(" "),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
variant: "solid",
|
|
70
|
+
theme: "primary",
|
|
71
|
+
isLoading: true,
|
|
72
|
+
isDisabled: false,
|
|
73
|
+
className: "bg-primary-500 text-white border-primary-600",
|
|
74
|
+
},
|
|
75
|
+
// Solid Neutral バリアント
|
|
76
|
+
{
|
|
77
|
+
variant: "solid",
|
|
78
|
+
theme: "neutral",
|
|
79
|
+
isLoading: false,
|
|
80
|
+
isDisabled: false,
|
|
81
|
+
className: [
|
|
82
|
+
"bg-[var(--color-black-alpha-600)] text-white border-neutral-600",
|
|
83
|
+
"hover:bg-[var(--color-black-alpha-700)] hover:border-neutral-700",
|
|
84
|
+
"active:bg-[var(--color-black-alpha-800)] active:border-neutral-800",
|
|
85
|
+
].join(" "),
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
variant: "solid",
|
|
89
|
+
theme: "neutral",
|
|
90
|
+
isLoading: true,
|
|
91
|
+
isDisabled: false,
|
|
92
|
+
className: "bg-[var(--color-black-alpha-600)] text-white border-neutral-600",
|
|
93
|
+
},
|
|
94
|
+
// Solid Negative バリアント
|
|
95
|
+
{
|
|
96
|
+
variant: "solid",
|
|
97
|
+
theme: "negative",
|
|
98
|
+
isLoading: false,
|
|
99
|
+
isDisabled: false,
|
|
100
|
+
className: [
|
|
101
|
+
"bg-negative-500 text-white border-negative-600",
|
|
102
|
+
"hover:bg-negative-600 hover:border-negative-700",
|
|
103
|
+
"active:bg-negative-700 active:border-negative-800",
|
|
104
|
+
].join(" "),
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
variant: "solid",
|
|
108
|
+
theme: "negative",
|
|
109
|
+
isLoading: true,
|
|
110
|
+
isDisabled: false,
|
|
111
|
+
className: "bg-negative-500 text-white border-negative-600",
|
|
112
|
+
},
|
|
113
|
+
// Outline Primary バリアント
|
|
114
|
+
{
|
|
115
|
+
variant: "outline",
|
|
116
|
+
theme: "primary",
|
|
117
|
+
isLoading: false,
|
|
118
|
+
className: [
|
|
119
|
+
"bg-white text-primary-500 border-primary-300",
|
|
120
|
+
"hover:bg-primary-50",
|
|
121
|
+
"active:bg-primary-100 active:border-primary-400 active:text-primary-600",
|
|
122
|
+
].join(" "),
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
variant: "outline",
|
|
126
|
+
theme: "primary",
|
|
127
|
+
isLoading: true,
|
|
128
|
+
isDisabled: false,
|
|
129
|
+
className: "bg-white text-primary-500 border-primary-300",
|
|
130
|
+
},
|
|
131
|
+
// Outline Neutral バリアント
|
|
132
|
+
{
|
|
133
|
+
variant: "outline",
|
|
134
|
+
theme: "neutral",
|
|
135
|
+
isLoading: false,
|
|
136
|
+
className: [
|
|
137
|
+
"bg-white text-neutral-700 border-neutral-300",
|
|
138
|
+
"hover:bg-[var(--color-black-alpha-50)]",
|
|
139
|
+
"active:bg-[var(--color-black-alpha-100)]",
|
|
140
|
+
].join(" "),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
variant: "outline",
|
|
144
|
+
theme: "neutral",
|
|
145
|
+
isLoading: true,
|
|
146
|
+
isDisabled: false,
|
|
147
|
+
className: "bg-white text-neutral-700 border-neutral-300",
|
|
148
|
+
},
|
|
149
|
+
// Outline Negative バリアント
|
|
150
|
+
{
|
|
151
|
+
variant: "outline",
|
|
152
|
+
theme: "negative",
|
|
153
|
+
isLoading: false,
|
|
154
|
+
isDisabled: false,
|
|
155
|
+
className: [
|
|
156
|
+
"bg-white text-negative-500 border-negative-300",
|
|
157
|
+
"hover:bg-negative-50",
|
|
158
|
+
"active:bg-negative-100 active:border-negative-400 active:text-negative-600",
|
|
159
|
+
].join(" "),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
variant: "outline",
|
|
163
|
+
theme: "negative",
|
|
164
|
+
isLoading: true,
|
|
165
|
+
isDisabled: false,
|
|
166
|
+
className: "bg-white text-negative-500 border-negative-300",
|
|
167
|
+
},
|
|
168
|
+
// Ghost Primary バリアント
|
|
169
|
+
{
|
|
170
|
+
variant: "ghost",
|
|
171
|
+
theme: "primary",
|
|
172
|
+
isLoading: false,
|
|
173
|
+
isDisabled: false,
|
|
174
|
+
className: "text-primary-500 hover:bg-primary-50 active:bg-primary-100 active:text-primary-600",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
variant: "ghost",
|
|
178
|
+
theme: "primary",
|
|
179
|
+
isLoading: true,
|
|
180
|
+
isDisabled: false,
|
|
181
|
+
className: "text-primary-500",
|
|
182
|
+
},
|
|
183
|
+
// Ghost neutral バリアント
|
|
184
|
+
{
|
|
185
|
+
variant: "ghost",
|
|
186
|
+
theme: "neutral",
|
|
187
|
+
isLoading: false,
|
|
188
|
+
isDisabled: false,
|
|
189
|
+
className: "text-neutral-700 hover:bg-[var(--color-black-alpha-50)] active:bg-[var(--color-black-alpha-100)]",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
variant: "ghost",
|
|
193
|
+
theme: "neutral",
|
|
194
|
+
isLoading: true,
|
|
195
|
+
isDisabled: false,
|
|
196
|
+
className: "text-neutral-700",
|
|
197
|
+
},
|
|
198
|
+
// Ghost Negative バリアント
|
|
199
|
+
{
|
|
200
|
+
variant: "ghost",
|
|
201
|
+
theme: "negative",
|
|
202
|
+
isLoading: false,
|
|
203
|
+
isDisabled: false,
|
|
204
|
+
className: "text-negative-500 hover:bg-negative-50 active:bg-negative-100 active:text-negative-600",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
variant: "ghost",
|
|
208
|
+
theme: "negative",
|
|
209
|
+
isLoading: true,
|
|
210
|
+
isDisabled: false,
|
|
211
|
+
className: "text-negative-500",
|
|
212
|
+
},
|
|
213
|
+
// Disabled styles for all variants
|
|
214
|
+
{
|
|
215
|
+
variant: "solid",
|
|
216
|
+
theme: "primary",
|
|
217
|
+
isDisabled: true,
|
|
218
|
+
className: "disabled:bg-primary-200 disabled:text-white disabled:border-none",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
variant: "solid",
|
|
222
|
+
theme: "neutral",
|
|
223
|
+
isDisabled: true,
|
|
224
|
+
className: "disabled:bg-[var(--color-black-alpha-200)] disabled:text-white disabled:border-none",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
variant: "solid",
|
|
228
|
+
theme: "negative",
|
|
229
|
+
isDisabled: true,
|
|
230
|
+
className: "disabled:bg-negative-200 disabled:text-white disabled:border-none",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
variant: "outline",
|
|
234
|
+
theme: "primary",
|
|
235
|
+
isDisabled: true,
|
|
236
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-primary-200 disabled:border-primary-100",
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
variant: "outline",
|
|
240
|
+
theme: "neutral",
|
|
241
|
+
isDisabled: true,
|
|
242
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-neutral-200 disabled:border-neutral-100",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
variant: "outline",
|
|
246
|
+
theme: "negative",
|
|
247
|
+
isDisabled: true,
|
|
248
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-negative-200 disabled:border-negative-100",
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
variant: "ghost",
|
|
252
|
+
theme: "primary",
|
|
253
|
+
isDisabled: true,
|
|
254
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-primary-200",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
variant: "ghost",
|
|
258
|
+
theme: "neutral",
|
|
259
|
+
isDisabled: true,
|
|
260
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-neutral-200",
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
variant: "ghost",
|
|
264
|
+
theme: "negative",
|
|
265
|
+
isDisabled: true,
|
|
266
|
+
className: "disabled:bg-[var(--color-white-alpha-700)] disabled:text-negative-200",
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
defaultVariants: {
|
|
270
|
+
variant: "solid",
|
|
271
|
+
size: "md",
|
|
272
|
+
theme: "primary",
|
|
273
|
+
isLoading: false,
|
|
274
|
+
isDisabled: false,
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* **概要 / Overview**
|
|
279
|
+
*
|
|
280
|
+
* - アイコンボタンはフォームの送信、ダイアログの展開、アクションのキャンセル、削除の実行など、アクションやイベントのトリガーとして使用するコンポーネントです。
|
|
281
|
+
* - en: The IconButton component is used as a trigger for actions and events such as form submission, dialog expansion, action cancellation, and deletion execution.
|
|
282
|
+
*
|
|
283
|
+
* **使用例 / Usage Example**
|
|
284
|
+
*
|
|
285
|
+
* ```tsx
|
|
286
|
+
* <IconButton variant="solid" size="md" theme="primary" icon="edit" />
|
|
287
|
+
* ```
|
|
288
|
+
*
|
|
289
|
+
* **アンチパターン / Anti-patterns**
|
|
290
|
+
*
|
|
291
|
+
* - アイコンだけのアクションでは `Button` + `prefixIcon` ではなく `IconButton` を使ってください。
|
|
292
|
+
* en: Use `IconButton` for icon-only actions instead of `Button` with `prefixIcon`.
|
|
293
|
+
*
|
|
294
|
+
* ```tsx
|
|
295
|
+
* // ✅ Correct
|
|
296
|
+
* <IconButton icon="content_copy" aria-label="コピー" />
|
|
297
|
+
*
|
|
298
|
+
* // ❌ Wrong - Icon-only action を Button で表現しない
|
|
299
|
+
* <Button prefixIcon="content_copy" aria-label="コピー" />
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
|
|
303
|
+
* @param {IconButtonProps} props
|
|
304
|
+
*/
|
|
305
|
+
const IconButton = React.forwardRef((_a, ref) => {
|
|
306
|
+
var { className, variant, size, theme, isLoading = false, isDisabled = false, asChild = false, disabled, icon, children } = _a, props = __rest(_a, ["className", "variant", "size", "theme", "isLoading", "isDisabled", "asChild", "disabled", "icon", "children"]);
|
|
307
|
+
// disabled状態の管理(isDisabled、disabled、またはisLoadingがtrueの場合)
|
|
308
|
+
const isIconButtonDisabled = isLoading || isDisabled || disabled;
|
|
309
|
+
// アイコンのみのボタンには aria-label が必要(WCAG 1.1.1)
|
|
310
|
+
// en: Icon-only buttons require aria-label (WCAG 1.1.1)
|
|
311
|
+
if (process.env.NODE_ENV !== "production") {
|
|
312
|
+
if (!asChild && !props["aria-label"] && !props["aria-labelledby"]) {
|
|
313
|
+
console.warn("[IconButton] アイコンのみのボタンには aria-label を指定してください(WCAG 1.1.1)。" +
|
|
314
|
+
" / Icon-only buttons require aria-label (WCAG 1.1.1).");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const Comp = asChild ? SlotPrimitive.Slot : "button";
|
|
318
|
+
// アイコンのサイズをボタンサイズに合わせて設定
|
|
319
|
+
const getIconSize = () => {
|
|
320
|
+
switch (size) {
|
|
321
|
+
case "xs":
|
|
322
|
+
return 3;
|
|
323
|
+
case "sm":
|
|
324
|
+
return 5;
|
|
325
|
+
case "lg":
|
|
326
|
+
return 7;
|
|
327
|
+
default:
|
|
328
|
+
return 6;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
return (_jsx(Comp, Object.assign({ type: "button", className: cn(iconButtonVariants({
|
|
332
|
+
variant,
|
|
333
|
+
size,
|
|
334
|
+
theme,
|
|
335
|
+
isLoading,
|
|
336
|
+
isDisabled,
|
|
337
|
+
className,
|
|
338
|
+
})), ref: ref, disabled: isIconButtonDisabled }, props, { children: isLoading ? (_jsx(_Fragment, { children: _jsx(Spinner, { size: getIconSize(), className: "text-current" }) })) : (_jsx(Icon, { icon: icon, size: getIconSize() })) })));
|
|
339
|
+
});
|
|
340
|
+
IconButton.displayName = "IconButton";
|
|
341
|
+
export { IconButton, iconButtonVariants };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 Goodpatch Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { type VariantProps } from "class-variance-authority";
|
|
7
|
+
declare const inlineMessageVariants: (props?: ({
|
|
8
|
+
status?: "negative" | "info" | "success" | "warning" | null | undefined;
|
|
9
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
10
|
+
type InlineMessageVariant = VariantProps<typeof inlineMessageVariants>;
|
|
11
|
+
export interface InlineMessageProps extends React.HTMLAttributes<HTMLDivElement>, InlineMessageVariant {
|
|
12
|
+
/**
|
|
13
|
+
* メッセージのステータス
|
|
14
|
+
* en: Status of the message
|
|
15
|
+
*/
|
|
16
|
+
status: InlineMessageVariant["status"];
|
|
17
|
+
/**
|
|
18
|
+
* 閉じる時のハンドラー
|
|
19
|
+
* en: Handler when the message is dismissed
|
|
20
|
+
*/
|
|
21
|
+
onClose?: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* 閉じるボタンを表示するかどうか(デフォルト: true)
|
|
24
|
+
* en: Whether to show close button (default: true)
|
|
25
|
+
*/
|
|
26
|
+
isCloseTrigger?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 子要素
|
|
29
|
+
* en: Child nodes
|
|
30
|
+
*/
|
|
31
|
+
children?: React.ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* **概要 / Overview**
|
|
35
|
+
*
|
|
36
|
+
* - インラインメッセージはユーザーにシステムやサービスの状態を伝えるために使用するコンポーネントです。
|
|
37
|
+
* - en: The InlineMessage component is used to convey system or service status to users.
|
|
38
|
+
*
|
|
39
|
+
* **使用例 / Usage Example**
|
|
40
|
+
*
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <InlineMessage status="info" onClose={() => console.log('closed')}>
|
|
43
|
+
* <InlineMessageTitle>情報</InlineMessageTitle>
|
|
44
|
+
* <InlineMessageDescription>
|
|
45
|
+
* これは情報メッセージです。
|
|
46
|
+
* </InlineMessageDescription>
|
|
47
|
+
* </InlineMessage>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param {InlineMessageProps} props
|
|
51
|
+
*/
|
|
52
|
+
declare const InlineMessage: React.ForwardRefExoticComponent<InlineMessageProps & React.RefAttributes<HTMLDivElement>>;
|
|
53
|
+
/**
|
|
54
|
+
* **概要 / Overview**
|
|
55
|
+
*
|
|
56
|
+
* - インラインメッセージのタイトルコンポーネントです。
|
|
57
|
+
* - en: Title component for inline messages.
|
|
58
|
+
*
|
|
59
|
+
* **使用例 / Usage Example**
|
|
60
|
+
*
|
|
61
|
+
* ```tsx
|
|
62
|
+
* <InlineMessageTitle>タイトル</InlineMessageTitle>
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @param {React.HTMLAttributes<HTMLSpanElement>} props
|
|
66
|
+
*/
|
|
67
|
+
declare const InlineMessageTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & React.RefAttributes<HTMLSpanElement>>;
|
|
68
|
+
/**
|
|
69
|
+
* **概要 / Overview**
|
|
70
|
+
*
|
|
71
|
+
* - インラインメッセージの説明文コンポーネントです。
|
|
72
|
+
* - en: Description component for inline messages.
|
|
73
|
+
*
|
|
74
|
+
* **使用例 / Usage Example**
|
|
75
|
+
*
|
|
76
|
+
* ```tsx
|
|
77
|
+
* <InlineMessageDescription>詳細な説明文</InlineMessageDescription>
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @param {React.HTMLAttributes<HTMLParagraphElement>} props
|
|
81
|
+
*/
|
|
82
|
+
declare const InlineMessageDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
|
|
83
|
+
export { InlineMessage, InlineMessageTitle, InlineMessageDescription };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import figma from "@figma/code-connect";
|
|
3
|
+
import { InlineMessage, InlineMessageDescription, InlineMessageTitle, } from "./index.js";
|
|
4
|
+
/**
|
|
5
|
+
* -- This file was auto-generated by Code Connect --
|
|
6
|
+
* `props` includes a mapping from your code props to Figma properties.
|
|
7
|
+
* You should check this is correct, and update the `example` function
|
|
8
|
+
* to return the code example you'd like to see in Figma
|
|
9
|
+
*/
|
|
10
|
+
figma.connect(InlineMessage, "https://www.figma.com/design/7alBZXZf65YgcII41TWT0r/Sparkle-Design?node-id=1266%3A14202", {
|
|
11
|
+
props: {
|
|
12
|
+
title: figma.boolean("isTitle", {
|
|
13
|
+
true: figma.string("title"),
|
|
14
|
+
false: undefined,
|
|
15
|
+
}),
|
|
16
|
+
description: figma.string("description"),
|
|
17
|
+
isCloseTrigger: figma.boolean("isCloseTrigger"),
|
|
18
|
+
status: figma.enum("status", {
|
|
19
|
+
info: "info",
|
|
20
|
+
warning: "warning",
|
|
21
|
+
negative: "negative",
|
|
22
|
+
success: "success",
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
example: props => (_jsxs(InlineMessage, { isCloseTrigger: props.isCloseTrigger, status: props.status, children: [_jsx(InlineMessageTitle, { children: props.title }), _jsx(InlineMessageDescription, { children: props.description })] })),
|
|
26
|
+
});
|