sparkle-design 2.0.0-beta.0 → 2.0.0-beta.1

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/README.en.md CHANGED
@@ -24,6 +24,25 @@ It implements [Goodpatch](https://goodpatch.com/)'s "Sparkle Design" system on t
24
24
  - 🎨 **Customizability** ... A dedicated CLI tool lets you apply the same customizations found in the Figma files. This makes it easy to spin up code for design systems built on Sparkle Design.
25
25
  - 🤖 **AI Friendly** ... Ships with skills and guard configurations for Claude Code, Cursor, and Codex. Maintain design system quality even during AI-assisted coding.
26
26
 
27
+ ## Versions, React and CLI support
28
+
29
+ | Version | React | sparkle-design-cli | Status |
30
+ |---|---|---|---|
31
+ | **2.x** | 19+ | Latest (currently beta: `npx --yes sparkle-design-cli@beta`) | Current. New features and components land here only (currently in beta: `npm install sparkle-design@beta`) |
32
+ | **1.x** | 18 (19 also works) | Latest (`npx --yes sparkle-design-cli`) | **Deprecated maintenance line.** Only bug and security fixes, plus token/style updates needed to stay compatible with the latest CLI |
33
+
34
+ 2.x receives `ref` as a regular prop (the React 19 approach) in every component, so on React 18 refs and Radix `asChild` compositions (e.g. Tooltip / Dialog triggers) don't work correctly. Use 1.x for React 18 projects (npm refuses to install 2.x into a React 18 project because of the peer dependency conflict).
35
+
36
+ ```bash
37
+ npm install sparkle-design@1
38
+ ```
39
+
40
+ Both lines use the latest CLI without pinning. When the tokens generated by the CLI change, 1.x follows, so 1.x looks the same as 2.x (only React 19-specific changes and new features stay out of 1.x).
41
+
42
+ Even if you stay on 1.x, run `migrate` to check your app's legacy token classes when the tokens generated by the CLI change.
43
+
44
+ To move from 1.x to 2.x, upgrade your project to React 19 first. `npx --yes sparkle-design-cli@beta migrate` reports how to replace legacy tokens (e.g. `text-neutral-900`) with the new ones (dry run by default; `--write` rewrites files).
45
+
27
46
  ## Quick Start
28
47
 
29
48
  ### 1. Set up
package/README.md CHANGED
@@ -24,6 +24,25 @@ shadcn/ui をベースに、[グッドパッチ](https://goodpatch.com/)のデ
24
24
  - 🎨 **カスタマイズ性** ... 専用CLIツールを利用し、Figmaファイルと同等のカスタマイズを適用することが出来ます。これによりSparkle Designをベースとしたデザインシステムのコードを素早く用意することが出来ます。
25
25
  - 🤖 **AI フレンドリー** ... Claude Code / Cursor / Codex 向けのスキルとガード設定を同梱。AI コーディングでもデザインシステムの品質を維持できます。
26
26
 
27
+ ## バージョンと React・CLI の対応
28
+
29
+ | バージョン | React | sparkle-design-cli | 状態 |
30
+ |---|---|---|---|
31
+ | **2.x** | 19 以上 | 最新(現在は beta: `npx --yes sparkle-design-cli@beta`) | 現行。新機能・新コンポーネントはこちらにだけ入ります(現在は beta: `npm install sparkle-design@beta`) |
32
+ | **1.x** | 18(19 でも可) | 最新(`npx --yes sparkle-design-cli`) | **非推奨(deprecated)のメンテナンスライン**。不具合・セキュリティの修正と、最新の CLI と噛み合わせるためのトークン・スタイルの追従だけを行います |
33
+
34
+ 2.x は全コンポーネントで `ref` を通常の props として受け取る React 19 の方式に移行しているため、React 18 では `ref` や Radix の `asChild` 経由の組み合わせ(Tooltip / Dialog のトリガーなど)が正しく動きません。React 18 のプロジェクトは 1.x をお使いください(2.x を React 18 のプロジェクトに入れると、npm では peer 依存の衝突で止まります)。
35
+
36
+ ```bash
37
+ npm install sparkle-design@1
38
+ ```
39
+
40
+ CLI はどちらのバージョンでも固定せず最新を使います。CLI が生成するトークンが変わるときは 1.x も追従するので、1.x でも見た目は 2.x と同じデザインになります(1.x に入らないのは React 19 前提の変更と新機能だけです)。
41
+
42
+ 1.x を使い続ける場合も、CLI が生成するトークンが変わったときは、アプリ側で使っている旧トークンのクラスを `migrate` で確認してください。
43
+
44
+ 1.x から 2.x へは、プロジェクトを React 19 に上げてから移行してください。旧トークン(`text-neutral-900` など)から新トークンへの置き換えは `npx --yes sparkle-design-cli@beta migrate` で確認できます(既定は変更内容の表示のみ。`--write` で書き換え)。
45
+
27
46
  ## クイックスタート
28
47
 
29
48
  ### 1. セットアップ
@@ -7,7 +7,7 @@ import { type VariantProps } from "class-variance-authority";
7
7
  declare const badgeVariants: (props?: ({
8
8
  variant?: "normal" | "emphasis" | null | undefined;
9
9
  isNumberVisible?: boolean | null | undefined;
10
- size?: "xs" | "sm" | "md" | "lg" | null | undefined;
10
+ size?: "2xs" | "xs" | "sm" | "md" | "lg" | null | undefined;
11
11
  isGapped?: boolean | null | undefined;
12
12
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
13
13
  type BadgeVariants = VariantProps<typeof badgeVariants>;
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { cva } from "class-variance-authority";
14
14
  import { cn } from "../../../lib/utils.js";
15
- const badgeVariants = cva("inline-flex items-center text-text-inverse text-center justify-center rounded-full transition-colors focus:outline-hidden focus:ring-2 focus:ring-border-ring focus:ring-offset-2", {
15
+ const badgeVariants = cva("inline-flex overflow-hidden items-center text-text-inverse text-center justify-center rounded-full transition-colors focus:outline-hidden focus:ring-2 focus:ring-border-ring focus:ring-offset-2", {
16
16
  variants: {
17
17
  variant: {
18
18
  normal: "bg-surface-primary-high-enabled",
@@ -23,7 +23,8 @@ const badgeVariants = cva("inline-flex items-center text-text-inverse text-cente
23
23
  false: "",
24
24
  },
25
25
  size: {
26
- xs: "w-2 h-2 min-w-2",
26
+ "2xs": "w-2 h-2 min-w-2",
27
+ xs: "w-3.5 h-3.5 min-w-3.5",
27
28
  sm: "w-4 h-4 min-w-4",
28
29
  md: "min-w-6 py-0.5 px-1.5 character-1-bold-mono",
29
30
  lg: "min-w-8 py-1 px-1.5 character-3-bold-mono",
@@ -37,9 +38,14 @@ const badgeVariants = cva("inline-flex items-center text-text-inverse text-cente
37
38
  // isGappedのボーダー設定
38
39
  {
39
40
  isGapped: true,
40
- size: "xs",
41
+ size: "2xs",
41
42
  class: "outline-border-inverse outline-2",
42
43
  },
44
+ {
45
+ isGapped: true,
46
+ size: "xs",
47
+ class: "outline-border-inverse outline-4",
48
+ },
43
49
  {
44
50
  isGapped: true,
45
51
  size: "sm",
@@ -108,7 +114,7 @@ function Badge(_a) {
108
114
  var { className, isNumberVisible = true, size, variant = "normal", isGapped = false, children, role = "status" } = _a, props = __rest(_a, ["className", "isNumberVisible", "size", "variant", "isGapped", "children", "role"]);
109
115
  // sm以下のサイズの場合は、文字を非表示にする
110
116
  // en: Hide text for sizes sm and below
111
- if (size === "sm" || size === "xs") {
117
+ if (size === "sm" || size === "xs" || size === "2xs") {
112
118
  isNumberVisible = false;
113
119
  }
114
120
  // childrenがない場合はisNumberVisibleがfalseの扱いにする
@@ -37,9 +37,9 @@ const buttonVariants = cva([
37
37
  ghost: "",
38
38
  },
39
39
  size: {
40
- sm: "h-8 min-w-16 px-3 py-1 character-2-bold-pro",
41
- md: "h-10 min-w-20 px-4 py-1.5 character-3-bold-pro",
42
- lg: "h-12 min-w-24 px-5 py-2 character-4-bold-pro",
40
+ sm: "h-8 min-w-16 px-3 py-1 character-1-bold-pro",
41
+ md: "h-10 min-w-20 px-4 py-1.5 character-2-bold-pro",
42
+ lg: "h-12 min-w-24 px-5 py-2 character-3-bold-pro",
43
43
  },
44
44
  theme: {
45
45
  primary: "",
@@ -368,7 +368,7 @@ function Button(_a) {
368
368
  case "sm":
369
369
  return 4;
370
370
  case "lg":
371
- return 6;
371
+ return 7;
372
372
  default:
373
373
  return 5;
374
374
  }
@@ -531,7 +531,7 @@ function Button(_a) {
531
531
  theme,
532
532
  isLoading,
533
533
  className,
534
- })), onClickCapture: handleClickCapture, onAuxClickCapture: handleAuxClickCapture, onKeyDownCapture: handleKeyDownCapture, onClick: handleClick, onKeyDown: handleKeyDown }, restProps, { children: asChild ? (slottedChildren) : (_jsxs(_Fragment, { children: [prefixIcon && (_jsx(Icon, { icon: prefixIcon, size: getIconSize(), className: cn({ "opacity-0": isLoading }) })), isLoading ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 inline-flex", children: _jsx(Spinner, { size: getIconSize(), className: "text-current" }) }), _jsx("span", { className: "opacity-0", children: children })] })) : (_jsx("span", { className: "px-1", children: children })), suffixIcon && (_jsx(Icon, { icon: suffixIcon, size: getIconSize(), className: cn({ "opacity-0": isLoading }) }))] })) })));
534
+ })), onClickCapture: handleClickCapture, onAuxClickCapture: handleAuxClickCapture, onKeyDownCapture: handleKeyDownCapture, onClick: handleClick, onKeyDown: handleKeyDown }, restProps, { children: asChild ? (slottedChildren) : (_jsxs(_Fragment, { children: [prefixIcon && (_jsx(Icon, { icon: prefixIcon, size: getIconSize(), className: cn("text-current", { "opacity-0": isLoading }) })), isLoading ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 inline-flex", children: _jsx(Spinner, { size: getIconSize(), className: "text-current" }) }), _jsx("span", { className: "opacity-0", children: children })] })) : (_jsx("span", { className: "px-1", children: children })), suffixIcon && (_jsx(Icon, { icon: suffixIcon, size: getIconSize(), className: cn("text-current", { "opacity-0": isLoading }) }))] })) })));
535
535
  }
536
536
  Button.displayName = "Button";
537
537
  export { Button, buttonVariants };
@@ -20,15 +20,17 @@ import { Checkbox as CheckboxPrimitive } from "radix-ui";
20
20
  import { cva } from "class-variance-authority";
21
21
  import { cn } from "../../../lib/utils.js";
22
22
  import { Icon } from "../../../components/ui/icon/index.js";
23
- const checkboxItemVariants = cva([
24
- "relative rounded-sm transition-colors flex items-center justify-center cursor-pointer",
23
+ const checkboxItemVariants = cva(
24
+ // 表示寸法を維持しつつ、疑似要素で横24pxの操作領域を確保。en: Keep visuals, expand hit width to 24px.
25
+ [
26
+ "relative before:absolute before:inset-y-0 before:left-1/2 before:w-6 before:-translate-x-1/2 before:content-[''] rounded-sm transition-colors flex items-center justify-center cursor-pointer",
25
27
  "focus:outline-none",
26
28
  ].join(" "), {
27
29
  variants: {
28
30
  size: {
29
- sm: "h-8 w-8",
30
- md: "h-10 w-10",
31
- lg: "h-12 w-12",
31
+ sm: "h-8 w-4",
32
+ md: "h-10 w-[18px]",
33
+ lg: "h-12 w-5",
32
34
  },
33
35
  isDisabled: {
34
36
  true: "cursor-not-allowed",
@@ -47,8 +49,8 @@ const checkboxRootVariants = cva([
47
49
  variants: {
48
50
  size: {
49
51
  sm: "h-4 w-4",
50
- md: "h-5 w-5",
51
- lg: "h-6 w-6",
52
+ md: "h-[18px] w-[18px]",
53
+ lg: "h-5 w-5",
52
54
  },
53
55
  isInvalid: {
54
56
  true: [
@@ -115,12 +117,12 @@ const checkboxLabelVariants = cva("cursor-pointer", {
115
117
  variants: {
116
118
  size: {
117
119
  sm: "character-2-regular-pro",
118
- md: "character-3-regular-pro",
119
- lg: "character-4-regular-pro",
120
+ md: "character-2-regular-pro",
121
+ lg: "character-3-regular-pro",
120
122
  },
121
123
  isDisabled: {
122
124
  true: "text-text-neutral-disabled cursor-not-allowed",
123
- false: "text-text-neutral-middle",
125
+ false: "text-text-neutral-middle group-hover/checkbox:text-text-neutral-high",
124
126
  },
125
127
  },
126
128
  defaultVariants: {
@@ -170,22 +172,22 @@ function Checkbox(_a) {
170
172
  }, [isControlled, onCheckedChange]);
171
173
  // isDisabledとdisabledの組み合わせで無効状態を管理
172
174
  const isCheckboxDisabled = isDisabled || disabled;
173
- return (_jsxs("div", { className: "flex items-center", children: [_jsx(CheckboxPrimitive.Root, Object.assign({ "data-slot": "checkbox", id: id, "aria-invalid": isInvalid || undefined, className: cn(checkboxItemVariants({ size, isDisabled: isCheckboxDisabled }), "group", className), disabled: isCheckboxDisabled, checked: checked, onCheckedChange: handleChange }, props, { children: _jsx("div", { className: cn(checkboxRootVariants({
175
+ return (_jsxs("div", { className: cn("group/checkbox flex items-center", size === "lg" ? "gap-2" : "gap-1.5"), children: [_jsx(CheckboxPrimitive.Root, Object.assign({ "data-slot": "checkbox", id: id, "aria-invalid": isInvalid || undefined, className: cn(checkboxItemVariants({ size, isDisabled: isCheckboxDisabled }), "group", className), disabled: isCheckboxDisabled, checked: checked, onCheckedChange: handleChange }, props, { children: _jsx("div", { className: cn(checkboxRootVariants({
174
176
  size,
175
177
  isInvalid,
176
178
  isDisabled: isCheckboxDisabled,
177
- })), children: _jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "flex items-center justify-center text-surface-base-0", children: _jsx(Icon, { icon: checked === "indeterminate"
179
+ })), children: _jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "flex items-center justify-center text-surface-base-0", children: _jsx(Icon, { className: "text-current", icon: checked === "indeterminate"
178
180
  ? "check_indeterminate_small"
179
181
  : "check", size: (function () {
180
182
  switch (size) {
181
183
  case "sm":
182
184
  return 3;
183
185
  case "md":
184
- return 5;
186
+ return 4;
185
187
  case "lg":
186
- return 6;
187
- default:
188
188
  return 5;
189
+ default:
190
+ return 4;
189
191
  }
190
192
  })() }) }) }) })), label && (_jsx("label", { htmlFor: id, className: cn(checkboxLabelVariants({ size, isDisabled: isCheckboxDisabled })), children: label }))] }));
191
193
  }
@@ -18,6 +18,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { AlertDialog as DialogPrimitive } from "radix-ui";
19
19
  import { cn } from "../../../lib/utils.js";
20
20
  import { Button } from "../../../components/ui/button/index.js";
21
+ import { Overlay } from "../overlay/index.js";
21
22
  import { Icon } from "../icon/index.js";
22
23
  /**
23
24
  * **概要 / Overview**
@@ -90,7 +91,7 @@ function DialogPortal(_a) {
90
91
  }
91
92
  function DialogOverlay(_a) {
92
93
  var { className } = _a, props = __rest(_a, ["className"]);
93
- return (_jsx(DialogPrimitive.Overlay, Object.assign({ "data-slot": "dialog-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", className) }, props)));
94
+ return (_jsx(DialogPrimitive.Overlay, Object.assign({}, props, { asChild: true, children: _jsx(Overlay, { "data-slot": "dialog-overlay", className: cn("z-50", className) }) })));
94
95
  }
95
96
  function DialogContent(_a) {
96
97
  var { className, children, showCloseButton = true } = _a, props = __rest(_a, ["className", "children", "showCloseButton"]);
@@ -133,7 +134,7 @@ function DialogDescription(_a) {
133
134
  */
134
135
  function DialogCancel(_a) {
135
136
  var { className, children } = _a, props = __rest(_a, ["className", "children"]);
136
- return (_jsx(DialogPrimitive.Cancel, Object.assign({ "data-slot": "dialog-cancel", asChild: true }, props, { children: _jsx(Button, { variant: "ghost", theme: "neutral", size: "sm", className: className, children: children }) })));
137
+ return (_jsx(DialogPrimitive.Cancel, Object.assign({ "data-slot": "dialog-cancel", asChild: true }, props, { children: _jsx(Button, { variant: "ghost", theme: "neutral", size: "md", className: className, children: children }) })));
137
138
  }
138
139
  /**
139
140
  * **アンチパターン / Anti-patterns**
@@ -152,6 +153,6 @@ function DialogCancel(_a) {
152
153
  */
153
154
  function DialogAction(_a) {
154
155
  var { className, children, theme = "primary", variant = "solid" } = _a, props = __rest(_a, ["className", "children", "theme", "variant"]);
155
- return (_jsx(DialogPrimitive.Action, Object.assign({ "data-slot": "dialog-action", asChild: true }, props, { children: _jsx(Button, { variant: variant, theme: theme, size: "sm", className: className, children: children }) })));
156
+ return (_jsx(DialogPrimitive.Action, Object.assign({ "data-slot": "dialog-action", asChild: true }, props, { children: _jsx(Button, { variant: variant, theme: theme, size: "md", className: className, children: children }) })));
156
157
  }
157
158
  export { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogIcon, DialogTitle, DialogTrigger, DialogCancel, DialogAction, };
@@ -219,6 +219,6 @@ function FormErrorMessage(_a) {
219
219
  if (!body) {
220
220
  return null;
221
221
  }
222
- return (_jsxs("p", Object.assign({ "data-slot": "form-message", id: formMessageId, className: cn("flex gap-1 items-center text-text-negative-enabled character-1-regular-pro", className) }, props, { children: [_jsx(Icon, { icon: "error", size: 3 }), body] })));
222
+ return (_jsxs("p", Object.assign({ "data-slot": "form-message", id: formMessageId, className: cn("flex gap-1 items-center text-text-negative-enabled character-1-regular-pro", className) }, props, { children: [_jsx(Icon, { icon: "error", size: 3, className: "text-object-negative-enabled" }), body] })));
223
223
  }
224
224
  export { useFormField, Form, FormItem, FormHeader, FormControl, FormHelperMessage, FormErrorMessage, FormField, };
@@ -4,8 +4,8 @@
4
4
  */
5
5
  import * as React from "react";
6
6
  /**
7
- * アイコンサイズのスケール値(1-12)
8
- * en: Icon size scale values (1-12)
7
+ * アイコンサイズのスケール値(1-13)
8
+ * en: Icon size scale values (1-13)
9
9
  *
10
10
  * | scale | px |
11
11
  * |-------|-----|
@@ -14,15 +14,16 @@ import * as React from "react";
14
14
  * | 3 | 16 |
15
15
  * | 4 | 18 |
16
16
  * | 5 | 20 |
17
- * | 6 | 24 |
18
- * | 7 | 28 |
19
- * | 8 | 32 |
20
- * | 9 | 36 |
21
- * | 10 | 42 |
22
- * | 11 | 48 |
23
- * | 12 | 54 |
17
+ * | 6 | 22 |
18
+ * | 7 | 24 |
19
+ * | 8 | 28 |
20
+ * | 9 | 32 |
21
+ * | 10 | 36 |
22
+ * | 11 | 42 |
23
+ * | 12 | 48 |
24
+ * | 13 | 54 |
24
25
  */
25
- export type IconSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
26
+ export type IconSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
26
27
  export interface IconProps extends React.ComponentProps<"span"> {
27
28
  /**
28
29
  * 表示するアイコン名
@@ -30,8 +31,8 @@ export interface IconProps extends React.ComponentProps<"span"> {
30
31
  */
31
32
  icon: string;
32
33
  /**
33
- * アイコンサイズ(スケール値 1-12)
34
- * en: Size of the icon (scale value 1-12)
34
+ * アイコンサイズ(スケール値 1-13)
35
+ * en: Size of the icon (scale value 1-13)
35
36
  * @see IconSize
36
37
  */
37
38
  size?: IconSize;
@@ -63,7 +64,7 @@ export interface IconProps extends React.ComponentProps<"span"> {
63
64
  * **使用例 / Usage Example**
64
65
  *
65
66
  * ```tsx
66
- * <Icon icon="check" size={6} fill={true} />
67
+ * <Icon icon="check" size={7} fill={true} />
67
68
  * ```
68
69
  *
69
70
  * @param {IconProps} props
@@ -33,7 +33,7 @@ import { cn } from "../../../lib/utils.js";
33
33
  * **使用例 / Usage Example**
34
34
  *
35
35
  * ```tsx
36
- * <Icon icon="check" size={6} fill={true} />
36
+ * <Icon icon="check" size={7} fill={true} />
37
37
  * ```
38
38
  *
39
39
  * @param {IconProps} props
@@ -52,6 +52,6 @@ export function Icon(_a) {
52
52
  // font-weight が継承されると疑似ボールド(faux bold)で太く描画されるため明示する。
53
53
  // en: Icons are unified at weight 500. Set font-weight explicitly so an inherited
54
54
  // font-weight (e.g. bold Button labels) does not trigger faux-bold rendering.
55
- className: cn(iconTypographyClass, "select-none font-medium", className), "aria-hidden": "true" }, props, { children: icon })));
55
+ className: cn(iconTypographyClass, "select-none font-medium text-object-neutral-high", className), "aria-hidden": "true" }, props, { children: icon })));
56
56
  }
57
57
  Icon.displayName = "Icon";
@@ -443,9 +443,9 @@ function IconButton(_a) {
443
443
  case "sm":
444
444
  return 5;
445
445
  case "lg":
446
- return 7;
446
+ return 8;
447
447
  default:
448
- return 6;
448
+ return 7;
449
449
  }
450
450
  };
451
451
  const { onClick, onKeyDown, onClickCapture, onKeyDownCapture, onAuxClickCapture, type, form, formAction, formEncType, formMethod, formNoValidate, formTarget, value, popoverTarget, popoverTargetAction, "aria-disabled": ariaDisabled } = props, restProps = __rest(props, ["onClick", "onKeyDown", "onClickCapture", "onKeyDownCapture", "onAuxClickCapture", "type", "form", "formAction", "formEncType", "formMethod", "formNoValidate", "formTarget", "value", "popoverTarget", "popoverTargetAction", "aria-disabled"]);
@@ -553,7 +553,7 @@ function IconButton(_a) {
553
553
  // aria-disabled as well.
554
554
  isDisabled: Boolean(isDisabled || disabled) || isSoftDisabled,
555
555
  className,
556
- })), disabled: canUseButtonProps ? isIconButtonDisabled : undefined, onClickCapture: handleClickCapture, onAuxClickCapture: handleAuxClickCapture, onKeyDownCapture: handleKeyDownCapture, onClick: handleClick, onKeyDown: handleKeyDown }, restProps, { children: [asChild && (_jsx(SlotPrimitive.Slottable, { children: slottedChildren })), isLoading ? (_jsx(Spinner, { size: getIconSize(), className: "text-current" })) : (_jsx(Icon, { icon: icon, size: getIconSize() }))] })));
556
+ })), disabled: canUseButtonProps ? isIconButtonDisabled : undefined, onClickCapture: handleClickCapture, onAuxClickCapture: handleAuxClickCapture, onKeyDownCapture: handleKeyDownCapture, onClick: handleClick, onKeyDown: handleKeyDown }, restProps, { children: [asChild && (_jsx(SlotPrimitive.Slottable, { children: slottedChildren })), isLoading ? (_jsx(Spinner, { size: getIconSize(), className: "text-current" })) : (_jsx(Icon, { icon: icon, size: getIconSize(), className: "text-current" }))] })));
557
557
  }
558
558
  IconButton.displayName = "IconButton";
559
559
  export { IconButton, iconButtonVariants };
@@ -94,7 +94,7 @@ function InlineMessage(_a) {
94
94
  const colorClass = status
95
95
  ? statusColorClasses[status]
96
96
  : statusColorClasses.info;
97
- return (_jsx(InlineMessageContext.Provider, { value: contextValue, children: _jsxs("div", Object.assign({ ref: ref, role: "alert", "aria-labelledby": hasTitle ? titleId : undefined, "aria-describedby": hasDesc ? descId : undefined, className: cn(inlineMessageVariants({ status }), className) }, props, { children: [_jsx("span", { className: "inline-flex p-1 items-center justify-center", "aria-hidden": "true", children: _jsx(Icon, { icon: statusIcon, size: 6, fill: false, className: cn(colorClass) }) }), _jsx("div", { className: "flex flex-col flex-1 min-h-8", children: children }), isCloseTrigger && onClose && (_jsx(IconButton, { icon: "close", size: "sm", variant: "ghost", theme: "neutral", onClick: onClose, "aria-label": "\u9589\u3058\u308B", className: "shrink-0" }))] })) }));
97
+ return (_jsx(InlineMessageContext.Provider, { value: contextValue, children: _jsxs("div", Object.assign({ ref: ref, role: "alert", "aria-labelledby": hasTitle ? titleId : undefined, "aria-describedby": hasDesc ? descId : undefined, className: cn(inlineMessageVariants({ status }), className) }, props, { children: [_jsx("span", { className: "inline-flex p-1 items-center justify-center", "aria-hidden": "true", children: _jsx(Icon, { icon: statusIcon, size: 7, fill: false, className: cn(colorClass) }) }), _jsx("div", { className: "flex flex-col flex-1 min-h-8", children: children }), isCloseTrigger && onClose && (_jsx(IconButton, { icon: "close", size: "sm", variant: "ghost", theme: "neutral", onClick: onClose, "aria-label": "\u9589\u3058\u308B", className: "shrink-0" }))] })) }));
98
98
  }
99
99
  InlineMessage.displayName = "InlineMessage";
100
100
  /**
@@ -25,8 +25,8 @@ const inputVariants = cva("flex gap-0 items-center w-full rounded-action border
25
25
  variants: {
26
26
  size: {
27
27
  sm: "h-8 character-2-regular-pro",
28
- md: "h-10 character-3-regular-pro",
29
- lg: "h-12 character-4-regular-pro",
28
+ md: "h-10 character-2-regular-pro",
29
+ lg: "h-12 character-3-regular-pro",
30
30
  },
31
31
  isInvalid: {
32
32
  true: "border-border-negative-extra-high-enabled",
@@ -236,12 +236,16 @@ function Input(_a) {
236
236
  isDisabled: isInputDisabled,
237
237
  isFocused: isInputFocused && !isIconButtonFocused,
238
238
  className,
239
- }), !isInputDisabled && "cursor-text" // 入力可能な場合はテキストカーソルを表示
239
+ }), isInputDisabled &&
240
+ !isInvalid &&
241
+ !isTrigger &&
242
+ "border-border-neutral-middle", !isInputDisabled && "cursor-text" // 入力可能な場合はテキストカーソルを表示
240
243
  ),
241
244
  // NOTE: not supportエラーがLintで出るためコメントアウト
242
245
  // aria-disabled={isInputDisabled}
243
246
  // aria-invalid={isInvalid === null ? undefined : isInvalid}
244
- onClick: handleContainerClick, role: "presentation", tabIndex: -1, children: [_jsx("input", Object.assign({ ref: mergedInputRef, disabled: isInputDisabled, "aria-invalid": isInvalid || undefined, className: cn("w-full h-full bg-transparent border-none outline-hidden focus:outline-hidden", "text-text-neutral-high placeholder:text-text-neutral-low px-2", isInputDisabled &&
247
+ onClick: handleContainerClick, role: "presentation", tabIndex: -1, children: [_jsx("input", Object.assign({ ref: mergedInputRef, disabled: isInputDisabled, "aria-invalid": isInvalid || undefined, className: cn("w-full h-full bg-transparent border-none outline-hidden focus:outline-hidden", "text-text-neutral-high placeholder:text-text-neutral-low pr-2", size === "lg" ? "pl-3" : size === "sm" ? "pl-1.5" : "pl-2", !isTrigger &&
248
+ (size === "lg" ? "pr-3" : size === "sm" ? "pr-1.5" : "pr-2"), isInputDisabled &&
245
249
  "cursor-not-allowed text-text-neutral-disabled placeholder:text-text-neutral-disabled"), onChange: handleChange, onFocus: handleInputFocus, onBlur: handleInputBlur, defaultValue: defaultValue, value: value, "aria-disabled": isInputDisabled }, props)), isTrigger && (_jsx(IconButton
246
250
  // triggerProps を先に展開し、専用 props (triggerAriaLabel / onIconButtonClick)
247
251
  // と内部制御プロパティで上書きする
@@ -68,13 +68,13 @@ export function Link(_a) {
68
68
  const hasCharacterClass = className === null || className === void 0 ? void 0 : className.includes("character-");
69
69
  // character-X-*-* のXの部分(サイズ)を取得
70
70
  const characterSizeMatch = className === null || className === void 0 ? void 0 : className.match(/character-(\d+)-/);
71
- const parsed = characterSizeMatch ? parseInt(characterSizeMatch[1], 10) : 3;
72
- const characterSize = (parsed >= 1 && parsed <= 12 ? parsed : 3);
71
+ const parsed = characterSizeMatch ? parseInt(characterSizeMatch[1], 10) : 2;
72
+ const characterSize = (parsed >= 1 && parsed <= 12 ? parsed : 2);
73
73
  // character クラスの生成
74
74
  const characterSizeClass = hasCharacterClass
75
75
  ? "" // 外部で指定されている場合は付与しない
76
76
  : `character-${characterSize}-regular-pro`;
77
- const linkClassName = cn("inline group", characterSizeClass, className);
77
+ const linkClassName = cn("inline group rounded-lg focus-visible:outline-2 focus-visible:outline-border-ring focus-visible:outline-offset-2", characterSizeClass, className);
78
78
  if (asChild &&
79
79
  typeof process !== "undefined" &&
80
80
  process.env.NODE_ENV !== "production" &&
@@ -84,10 +84,12 @@ export function Link(_a) {
84
84
  console.warn("[Link] asChild の子要素にはリンク要素(<a> や next/link 等)を渡してください。<span> や <div> を渡すとアクセシビリティが損なわれます。");
85
85
  }
86
86
  }
87
- const linkContent = (_jsxs(_Fragment, { children: [_jsx("span", { className: "transition-colors text-text-primary-enabled group-hover:text-text-primary-hover underline decoration-current underline-offset-2", children: children }), isExternalLink && (_jsx(Icon, { icon: "open_in_new", size: characterSize, className: "ml-1 align-middle inline-block text-object-primary-enabled group-hover:text-object-primary-hover" }))] }));
87
+ const linkContent = (_jsxs(_Fragment, { children: [_jsx("span", { className: "transition-colors text-text-primary-enabled group-hover:text-text-primary-hover underline decoration-current underline-offset-2", children: children }), isExternalLink && (_jsx(Icon, { icon: "open_in_new", size: (characterSize >= 6 ? characterSize + 1 : characterSize), className: "ml-1 align-middle inline-block text-object-primary-enabled group-hover:text-object-primary-hover" }))] }));
88
88
  if (asChild) {
89
89
  return (_jsx(SlotPrimitive.Slot, Object.assign({ ref: ref, className: linkClassName }, props, { children: React.isValidElement(children)
90
- ? React.cloneElement(children, {}, _jsxs(_Fragment, { children: [_jsx("span", { className: "transition-colors text-text-primary-enabled group-hover:text-text-primary-hover underline decoration-current underline-offset-2", children: children.props.children }), isExternalLink && (_jsx(Icon, { icon: "open_in_new", size: characterSize, className: "ml-1 align-middle inline-block text-object-primary-enabled group-hover:text-object-primary-hover" }))] }))
90
+ ? React.cloneElement(children, {}, _jsxs(_Fragment, { children: [_jsx("span", { className: "transition-colors text-text-primary-enabled group-hover:text-text-primary-hover underline decoration-current underline-offset-2", children: children.props.children }), isExternalLink && (_jsx(Icon, { icon: "open_in_new", size: (characterSize >= 6
91
+ ? characterSize + 1
92
+ : characterSize), className: "ml-1 align-middle inline-block text-object-primary-enabled group-hover:text-object-primary-hover" }))] }))
91
93
  : linkContent })));
92
94
  }
93
95
  return (_jsx("a", Object.assign({ ref: ref, className: linkClassName }, props, { children: linkContent })));
@@ -18,6 +18,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import * as React from "react";
19
19
  import { Dialog as DialogPrimitive } from "radix-ui";
20
20
  import { cn } from "../../../lib/utils.js";
21
+ import { Overlay } from "../overlay/index.js";
21
22
  import { IconButton } from "../icon-button/index.js";
22
23
  /**
23
24
  * **概要 / Overview**
@@ -95,12 +96,12 @@ function ModalTitle(_a) {
95
96
  /// モーダルのクローズボタン
96
97
  function ModalClose(_a) {
97
98
  var { "aria-label": ariaLabel = "閉じる" } = _a, props = __rest(_a, ["aria-label"]);
98
- return (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(IconButton, Object.assign({ icon: "close", "data-slot": "modal-close", size: "xs", variant: "ghost", theme: "neutral", "aria-label": ariaLabel }, props)) }));
99
+ return (_jsx(DialogPrimitive.Close, { asChild: true, children: _jsx(IconButton, Object.assign({ icon: "close", "data-slot": "modal-close", size: "sm", variant: "ghost", theme: "neutral", "aria-label": ariaLabel }, props)) }));
99
100
  }
100
101
  /// モーダルのオーバーレイ要素
101
102
  function ModalOverlay(_a) {
102
103
  var { className } = _a, props = __rest(_a, ["className"]);
103
- return (_jsx(DialogPrimitive.Overlay, Object.assign({ "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", className) }, props)));
104
+ return (_jsx(DialogPrimitive.Overlay, Object.assign({}, props, { asChild: true, children: _jsx(Overlay, { "data-slot": "modal-overlay", className: cn("z-50", className) }) })));
104
105
  }
105
106
  /// モーダルの本体
106
107
  function ModalContent(_a) {
@@ -28,8 +28,8 @@ const labelVariants = cva("cursor-pointer", {
28
28
  variants: {
29
29
  size: {
30
30
  sm: "character-2-regular-pro",
31
- md: "character-3-regular-pro",
32
- lg: "character-4-regular-pro",
31
+ md: "character-2-regular-pro",
32
+ lg: "character-3-regular-pro",
33
33
  },
34
34
  isDisabled: {
35
35
  true: "text-text-neutral-disabled cursor-not-allowed",
@@ -41,15 +41,17 @@ const labelVariants = cva("cursor-pointer", {
41
41
  isDisabled: false,
42
42
  },
43
43
  });
44
- const radioItemVariants = cva([
45
- "relative rounded-full transition-colors flex items-center justify-center cursor-pointer",
44
+ const radioItemVariants = cva(
45
+ // 表示寸法を維持しつつ、疑似要素で横24pxの操作領域を確保。en: Keep visuals, expand hit width to 24px.
46
+ [
47
+ "relative before:absolute before:inset-y-0 before:left-1/2 before:w-6 before:-translate-x-1/2 before:content-[''] rounded-full transition-colors flex items-center justify-center cursor-pointer",
46
48
  "focus:outline-none",
47
49
  ].join(" "), {
48
50
  variants: {
49
51
  size: {
50
- sm: "h-8 w-8",
51
- md: "h-10 w-10",
52
- lg: "h-12 w-12",
52
+ sm: "h-8 w-4",
53
+ md: "h-10 w-[18px]",
54
+ lg: "h-12 w-5",
53
55
  },
54
56
  isDisabled: {
55
57
  true: "cursor-not-allowed",
@@ -68,8 +70,8 @@ const radioIndicatorVariants = cva([
68
70
  variants: {
69
71
  size: {
70
72
  sm: "h-4 w-4",
71
- md: "h-5 w-5",
72
- lg: "h-6 w-6",
73
+ md: "h-[18px] w-[18px]",
74
+ lg: "h-5 w-5",
73
75
  },
74
76
  isInvalid: {
75
77
  true: "border-object-negative-enabled [.group[data-state=checked]_&]:border-object-negative-enabled",
@@ -110,8 +112,8 @@ const radioIndicatorDotVariants = cva("rounded-full transition-colors flex items
110
112
  variants: {
111
113
  size: {
112
114
  sm: "h-4 w-4",
113
- md: "h-5 w-5",
114
- lg: "h-6 w-6",
115
+ md: "h-[18px] w-[18px]",
116
+ lg: "h-5 w-5",
115
117
  },
116
118
  isInvalid: {
117
119
  true: "[.group[data-state=checked]_&]:bg-object-negative-enabled",
@@ -154,8 +156,8 @@ const radioIndicatorDotInnerVariants = cva("rounded-full bg-surface-base-0", {
154
156
  variants: {
155
157
  size: {
156
158
  sm: "h-2 w-2",
157
- md: "h-2.5 w-2.5",
158
- lg: "h-3 w-3",
159
+ md: "h-[9px] w-[9px]",
160
+ lg: "h-2.5 w-2.5",
159
161
  },
160
162
  },
161
163
  defaultVariants: {
@@ -264,7 +266,7 @@ Radio.displayName = RadioPrimitive.Root.displayName;
264
266
  function RadioItem(_a) {
265
267
  var { className, size = "md", isInvalid: isInvalidProp = false, disabled = false, label, id } = _a, props = __rest(_a, ["className", "size", "isInvalid", "disabled", "label", "id"]);
266
268
  const isInvalid = React.useContext(RadioInvalidContext) || !!isInvalidProp;
267
- return (_jsxs("div", { className: "flex items-center", children: [_jsx(RadioPrimitive.Item, Object.assign({ "data-slot": "radio-group-item", id: id, className: cn(radioItemVariants({ size, isDisabled: disabled }), "group", className), disabled: disabled }, props, { children: _jsx("div", { className: cn(radioIndicatorVariants({ size, isInvalid, isDisabled: disabled })), children: _jsx(RadioPrimitive.Indicator, { "data-slot": "radio-group-indicator", className: cn(radioIndicatorDotVariants({
269
+ return (_jsxs("div", { className: cn("flex items-center", size === "lg" ? "gap-2" : "gap-1.5"), children: [_jsx(RadioPrimitive.Item, Object.assign({ "data-slot": "radio-group-item", id: id, className: cn(radioItemVariants({ size, isDisabled: disabled }), "group", className), disabled: disabled }, props, { children: _jsx("div", { className: cn(radioIndicatorVariants({ size, isInvalid, isDisabled: disabled })), children: _jsx(RadioPrimitive.Indicator, { "data-slot": "radio-group-indicator", className: cn(radioIndicatorDotVariants({
268
270
  size,
269
271
  isInvalid,
270
272
  isDisabled: disabled,
@@ -26,9 +26,11 @@ const selectTriggerVariants = cva([
26
26
  ].join(" "), {
27
27
  variants: {
28
28
  size: {
29
- sm: "h-8 py-1 pl-2 pr-1 gap-2 character-2-regular-pro",
30
- md: "h-10 py-1 pl-3 pr-1.5 gap-2 character-3-regular-pro",
31
- lg: "h-12 py-1 pl-4 pr-2 gap-2 character-4-regular-pro",
29
+ // Figma の内側6px + 外側4pxを合成した10px。en: Combine inner 6px and outer 4px.
30
+ // sparkle-disable-next-line use-figma-spacing-scale
31
+ sm: "h-8 py-1 pl-2.5 pr-1.5 gap-2 character-2-regular-pro",
32
+ md: "h-10 py-1 pl-3 pr-2 gap-2 character-2-regular-pro",
33
+ lg: "h-12 py-1 pl-4 pr-2 gap-2 character-3-regular-pro",
32
34
  },
33
35
  isInvalid: {
34
36
  true: "bg-surface-base-0 border-border-negative-extra-high-enabled hover:border-border-negative-extra-high-hover data-[state=open]:border-border-negative-extra-high-hover",
@@ -56,8 +58,8 @@ const selectIconVariants = cva("", {
56
58
  variants: {
57
59
  size: {
58
60
  sm: "icon-5-fill-0",
59
- md: "icon-6-fill-0",
60
- lg: "icon-7-fill-0",
61
+ md: "icon-7-fill-0",
62
+ lg: "icon-8-fill-0",
61
63
  },
62
64
  isDisabled: {
63
65
  true: "text-object-neutral-disabled",
@@ -228,7 +230,7 @@ function SelectItem(_a) {
228
230
  "py-1.5 pl-8 pr-2 text-sm",
229
231
  "character-1-regular-pro text-text-neutral-middle",
230
232
  "outline-none focus:bg-neutral-100 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
231
- ].join(" "), className) }, props, { children: [_jsx(SelectPrimitive.ItemIndicator, { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(Icon, { icon: "check", size: 4 }) }), _jsx(SelectPrimitive.ItemText, { className: cn("flex-1", textClassName), children: children })] })));
233
+ ].join(" "), className) }, props, { children: [_jsx(SelectPrimitive.ItemIndicator, { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(Icon, { icon: "check", size: 4, className: "text-current" }) }), _jsx(SelectPrimitive.ItemText, { className: cn("flex-1", textClassName), children: children })] })));
232
234
  }
233
235
  /**
234
236
  * **概要 / Overview**
@@ -260,7 +262,7 @@ function SelectSeparator(_a) {
260
262
  */
261
263
  function SelectScrollUpButton(_a) {
262
264
  var { className } = _a, props = __rest(_a, ["className"]);
263
- return (_jsx(SelectPrimitive.ScrollUpButton, Object.assign({ "data-slot": "select-scroll-up-button", className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(Icon, { icon: "expand_less", size: 4 }) })));
265
+ return (_jsx(SelectPrimitive.ScrollUpButton, Object.assign({ "data-slot": "select-scroll-up-button", className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(Icon, { icon: "expand_less", size: 4, className: "text-object-neutral-middle" }) })));
264
266
  }
265
267
  /**
266
268
  * **概要 / Overview**
@@ -276,6 +278,6 @@ function SelectScrollUpButton(_a) {
276
278
  */
277
279
  function SelectScrollDownButton(_a) {
278
280
  var { className } = _a, props = __rest(_a, ["className"]);
279
- return (_jsx(SelectPrimitive.ScrollDownButton, Object.assign({ "data-slot": "select-scroll-down-button", className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(Icon, { icon: "expand_more", size: 4 }) })));
281
+ return (_jsx(SelectPrimitive.ScrollDownButton, Object.assign({ "data-slot": "select-scroll-down-button", className: cn("flex cursor-default items-center justify-center py-1", className) }, props, { children: _jsx(Icon, { icon: "expand_more", size: 4, className: "text-object-neutral-middle" }) })));
280
282
  }
281
283
  export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, SelectScrollUpButton, SelectScrollDownButton, };
@@ -41,7 +41,7 @@ const sliderRangeVariants = cva("absolute h-full bg-object-info", {
41
41
  },
42
42
  });
43
43
  const sliderThumbVariants = cva([
44
- "relative block rounded-full border border-object-neutral-low bg-surface-base-0 shadow-raise cursor-pointer",
44
+ "relative block rounded-full border border-object-neutral-low bg-surface-base-0 shadow-base cursor-pointer",
45
45
  // 半透明の状態色は白地に重ねる(つまみの下のトラックを透かさない)
46
46
  // en: Layer translucent state colors over the white fill so the track does not show through
47
47
  "ring-offset-background transition-colors hover:border-object-neutral-middle hover:bg-linear-to-r hover:from-surface-neutral-low-hover hover:to-surface-neutral-low-hover",
@@ -54,7 +54,7 @@ const sliderThumbVariants = cva([
54
54
  ].join(" "), {
55
55
  variants: {
56
56
  isDisabled: {
57
- true: "pointer-events-none bg-surface-neutral-middle-disabled bg-none border-none shadow-base cursor-not-allowed",
57
+ true: "pointer-events-none bg-surface-neutral-middle-disabled bg-none border-object-neutral-low shadow-base cursor-not-allowed",
58
58
  },
59
59
  },
60
60
  defaultVariants: {
@@ -6,8 +6,8 @@ import React from "react";
6
6
  import { type IconSize } from "@/components/ui/icon";
7
7
  export interface SpinnerProps extends React.ComponentProps<"span"> {
8
8
  /**
9
- * スピナーのサイズ(スケール値 1-12)
10
- * en: Size of the spinner (scale value 1-12)
9
+ * スピナーのサイズ(スケール値 1-13)
10
+ * en: Size of the spinner (scale value 1-13)
11
11
  * @see IconSize
12
12
  */
13
13
  size?: IconSize;
@@ -20,12 +20,12 @@ export interface SpinnerProps extends React.ComponentProps<"span"> {
20
20
  *
21
21
  * **アンチパターン / Anti-patterns**
22
22
  *
23
- * - `size` にピクセル値(24, 32 など)を渡さないでください。スケール値(1-12)を使用してください。
24
- * en: Do not pass pixel values to `size`. Use scale values (1-12) instead.
23
+ * - `size` にピクセル値(24, 32 など)を渡さないでください。スケール値(1-13)を使用してください。
24
+ * en: Do not pass pixel values to `size`. Use scale values (1-13) instead.
25
25
  *
26
26
  * ```tsx
27
27
  * // ✅ Correct - スケール値
28
- * <Spinner size={6} />
28
+ * <Spinner size={7} />
29
29
  *
30
30
  * // ❌ Wrong - ピクセル値
31
31
  * <Spinner size={24} />
@@ -34,7 +34,7 @@ export interface SpinnerProps extends React.ComponentProps<"span"> {
34
34
  * **使用例 / Usage Example**
35
35
  *
36
36
  * ```tsx
37
- * <Spinner size={6} />
37
+ * <Spinner size={7} />
38
38
  * ```
39
39
  *
40
40
  * @param {SpinnerProps} props
@@ -20,12 +20,12 @@ import { Icon } from "../../../components/ui/icon/index.js";
20
20
  *
21
21
  * **アンチパターン / Anti-patterns**
22
22
  *
23
- * - `size` にピクセル値(24, 32 など)を渡さないでください。スケール値(1-12)を使用してください。
24
- * en: Do not pass pixel values to `size`. Use scale values (1-12) instead.
23
+ * - `size` にピクセル値(24, 32 など)を渡さないでください。スケール値(1-13)を使用してください。
24
+ * en: Do not pass pixel values to `size`. Use scale values (1-13) instead.
25
25
  *
26
26
  * ```tsx
27
27
  * // ✅ Correct - スケール値
28
- * <Spinner size={6} />
28
+ * <Spinner size={7} />
29
29
  *
30
30
  * // ❌ Wrong - ピクセル値
31
31
  * <Spinner size={24} />
@@ -34,7 +34,7 @@ import { Icon } from "../../../components/ui/icon/index.js";
34
34
  * **使用例 / Usage Example**
35
35
  *
36
36
  * ```tsx
37
- * <Spinner size={6} />
37
+ * <Spinner size={7} />
38
38
  * ```
39
39
  *
40
40
  * @param {SpinnerProps} props
@@ -26,8 +26,8 @@ const TabsListVariantContext = createContext(undefined);
26
26
  */
27
27
  const tabsTriggerVariants = cva([
28
28
  "inline-flex items-center justify-center gap-1.5 whitespace-nowrap transition-colors duration-150 cursor-pointer disabled:cursor-not-allowed",
29
- "px-3 py-2 character-3-regular-pro",
30
- "focus-visible:outline-none",
29
+ "px-3 py-2 character-2-regular-pro data-[state=active]:[font-weight:var(--font-weight-char-bold)]!",
30
+ "relative focus-visible:outline-none focus-visible:z-20 before:pointer-events-none before:absolute before:inset-[-4px] before:rounded-lg before:border-2 before:border-border-ring before:opacity-0 focus-visible:before:opacity-100",
31
31
  ], {
32
32
  variants: {
33
33
  variant: {
@@ -102,7 +102,7 @@ const tabsListVariants = cva(["relative inline-flex items-center"], {
102
102
  },
103
103
  scrollable: {
104
104
  true: [
105
- "w-full max-w-full justify-start gap-2 overflow-x-auto overflow-y-visible",
105
+ "w-full max-w-full justify-start gap-2 overflow-x-auto overflow-y-visible p-1",
106
106
  "whitespace-nowrap overscroll-x-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
107
107
  ].join(" "),
108
108
  false: "w-fit justify-center gap-2 overflow-visible",
@@ -10,6 +10,8 @@ declare const tagVariants: (props?: ({
10
10
  status?: "neutral" | "negative" | "info" | "success" | "warning" | null | undefined;
11
11
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
12
12
  export interface TagProps extends React.ComponentProps<"div">, VariantProps<typeof tagVariants> {
13
+ /** ステータスドットの表示 / en: Whether to show a status dot */
14
+ body?: "none" | "status";
13
15
  /**
14
16
  * タグのラベルテキスト
15
17
  * en: Label text displayed inside the tag
@@ -46,7 +48,7 @@ export interface TagProps extends React.ComponentProps<"div">, VariantProps<type
46
48
  *
47
49
  * @param {TagProps} props
48
50
  */
49
- declare function Tag({ className, variant, size, status, children, ref, ...props }: TagProps): React.JSX.Element;
51
+ declare function Tag({ className, variant, size, status, body, children, ref, ...props }: TagProps): React.JSX.Element;
50
52
  declare namespace Tag {
51
53
  var displayName: string;
52
54
  }
@@ -9,11 +9,11 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
- import { jsx as _jsx } from "react/jsx-runtime";
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import { cva } from "class-variance-authority";
14
14
  import { cn } from "../../../lib/utils.js";
15
15
  // タグのスタイル定義
16
- const tagVariants = cva("inline-flex items-center justify-center rounded-notice h-fit min-w-0", {
16
+ const tagVariants = cva("inline-flex items-center justify-center rounded-full h-fit min-w-0", {
17
17
  variants: {
18
18
  variant: {
19
19
  solid: "",
@@ -21,9 +21,9 @@ const tagVariants = cva("inline-flex items-center justify-center rounded-notice
21
21
  subtle: "",
22
22
  },
23
23
  size: {
24
- sm: "py-0 px-2 min-w-10 character-1-bold-pro",
25
- md: "py-0.5 px-2 min-w-12 character-1-bold-pro",
26
- lg: "py-1 px-2 min-w-14 character-2-bold-pro",
24
+ sm: "min-h-5 py-1 px-1.5 min-w-10 character-1-bold-pro",
25
+ md: "min-h-6 py-1.5 px-2 min-w-12 character-1-bold-pro",
26
+ lg: "min-h-7 py-1.5 px-2 min-w-14 character-2-bold-pro",
27
27
  },
28
28
  status: {
29
29
  neutral: "",
@@ -70,31 +70,31 @@ const tagVariants = cva("inline-flex items-center justify-center rounded-notice
70
70
  {
71
71
  variant: "outline",
72
72
  status: "neutral",
73
- className: "border-object-neutral-middle text-text-neutral-middle bg-surface-base-0",
73
+ className: "border-border-neutral-middle text-text-neutral-middle bg-surface-base-0",
74
74
  },
75
75
  // info + outline
76
76
  {
77
77
  variant: "outline",
78
78
  status: "info",
79
- className: "border-object-info text-text-info bg-surface-base-0",
79
+ className: "border-border-info text-text-info bg-surface-base-0",
80
80
  },
81
81
  // success + outline
82
82
  {
83
83
  variant: "outline",
84
84
  status: "success",
85
- className: "border-object-success text-text-success bg-surface-base-0",
85
+ className: "border-border-success text-text-success bg-surface-base-0",
86
86
  },
87
87
  // warning + outline
88
88
  {
89
89
  variant: "outline",
90
90
  status: "warning",
91
- className: "border-object-warning text-text-warning bg-surface-base-0",
91
+ className: "border-border-warning text-text-warning bg-surface-base-0",
92
92
  },
93
93
  // negative + outline
94
94
  {
95
95
  variant: "outline",
96
96
  status: "negative",
97
- className: "border-object-negative-enabled text-text-negative-enabled bg-surface-base-0",
97
+ className: "border-border-negative-high text-text-negative-enabled bg-surface-base-0",
98
98
  },
99
99
  // === SUBTLE バリアント ===
100
100
  // neutral + subtle
@@ -165,8 +165,16 @@ const tagVariants = cva("inline-flex items-center justify-center rounded-notice
165
165
  * @param {TagProps} props
166
166
  */
167
167
  function Tag(_a) {
168
- var { className, variant, size, status, children, ref } = _a, props = __rest(_a, ["className", "variant", "size", "status", "children", "ref"]);
169
- return (_jsx("div", Object.assign({ ref: ref, className: cn(tagVariants({ variant, size, status, className })) }, props, { children: _jsx("span", { className: "min-w-0 truncate", children: children }) })));
168
+ var { className, variant = "solid", size = "md", status = "neutral", body = "none", children, ref } = _a, props = __rest(_a, ["className", "variant", "size", "status", "body", "children", "ref"]);
169
+ return (_jsxs("div", Object.assign({ ref: ref, className: cn(tagVariants({ variant, size, status, className })) }, props, { children: [body === "status" && (_jsx("span", { "aria-hidden": "true", className: cn("flex size-2.5 shrink-0 items-center justify-center", size === "sm" ? "mr-0.5" : "mr-1"), children: _jsx("span", { className: cn("size-1.5 rounded-full", variant === "solid"
170
+ ? "bg-object-inverse"
171
+ : {
172
+ neutral: "bg-object-neutral-middle",
173
+ info: "bg-object-info",
174
+ success: "bg-object-success",
175
+ warning: "bg-object-warning",
176
+ negative: "bg-object-negative-enabled",
177
+ }[status !== null && status !== void 0 ? status : "neutral"]) }) })), _jsx("span", { className: "min-w-0 truncate [text-box-trim:trim-both] [text-box-edge:cap_alphabetic]", children: children })] })));
170
178
  }
171
179
  Tag.displayName = "Tag";
172
180
  export { Tag, tagVariants };
@@ -11,7 +11,7 @@ import { type VariantProps } from "class-variance-authority";
11
11
  * - en: The Textarea component is used to capture user input in the form of multi-line text fields.
12
12
  */
13
13
  declare const textareaVariants: (props?: ({
14
- size?: "sm" | "md" | "lg" | null | undefined;
14
+ size?: "md" | "lg" | null | undefined;
15
15
  isInvalid?: boolean | null | undefined;
16
16
  isDisabled?: boolean | null | undefined;
17
17
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -20,13 +20,12 @@ import { cn } from "../../../lib/utils.js";
20
20
  */
21
21
  const textareaVariants = cva(
22
22
  // ベーススタイル
23
- "flex w-full rounded-action border bg-surface-base-0 px-3 py-1 ring-offset-background placeholder:text-text-neutral-low focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-ring focus-visible:ring-offset-2 resize", {
23
+ "flex w-full rounded-action border bg-surface-base-0 pt-2 pb-1 ring-offset-background placeholder:text-text-neutral-low focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-ring focus-visible:ring-offset-2 resize", {
24
24
  variants: {
25
- // サイズバリアント(sm, md, lg)
25
+ // サイズバリアント(md, lg)
26
26
  size: {
27
- sm: "min-h-[56px] character-2-regular-pro",
28
- md: "min-h-[56px] character-3-regular-pro",
29
- lg: "min-h-[64px] character-4-regular-pro",
27
+ md: "min-h-32 px-3 character-2-regular-pro",
28
+ lg: "min-h-32 px-4 character-3-regular-pro",
30
29
  },
31
30
  // エラー状態のバリアント
32
31
  isInvalid: {
@@ -42,7 +42,7 @@ import { IconButton } from "../../../components/ui/icon-button/index.js";
42
42
  * @param {ToastProps} props
43
43
  */
44
44
  export function Toast({ className, title, description, isCloseTrigger = true, id, }) {
45
- return (_jsxs("div", { role: "status", className: cn("shadow-float px-3 py-2 text-text-neutral-high flex w-[320px] rounded-notice gap-2 bg-surface-neutral-middle-enabled border border-border-neutral-middle", className), children: [_jsxs("div", { className: "h-full flex flex-col justify-center gap-0 px-1 grow", children: [title && (_jsx("p", { className: "character-3-bold-pro min-h-8 flex items-center", children: title })), _jsx("p", { className: "character-3-regular-pro min-h-8 flex items-center", children: description })] }), isCloseTrigger && (_jsx(IconButton, { icon: "close", size: "sm", variant: "ghost", theme: "neutral", "aria-label": "\u9589\u3058\u308B", onClick: () => {
45
+ return (_jsxs("div", { role: "status", className: cn("shadow-float px-3 py-3 text-text-neutral-high flex w-[320px] rounded-notice gap-2 bg-surface-neutral-middle-enabled border border-border-neutral-middle", className), children: [_jsxs("div", { className: "h-full flex flex-col justify-center gap-0 px-1 grow", children: [title && (_jsx("p", { className: "character-3-bold-pro min-h-8 flex items-center", children: title })), _jsx("p", { className: "character-2-regular-pro min-h-8 flex items-center", children: description })] }), isCloseTrigger && (_jsx(IconButton, { icon: "close", size: "sm", variant: "ghost", theme: "neutral", "aria-label": "\u9589\u3058\u308B", onClick: () => {
46
46
  sonnerToast.dismiss(id);
47
47
  } }))] }));
48
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-design",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public"