@designtools/shadows 0.1.5 → 0.1.6

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.
@@ -0,0 +1,210 @@
1
+ import { useState, useRef, useEffect } from "react";
2
+ import { Half2Icon } from "@radix-ui/react-icons";
3
+
4
+ export interface PreviewSettings {
5
+ previewBg: string;
6
+ showBorder: boolean;
7
+ borderColor: string;
8
+ }
9
+
10
+ export const DEFAULT_PREVIEW_SETTINGS: PreviewSettings = {
11
+ previewBg: "rgb(240, 244, 250)",
12
+ showBorder: false,
13
+ borderColor: "#e8e8e8",
14
+ };
15
+
16
+ const BG_SWATCHES = [
17
+ { name: "Soft Blue", value: "rgb(240, 244, 250)" },
18
+ { name: "White", value: "white" },
19
+ { name: "Light Gray", value: "#f0f0f0" },
20
+ { name: "Gray", value: "#e0e0e0" },
21
+ { name: "Mid Gray", value: "#d0d0d0" },
22
+ { name: "Dark Gray", value: "#bbb" },
23
+ ];
24
+
25
+ const BORDER_COLORS = [
26
+ { name: "Lightest", value: "#eee" },
27
+ { name: "Light", value: "#e0e0e0" },
28
+ { name: "Medium", value: "#d0d0d0" },
29
+ { name: "Dark", value: "#bbb" },
30
+ ];
31
+
32
+ interface ShadowPreviewSettingsProps {
33
+ settings: PreviewSettings;
34
+ onChange: (settings: PreviewSettings) => void;
35
+ }
36
+
37
+ export function ShadowPreviewSettingsButton({
38
+ settings,
39
+ onChange,
40
+ }: ShadowPreviewSettingsProps) {
41
+ const [open, setOpen] = useState(false);
42
+ const popoverRef = useRef<HTMLDivElement>(null);
43
+ const buttonRef = useRef<HTMLButtonElement>(null);
44
+
45
+ useEffect(() => {
46
+ if (!open) return;
47
+ const handleClick = (e: MouseEvent) => {
48
+ if (
49
+ popoverRef.current &&
50
+ !popoverRef.current.contains(e.target as Node) &&
51
+ buttonRef.current &&
52
+ !buttonRef.current.contains(e.target as Node)
53
+ ) {
54
+ setOpen(false);
55
+ }
56
+ };
57
+ document.addEventListener("mousedown", handleClick);
58
+ return () => document.removeEventListener("mousedown", handleClick);
59
+ }, [open]);
60
+
61
+ return (
62
+ <div style={{ position: "relative" }}>
63
+ <button
64
+ ref={buttonRef}
65
+ onClick={() => setOpen(!open)}
66
+ className="cursor-pointer"
67
+ style={{
68
+ display: "flex",
69
+ alignItems: "center",
70
+ gap: 6,
71
+ padding: "3px 8px 3px 6px",
72
+ borderRadius: 6,
73
+ fontSize: 10,
74
+ fontWeight: 500,
75
+ color: open ? "var(--studio-accent)" : "var(--studio-text-dimmed)",
76
+ background: open ? "var(--studio-accent-muted)" : "var(--studio-input-bg)",
77
+ border: "1px solid",
78
+ borderColor: open ? "var(--studio-accent)" : "var(--studio-border)",
79
+ transition: "all 0.15s",
80
+ }}
81
+ >
82
+ <Half2Icon style={{ width: 12, height: 12 }} />
83
+ Settings
84
+ </button>
85
+
86
+ {open && (
87
+ <div
88
+ ref={popoverRef}
89
+ style={{
90
+ position: "absolute",
91
+ top: "100%",
92
+ right: 0,
93
+ marginTop: 4,
94
+ background: "var(--studio-surface)",
95
+ border: "1px solid var(--studio-border)",
96
+ borderRadius: 8,
97
+ padding: "12px 14px",
98
+ zIndex: 100,
99
+ width: 248,
100
+ boxShadow: "0 8px 24px rgb(0 0 0 / 0.15)",
101
+ }}
102
+ >
103
+ <div className="flex flex-col gap-3.5">
104
+ {/* Background */}
105
+ <div>
106
+ <div
107
+ className="text-[9px] font-semibold uppercase tracking-wide mb-2"
108
+ style={{ color: "var(--studio-text-dimmed)" }}
109
+ >
110
+ Preview Background
111
+ </div>
112
+ <div className="flex gap-1.5">
113
+ {BG_SWATCHES.map((bg) => (
114
+ <button
115
+ key={bg.value}
116
+ onClick={() =>
117
+ onChange({ ...settings, previewBg: bg.value })
118
+ }
119
+ className="shrink-0 cursor-pointer"
120
+ title={bg.name}
121
+ style={{
122
+ width: 24,
123
+ height: 24,
124
+ borderRadius: 5,
125
+ background: bg.value,
126
+ border:
127
+ settings.previewBg === bg.value
128
+ ? "2px solid var(--studio-accent)"
129
+ : "1px solid var(--studio-border)",
130
+ }}
131
+ />
132
+ ))}
133
+ </div>
134
+ </div>
135
+
136
+ {/* Borders */}
137
+ <div>
138
+ <div className="flex items-center justify-between mb-2">
139
+ <div
140
+ className="text-[9px] font-semibold uppercase tracking-wide"
141
+ style={{ color: "var(--studio-text-dimmed)" }}
142
+ >
143
+ Show card borders
144
+ </div>
145
+ <button
146
+ onClick={() =>
147
+ onChange({
148
+ ...settings,
149
+ showBorder: !settings.showBorder,
150
+ })
151
+ }
152
+ className="shrink-0 cursor-pointer"
153
+ style={{
154
+ width: 34,
155
+ height: 20,
156
+ borderRadius: 10,
157
+ border: "1px solid var(--studio-border)",
158
+ background: settings.showBorder
159
+ ? "var(--studio-accent)"
160
+ : "var(--studio-input-bg)",
161
+ position: "relative",
162
+ transition: "background 0.15s",
163
+ }}
164
+ >
165
+ <div
166
+ style={{
167
+ width: 14,
168
+ height: 14,
169
+ borderRadius: "50%",
170
+ background: "white",
171
+ position: "absolute",
172
+ top: 2,
173
+ left: settings.showBorder ? 16 : 2,
174
+ transition: "left 0.15s",
175
+ boxShadow: "0 1px 2px rgb(0 0 0 / 0.15)",
176
+ }}
177
+ />
178
+ </button>
179
+ </div>
180
+ {settings.showBorder && (
181
+ <div className="flex gap-1.5">
182
+ {BORDER_COLORS.map((bc) => (
183
+ <button
184
+ key={bc.value}
185
+ onClick={() =>
186
+ onChange({ ...settings, borderColor: bc.value })
187
+ }
188
+ className="shrink-0 cursor-pointer"
189
+ title={bc.name}
190
+ style={{
191
+ width: 24,
192
+ height: 24,
193
+ borderRadius: 5,
194
+ background: bc.value,
195
+ border:
196
+ settings.borderColor === bc.value
197
+ ? "2px solid var(--studio-accent)"
198
+ : "1px solid var(--studio-border)",
199
+ }}
200
+ />
201
+ ))}
202
+ </div>
203
+ )}
204
+ </div>
205
+ </div>
206
+ </div>
207
+ )}
208
+ </div>
209
+ );
210
+ }
@@ -3,6 +3,8 @@ interface ShadowPreviewProps {
3
3
  size?: number;
4
4
  shape?: "square" | "rounded" | "circle";
5
5
  background?: string;
6
+ showBorder?: boolean;
7
+ borderColor?: string;
6
8
  }
7
9
 
8
10
  export function ShadowPreview({
@@ -10,6 +12,8 @@ export function ShadowPreview({
10
12
  size = 32,
11
13
  shape = "rounded",
12
14
  background = "white",
15
+ showBorder = false,
16
+ borderColor = "#e0e0e0",
13
17
  }: ShadowPreviewProps) {
14
18
  const borderRadius =
15
19
  shape === "circle" ? "50%" : shape === "rounded" ? "4px" : "0";
@@ -23,7 +27,7 @@ export function ShadowPreview({
23
27
  borderRadius,
24
28
  background,
25
29
  boxShadow: value,
26
- border: "1px solid var(--studio-border-subtle)",
30
+ border: showBorder ? `1px solid ${borderColor}` : "none",
27
31
  }}
28
32
  />
29
33
  );