@zmzai/theme 0.2.0 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zmzai/theme",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "zmzai 全品牌设计系统 — Radix UI + framer-motion + Tailwind v4 + MiSans",
@@ -5,7 +5,7 @@ import { cva } from "class-variance-authority";
5
5
  import { cn } from "../../utils/cn";
6
6
 
7
7
  export const badgeVariants = cva(
8
- "inline-flex items-center gap-1.5 rounded-full font-medium text-xs whitespace-nowrap",
8
+ "inline-flex items-center gap-1.5 rounded-sm font-medium text-xs whitespace-nowrap",
9
9
  {
10
10
  variants: {
11
11
  variant: {
@@ -4,13 +4,13 @@ import { cva } from "class-variance-authority";
4
4
  * Button variant styles.
5
5
  *
6
6
  * Design:
7
- * - All variants use pill radius (rounded-full)
7
+ * - 锐角 2px(v0.2 暖纸风),hover 轻微缩放
8
8
  * - primary: black fill, white text, hover scale + shadow
9
9
  * - secondary: transparent, border, hover fill
10
10
  * - ghost: no border, subtle hover bg
11
11
  */
12
12
  export const buttonVariants = cva(
13
- "inline-flex cursor-pointer items-center justify-center gap-2 rounded-full font-semibold transition-colors transition-transform disabled:pointer-events-none disabled:opacity-40 select-none",
13
+ "inline-flex cursor-pointer items-center justify-center gap-2 rounded-sm font-semibold transition-colors transition-transform disabled:pointer-events-none disabled:opacity-40 select-none",
14
14
  {
15
15
  variants: {
16
16
  variant: {
@@ -8,7 +8,7 @@ import { cva } from "class-variance-authority";
8
8
  * - interactive: hover lifts up + shadow + border darkens
9
9
  */
10
10
  export const cardVariants = cva(
11
- "bg-bg border rounded-xl transition-colors transition-transform duration-200",
11
+ "bg-bg border rounded-sm transition-colors transition-transform duration-200",
12
12
  {
13
13
  variants: {
14
14
  variant: {
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import { forwardRef, type ButtonHTMLAttributes } from "react";
4
+ import { cn } from "../../utils/cn";
5
+
6
+ export interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "ref"> {
7
+ /** 尺寸:sm=h-6 md=h-7 lg=h-8(密集工具条场景,不做 hover 缩放) */
8
+ size?: "sm" | "md" | "lg";
9
+ /** 视觉:ghost=透明 hover 背景;quiet=无 hover 背景只有颜色变化 */
10
+ tone?: "ghost" | "quiet";
11
+ label?: string;
12
+ }
13
+
14
+ /**
15
+ * IconButton — 密集场景的纯图标按钮。
16
+ *
17
+ * 与 Button 的区别:不做 framer-motion hover 缩放(工具条里会跳),
18
+ * 尺寸更小(6/7/8),tone=quiet 时连背景都没有(纯颜色 hover)。
19
+ *
20
+ * @example
21
+ * <IconButton label="重命名"><Icon name="edit" size={12} /></IconButton>
22
+ */
23
+ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
24
+ ({ className, size = "md", tone = "ghost", label, type = "button", ...props }, ref) => {
25
+ return (
26
+ <button
27
+ ref={ref}
28
+ type={type}
29
+ aria-label={label}
30
+ title={label}
31
+ className={cn(
32
+ "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-sm text-ink-3 transition-colors disabled:pointer-events-none disabled:opacity-40",
33
+ size === "sm" && "h-6 w-6",
34
+ size === "md" && "h-7 w-7",
35
+ size === "lg" && "h-8 w-8",
36
+ tone === "ghost" && "hover:bg-surface-2 hover:text-ink",
37
+ tone === "quiet" && "hover:text-ink",
38
+ className,
39
+ )}
40
+ {...props}
41
+ />
42
+ );
43
+ },
44
+ );
45
+
46
+ IconButton.displayName = "IconButton";
@@ -0,0 +1,2 @@
1
+ export { IconButton } from "./IconButton";
2
+ export type { IconButtonProps } from "./IconButton";
@@ -13,6 +13,8 @@ export * from "./tooltip";
13
13
  export * from "./dialog";
14
14
  export * from "./dropdown-menu";
15
15
  export * from "./select";
16
+ export * from "./icon-button";
17
+ export * from "./tabs";
16
18
 
17
19
  // === Interactive Enhancement ===
18
20
  export * from "./magnetic-button";
@@ -13,9 +13,9 @@ export const inputVariants = cva(
13
13
  variants: {
14
14
  variant: {
15
15
  default:
16
- "border border-line rounded-lg px-4 py-2.5 text-sm focus:border-ink",
16
+ "border border-line rounded-sm px-4 py-2.5 text-sm focus:border-ink",
17
17
  brutal:
18
- "border-2 border-ink rounded-xl px-4 py-3 text-sm shadow-[4px_4px_0_var(--color-ink)] focus:shadow-[6px_6px_0_var(--color-accent)] focus:border-accent focus:-translate-x-px focus:-translate-y-px",
18
+ "border-2 border-ink rounded-sm px-4 py-3 text-sm",
19
19
  },
20
20
  size: {
21
21
  sm: "text-xs py-2 px-3",
@@ -18,7 +18,7 @@ export function SelectTrigger({
18
18
  return (
19
19
  <SelectPrimitive.Trigger
20
20
  className={cn(
21
- "inline-flex h-9 items-center justify-between gap-2 rounded-lg border border-line bg-bg px-3 py-2 text-sm font-medium text-ink outline-none transition-colors",
21
+ "inline-flex h-9 items-center justify-between gap-2 rounded-sm border border-line bg-bg px-3 py-2 text-sm font-medium text-ink outline-none transition-colors",
22
22
  "hover:border-ink/40 focus:border-ink data-[placeholder]:text-ink-3",
23
23
  className
24
24
  )}
@@ -48,7 +48,7 @@ export function SelectContent({
48
48
  position={position}
49
49
  sideOffset={4}
50
50
  className={cn(
51
- "z-50 min-w-[8rem] overflow-hidden rounded-lg border border-line bg-bg p-1 shadow-lg",
51
+ "z-50 min-w-[8rem] overflow-hidden rounded-sm border border-line bg-bg p-1 shadow-lg",
52
52
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
53
53
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
54
54
  className
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import { cn } from "../../utils/cn";
4
+
5
+ export type TabItem = { value: string; label: React.ReactNode; count?: number };
6
+
7
+ export interface TabsProps {
8
+ items: TabItem[];
9
+ value: string;
10
+ onValueChange: (value: string) => void;
11
+ className?: string;
12
+ }
13
+
14
+ /**
15
+ * Tabs — 下划线激活态的水平标签栏(锐角风)。
16
+ *
17
+ * @example
18
+ * <Tabs items={[{value:"a",label:"产物",count:2},{value:"b",label:"改动"}]} value={tab} onValueChange={setTab} />
19
+ */
20
+ export function Tabs({ items, value, onValueChange, className }: TabsProps) {
21
+ return (
22
+ <div className={cn("flex gap-0 border-b border-line", className)} role="tablist">
23
+ {items.map((item) => {
24
+ const active = item.value === value;
25
+ return (
26
+ <button
27
+ key={item.value}
28
+ type="button"
29
+ role="tab"
30
+ aria-selected={active}
31
+ className={cn(
32
+ "cursor-pointer border-b-2 px-3 py-2.5 text-xs font-medium transition-colors",
33
+ active ? "border-ink text-ink" : "border-transparent text-ink-3 hover:text-ink-2",
34
+ )}
35
+ onClick={() => onValueChange(item.value)}
36
+ >
37
+ {item.label}
38
+ {typeof item.count === "number" && (
39
+ <span className="ml-1 rounded-full bg-surface-2 px-1.5 text-[10px]">{item.count}</span>
40
+ )}
41
+ </button>
42
+ );
43
+ })}
44
+ </div>
45
+ );
46
+ }
@@ -0,0 +1,2 @@
1
+ export { Tabs } from "./Tabs";
2
+ export type { TabItem, TabsProps } from "./Tabs";
@@ -25,9 +25,9 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
25
25
  className={cn(
26
26
  "w-full resize-none bg-bg font-sans text-ink placeholder:text-ink-3 outline-none transition-all",
27
27
  variant === "default" &&
28
- "border border-line rounded-lg px-4 py-2.5 text-sm focus:border-ink",
28
+ "border border-line rounded-sm px-4 py-2.5 text-sm focus:border-ink",
29
29
  variant === "brutal" &&
30
- "border-2 border-ink rounded-xl px-4 py-3 text-sm shadow-[4px_4px_0_var(--color-ink)] focus:shadow-[6px_6px_0_var(--color-accent)] focus:border-accent focus:-translate-x-px focus:-translate-y-px",
30
+ "border-2 border-ink rounded-sm px-4 py-3 text-sm",
31
31
  className
32
32
  )}
33
33
  {...props}