@fxshelf/button-kit 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/react/Button.tsx
8
+
9
+ // src/core/variants.ts
10
+ var BUTTON_VARIANTS = [
11
+ "solid",
12
+ "outline",
13
+ "soft",
14
+ "glow",
15
+ "neon",
16
+ "shimmer",
17
+ "chroma",
18
+ "liquid",
19
+ "wipe",
20
+ "glass"
21
+ ];
22
+ var DEFAULT_VARIANT = "solid";
23
+ function resolveVariant(variant) {
24
+ if (variant != null && BUTTON_VARIANTS.includes(variant)) {
25
+ return variant;
26
+ }
27
+ return DEFAULT_VARIANT;
28
+ }
29
+ function variantClassName(variant) {
30
+ return `fx-btn fx-btn--${resolveVariant(variant)}`;
31
+ }
32
+ function Button({
33
+ variant = "solid",
34
+ children,
35
+ className,
36
+ style,
37
+ type = "button",
38
+ ...rest
39
+ }) {
40
+ const classes = [variantClassName(variant), className].filter(Boolean).join(" ");
41
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type, className: classes, style, ...rest, children });
42
+ }
43
+
44
+ exports.BUTTON_VARIANTS = BUTTON_VARIANTS;
45
+ exports.Button = Button;
46
+ //# sourceMappingURL=index.cjs.map
47
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/variants.ts","../src/react/Button.tsx"],"names":["jsx"],"mappings":";;;;;;;;AACO,IAAM,eAAA,GAAkB;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF;AAIO,IAAM,eAAA,GAAiC,OAAA;AAEvC,SAAS,eAAe,OAAA,EAAiC;AAC9D,EAAA,IACE,OAAA,IAAW,IAAA,IACV,eAAA,CAAsC,QAAA,CAAS,OAAO,CAAA,EACvD;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AACA,EAAA,OAAO,eAAA;AACT;AAEO,SAAS,iBAAiB,OAAA,EAA0B;AACzD,EAAA,OAAO,CAAA,eAAA,EAAkB,cAAA,CAAe,OAAO,CAAC,CAAA,CAAA;AAClD;ACLO,SAAS,MAAA,CAAO;AAAA,EACrB,OAAA,GAAU,OAAA;AAAA,EACV,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,QAAA;AAAA,EACP,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,MAAM,OAAA,GAAU,CAAC,gBAAA,CAAiB,OAAO,CAAA,EAAG,SAAS,CAAA,CAClD,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AAEX,EAAA,uBACEA,cAAA,CAAC,YAAO,IAAA,EAAY,SAAA,EAAW,SAAS,KAAA,EAAe,GAAG,MACvD,QAAA,EACH,CAAA;AAEJ","file":"index.cjs","sourcesContent":["/** Built-in button looks. Pass any of these as `variant`. */\nexport const BUTTON_VARIANTS = [\n 'solid',\n 'outline',\n 'soft',\n 'glow',\n 'neon',\n 'shimmer',\n 'chroma',\n 'liquid',\n 'wipe',\n 'glass',\n] as const\n\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number]\n\nexport const DEFAULT_VARIANT: ButtonVariant = 'solid'\n\nexport function resolveVariant(variant?: string): ButtonVariant {\n if (\n variant != null &&\n (BUTTON_VARIANTS as readonly string[]).includes(variant)\n ) {\n return variant as ButtonVariant\n }\n return DEFAULT_VARIANT\n}\n\nexport function variantClassName(variant?: string): string {\n return `fx-btn fx-btn--${resolveVariant(variant)}`\n}\n","'use client'\n\nimport {\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactNode,\n} from 'react'\nimport {\n BUTTON_VARIANTS,\n type ButtonVariant,\n variantClassName,\n} from '../core/variants'\nimport '../core/styles.css'\n\nexport type ButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'className' | 'style' | 'children'\n> & {\n /** Switch look by name: solid | outline | soft | glow | neon | shimmer | chroma | liquid | wipe | glass. */\n variant?: ButtonVariant | (string & {})\n children?: ReactNode\n className?: string\n style?: CSSProperties\n}\n\nexport function Button({\n variant = 'solid',\n children,\n className,\n style,\n type = 'button',\n ...rest\n}: ButtonProps) {\n const classes = [variantClassName(variant), className]\n .filter(Boolean)\n .join(' ')\n\n return (\n <button type={type} className={classes} style={style} {...rest}>\n {children}\n </button>\n )\n}\n\nexport { BUTTON_VARIANTS, type ButtonVariant }\nexport default Button\n"]}
package/dist/index.css ADDED
@@ -0,0 +1,273 @@
1
+ /* src/core/styles.css */
2
+ .fx-btn {
3
+ --fx-btn-fg: #0f0f12;
4
+ --fx-btn-bg: #f4f4f5;
5
+ --fx-btn-accent: #3b82f6;
6
+ --fx-btn-radius: 10px;
7
+ position: relative;
8
+ display: inline-flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ gap: 0.5rem;
12
+ padding: 0.7rem 1.25rem;
13
+ border: 1px solid transparent;
14
+ border-radius: var(--fx-btn-radius);
15
+ background: var(--fx-btn-bg);
16
+ color: var(--fx-btn-fg);
17
+ font: inherit;
18
+ font-size: 0.9375rem;
19
+ font-weight: 600;
20
+ line-height: 1.2;
21
+ letter-spacing: 0.01em;
22
+ text-decoration: none;
23
+ cursor: pointer;
24
+ user-select: none;
25
+ -webkit-tap-highlight-color: transparent;
26
+ isolation: isolate;
27
+ overflow: hidden;
28
+ transition:
29
+ transform 160ms ease,
30
+ box-shadow 200ms ease,
31
+ background-color 200ms ease,
32
+ border-color 200ms ease,
33
+ color 200ms ease;
34
+ }
35
+ .fx-btn:focus-visible {
36
+ outline: 2px solid var(--fx-btn-accent);
37
+ outline-offset: 3px;
38
+ }
39
+ .fx-btn:disabled {
40
+ opacity: 0.5;
41
+ cursor: not-allowed;
42
+ pointer-events: none;
43
+ }
44
+ .fx-btn:active:not(:disabled) {
45
+ transform: translateY(1px) scale(0.98);
46
+ }
47
+ .fx-btn--solid {
48
+ --fx-btn-fg: #fafafa;
49
+ --fx-btn-bg: #18181b;
50
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;
51
+ }
52
+ .fx-btn--solid:hover:not(:disabled) {
53
+ background: #27272a;
54
+ }
55
+ .fx-btn--outline {
56
+ --fx-btn-fg: #18181b;
57
+ --fx-btn-bg: transparent;
58
+ border-color: #d4d4d8;
59
+ background: transparent;
60
+ }
61
+ .fx-btn--outline:hover:not(:disabled) {
62
+ border-color: #18181b;
63
+ background: #18181b;
64
+ color: #fafafa;
65
+ }
66
+ .fx-btn--soft {
67
+ --fx-btn-fg: #1d4ed8;
68
+ --fx-btn-bg: #dbeafe;
69
+ }
70
+ .fx-btn--soft:hover:not(:disabled) {
71
+ background: #bfdbfe;
72
+ transform: translateY(-1px);
73
+ }
74
+ .fx-btn--soft:active:not(:disabled) {
75
+ transform: translateY(0) scale(0.98);
76
+ }
77
+ .fx-btn--glow {
78
+ --fx-btn-fg: #f8fafc;
79
+ --fx-btn-bg: #2563eb;
80
+ box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.45), 0 8px 24px rgba(37, 99, 235, 0.28);
81
+ animation: fx-btn-glow-pulse 2.4s ease-in-out infinite;
82
+ }
83
+ .fx-btn--glow:hover:not(:disabled) {
84
+ background: #1d4ed8;
85
+ box-shadow: 0 0 0 6px rgba(37, 99, 235, 0.18), 0 10px 28px rgba(37, 99, 235, 0.4);
86
+ animation: none;
87
+ }
88
+ @keyframes fx-btn-glow-pulse {
89
+ 0%, 100% {
90
+ box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.4), 0 8px 24px rgba(37, 99, 235, 0.28);
91
+ }
92
+ 50% {
93
+ box-shadow: 0 0 0 8px rgba(37, 99, 235, 0), 0 10px 28px rgba(37, 99, 235, 0.35);
94
+ }
95
+ }
96
+ .fx-btn--neon {
97
+ --fx-btn-fg: #67e8f9;
98
+ --fx-btn-bg: #0b1220;
99
+ border-color: #22d3ee;
100
+ box-shadow:
101
+ 0 0 0 1px rgba(34, 211, 238, 0.25),
102
+ 0 0 18px rgba(34, 211, 238, 0.35),
103
+ inset 0 0 12px rgba(34, 211, 238, 0.08);
104
+ text-shadow: 0 0 10px rgba(103, 232, 249, 0.55);
105
+ }
106
+ .fx-btn--neon:hover:not(:disabled) {
107
+ color: #ecfeff;
108
+ border-color: #67e8f9;
109
+ box-shadow:
110
+ 0 0 0 1px rgba(103, 232, 249, 0.45),
111
+ 0 0 28px rgba(34, 211, 238, 0.55),
112
+ inset 0 0 16px rgba(34, 211, 238, 0.14);
113
+ }
114
+ .fx-btn--shimmer {
115
+ --fx-btn-fg: #fafafa;
116
+ --fx-btn-bg: #111827;
117
+ }
118
+ .fx-btn--shimmer::before {
119
+ content: "";
120
+ position: absolute;
121
+ inset: 0;
122
+ z-index: -1;
123
+ background:
124
+ linear-gradient(
125
+ 110deg,
126
+ transparent 30%,
127
+ rgba(255, 255, 255, 0.28) 48%,
128
+ transparent 66%);
129
+ transform: translateX(-120%);
130
+ transition: transform 0.55s ease;
131
+ }
132
+ .fx-btn--shimmer:hover:not(:disabled)::before {
133
+ transform: translateX(120%);
134
+ }
135
+ .fx-btn--shimmer:hover:not(:disabled) {
136
+ background: #1f2937;
137
+ }
138
+ .fx-btn--chroma {
139
+ --fx-btn-fg: #fff;
140
+ --fx-btn-radius: 999px;
141
+ z-index: 0;
142
+ overflow: visible;
143
+ isolation: auto;
144
+ border: none;
145
+ background:
146
+ linear-gradient(
147
+ to right,
148
+ #03a9f4,
149
+ #f441a5,
150
+ #ffeb3b,
151
+ #03a9f4);
152
+ background-size: 400%;
153
+ letter-spacing: 0.08em;
154
+ animation: fx-btn-chroma-shift 8s ease infinite;
155
+ }
156
+ .fx-btn--chroma::before {
157
+ content: "";
158
+ position: absolute;
159
+ inset: -4px;
160
+ z-index: -1;
161
+ border-radius: inherit;
162
+ background:
163
+ linear-gradient(
164
+ to right,
165
+ #03a9f4,
166
+ #f441a5,
167
+ #ffeb3b,
168
+ #03a9f4);
169
+ background-size: 400%;
170
+ filter: blur(0);
171
+ opacity: 0;
172
+ pointer-events: none;
173
+ transition: opacity 0.4s ease, filter 0.4s ease;
174
+ animation: fx-btn-chroma-shift 8s ease infinite;
175
+ }
176
+ .fx-btn--chroma:hover:not(:disabled)::before {
177
+ opacity: 1;
178
+ filter: blur(8px);
179
+ }
180
+ .fx-btn--chroma:active:not(:disabled) {
181
+ transform: translateY(1px) scale(0.98);
182
+ }
183
+ @keyframes fx-btn-chroma-shift {
184
+ 0% {
185
+ background-position: 0%;
186
+ }
187
+ 100% {
188
+ background-position: 400%;
189
+ }
190
+ }
191
+ .fx-btn--liquid {
192
+ --fx-btn-fg: #0891b2;
193
+ --fx-btn-bg: transparent;
194
+ z-index: 0;
195
+ border-color: #0891b2;
196
+ background: transparent;
197
+ overflow: hidden;
198
+ }
199
+ .fx-btn--liquid::before {
200
+ content: "";
201
+ position: absolute;
202
+ left: -30%;
203
+ bottom: 0;
204
+ z-index: -1;
205
+ width: 160%;
206
+ height: 220%;
207
+ border-radius: 42% 48% 0 0 / 28% 32% 0 0;
208
+ background:
209
+ linear-gradient(
210
+ 180deg,
211
+ #22d3ee,
212
+ #0891b2);
213
+ transform: translateY(82%);
214
+ transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);
215
+ }
216
+ .fx-btn--liquid:hover:not(:disabled) {
217
+ color: #fff;
218
+ }
219
+ .fx-btn--liquid:hover:not(:disabled)::before {
220
+ transform: translateY(12%);
221
+ animation: fx-btn-liquid-wave 2.4s ease-in-out infinite 0.55s;
222
+ }
223
+ @keyframes fx-btn-liquid-wave {
224
+ 0%, 100% {
225
+ border-radius: 42% 48% 0 0 / 28% 32% 0 0;
226
+ }
227
+ 50% {
228
+ border-radius: 48% 42% 0 0 / 34% 26% 0 0;
229
+ }
230
+ }
231
+ .fx-btn--wipe {
232
+ --fx-btn-fg: #f4f4f5;
233
+ --fx-btn-bg: transparent;
234
+ z-index: 0;
235
+ border-color: rgba(244, 244, 245, 0.7);
236
+ background: transparent;
237
+ overflow: hidden;
238
+ }
239
+ .fx-btn--wipe::before {
240
+ content: "";
241
+ position: absolute;
242
+ inset: 0;
243
+ z-index: -1;
244
+ background: #f4f4f5;
245
+ transform: translateX(-105%) skewX(-12deg);
246
+ transform-origin: left center;
247
+ transition: transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);
248
+ }
249
+ .fx-btn--wipe:hover:not(:disabled) {
250
+ color: #18181b;
251
+ border-color: #f4f4f5;
252
+ }
253
+ .fx-btn--wipe:hover:not(:disabled)::before {
254
+ transform: translateX(0) skewX(0deg);
255
+ }
256
+ .fx-btn--glass {
257
+ --fx-btn-fg: #f8fafc;
258
+ --fx-btn-bg: rgba(255, 255, 255, 0.1);
259
+ border-color: rgba(255, 255, 255, 0.28);
260
+ background: rgba(255, 255, 255, 0.1);
261
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 8px 24px rgba(0, 0, 0, 0.18);
262
+ backdrop-filter: blur(14px);
263
+ -webkit-backdrop-filter: blur(14px);
264
+ }
265
+ .fx-btn--glass:hover:not(:disabled) {
266
+ background: rgba(255, 255, 255, 0.18);
267
+ border-color: rgba(255, 255, 255, 0.4);
268
+ transform: translateY(-1px);
269
+ }
270
+ .fx-btn--glass:active:not(:disabled) {
271
+ transform: translateY(0) scale(0.98);
272
+ }
273
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/styles.css"],"sourcesContent":[".fx-btn {\n --fx-btn-fg: #0f0f12;\n --fx-btn-bg: #f4f4f5;\n --fx-btn-accent: #3b82f6;\n --fx-btn-radius: 10px;\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.7rem 1.25rem;\n border: 1px solid transparent;\n border-radius: var(--fx-btn-radius);\n background: var(--fx-btn-bg);\n color: var(--fx-btn-fg);\n font: inherit;\n font-size: 0.9375rem;\n font-weight: 600;\n line-height: 1.2;\n letter-spacing: 0.01em;\n text-decoration: none;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n isolation: isolate;\n overflow: hidden;\n transition:\n transform 160ms ease,\n box-shadow 200ms ease,\n background-color 200ms ease,\n border-color 200ms ease,\n color 200ms ease;\n}\n\n.fx-btn:focus-visible {\n outline: 2px solid var(--fx-btn-accent);\n outline-offset: 3px;\n}\n\n.fx-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.fx-btn:active:not(:disabled) {\n transform: translateY(1px) scale(0.98);\n}\n\n/* —— solid —— */\n.fx-btn--solid {\n --fx-btn-fg: #fafafa;\n --fx-btn-bg: #18181b;\n box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset;\n}\n\n.fx-btn--solid:hover:not(:disabled) {\n background: #27272a;\n}\n\n/* —— outline —— */\n.fx-btn--outline {\n --fx-btn-fg: #18181b;\n --fx-btn-bg: transparent;\n border-color: #d4d4d8;\n background: transparent;\n}\n\n.fx-btn--outline:hover:not(:disabled) {\n border-color: #18181b;\n background: #18181b;\n color: #fafafa;\n}\n\n/* —— soft —— */\n.fx-btn--soft {\n --fx-btn-fg: #1d4ed8;\n --fx-btn-bg: #dbeafe;\n}\n\n.fx-btn--soft:hover:not(:disabled) {\n background: #bfdbfe;\n transform: translateY(-1px);\n}\n\n.fx-btn--soft:active:not(:disabled) {\n transform: translateY(0) scale(0.98);\n}\n\n/* —— glow —— */\n.fx-btn--glow {\n --fx-btn-fg: #f8fafc;\n --fx-btn-bg: #2563eb;\n box-shadow:\n 0 0 0 0 rgba(37, 99, 235, 0.45),\n 0 8px 24px rgba(37, 99, 235, 0.28);\n animation: fx-btn-glow-pulse 2.4s ease-in-out infinite;\n}\n\n.fx-btn--glow:hover:not(:disabled) {\n background: #1d4ed8;\n box-shadow:\n 0 0 0 6px rgba(37, 99, 235, 0.18),\n 0 10px 28px rgba(37, 99, 235, 0.4);\n animation: none;\n}\n\n@keyframes fx-btn-glow-pulse {\n 0%,\n 100% {\n box-shadow:\n 0 0 0 0 rgba(37, 99, 235, 0.4),\n 0 8px 24px rgba(37, 99, 235, 0.28);\n }\n 50% {\n box-shadow:\n 0 0 0 8px rgba(37, 99, 235, 0),\n 0 10px 28px rgba(37, 99, 235, 0.35);\n }\n}\n\n/* —— neon —— */\n.fx-btn--neon {\n --fx-btn-fg: #67e8f9;\n --fx-btn-bg: #0b1220;\n border-color: #22d3ee;\n box-shadow:\n 0 0 0 1px rgba(34, 211, 238, 0.25),\n 0 0 18px rgba(34, 211, 238, 0.35),\n inset 0 0 12px rgba(34, 211, 238, 0.08);\n text-shadow: 0 0 10px rgba(103, 232, 249, 0.55);\n}\n\n.fx-btn--neon:hover:not(:disabled) {\n color: #ecfeff;\n border-color: #67e8f9;\n box-shadow:\n 0 0 0 1px rgba(103, 232, 249, 0.45),\n 0 0 28px rgba(34, 211, 238, 0.55),\n inset 0 0 16px rgba(34, 211, 238, 0.14);\n}\n\n/* —— shimmer —— */\n.fx-btn--shimmer {\n --fx-btn-fg: #fafafa;\n --fx-btn-bg: #111827;\n}\n\n.fx-btn--shimmer::before {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n background: linear-gradient(\n 110deg,\n transparent 30%,\n rgba(255, 255, 255, 0.28) 48%,\n transparent 66%\n );\n transform: translateX(-120%);\n transition: transform 0.55s ease;\n}\n\n.fx-btn--shimmer:hover:not(:disabled)::before {\n transform: translateX(120%);\n}\n\n.fx-btn--shimmer:hover:not(:disabled) {\n background: #1f2937;\n}\n\n/* —— chroma(炫彩流光 + hover 高斯光晕) —— */\n.fx-btn--chroma {\n --fx-btn-fg: #fff;\n --fx-btn-radius: 999px;\n z-index: 0;\n overflow: visible;\n isolation: auto;\n border: none;\n background: linear-gradient(\n to right,\n #03a9f4,\n #f441a5,\n #ffeb3b,\n #03a9f4\n );\n background-size: 400%;\n letter-spacing: 0.08em;\n animation: fx-btn-chroma-shift 8s ease infinite;\n}\n\n.fx-btn--chroma::before {\n content: '';\n position: absolute;\n inset: -4px;\n z-index: -1;\n border-radius: inherit;\n background: linear-gradient(\n to right,\n #03a9f4,\n #f441a5,\n #ffeb3b,\n #03a9f4\n );\n background-size: 400%;\n filter: blur(0);\n opacity: 0;\n pointer-events: none;\n transition:\n opacity 0.4s ease,\n filter 0.4s ease;\n animation: fx-btn-chroma-shift 8s ease infinite;\n}\n\n.fx-btn--chroma:hover:not(:disabled)::before {\n opacity: 1;\n filter: blur(8px);\n}\n\n.fx-btn--chroma:active:not(:disabled) {\n transform: translateY(1px) scale(0.98);\n}\n\n@keyframes fx-btn-chroma-shift {\n 0% {\n background-position: 0%;\n }\n\n 100% {\n background-position: 400%;\n }\n}\n\n/* —— liquid(底部液体升起) —— */\n.fx-btn--liquid {\n --fx-btn-fg: #0891b2;\n --fx-btn-bg: transparent;\n z-index: 0;\n border-color: #0891b2;\n background: transparent;\n overflow: hidden;\n}\n\n.fx-btn--liquid::before {\n content: '';\n position: absolute;\n left: -30%;\n bottom: 0;\n z-index: -1;\n width: 160%;\n height: 220%;\n border-radius: 42% 48% 0 0 / 28% 32% 0 0;\n background: linear-gradient(180deg, #22d3ee, #0891b2);\n transform: translateY(82%);\n transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.fx-btn--liquid:hover:not(:disabled) {\n color: #fff;\n}\n\n.fx-btn--liquid:hover:not(:disabled)::before {\n transform: translateY(12%);\n animation: fx-btn-liquid-wave 2.4s ease-in-out infinite 0.55s;\n}\n\n@keyframes fx-btn-liquid-wave {\n 0%,\n 100% {\n border-radius: 42% 48% 0 0 / 28% 32% 0 0;\n }\n\n 50% {\n border-radius: 48% 42% 0 0 / 34% 26% 0 0;\n }\n}\n\n/* —— wipe(左向右擦除填充) —— */\n.fx-btn--wipe {\n --fx-btn-fg: #f4f4f5;\n --fx-btn-bg: transparent;\n z-index: 0;\n border-color: rgba(244, 244, 245, 0.7);\n background: transparent;\n overflow: hidden;\n}\n\n.fx-btn--wipe::before {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n background: #f4f4f5;\n transform: translateX(-105%) skewX(-12deg);\n transform-origin: left center;\n transition: transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);\n}\n\n.fx-btn--wipe:hover:not(:disabled) {\n color: #18181b;\n border-color: #f4f4f5;\n}\n\n.fx-btn--wipe:hover:not(:disabled)::before {\n transform: translateX(0) skewX(0deg);\n}\n\n/* —— glass(毛玻璃) —— */\n.fx-btn--glass {\n --fx-btn-fg: #f8fafc;\n --fx-btn-bg: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.28);\n background: rgba(255, 255, 255, 0.1);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n 0 8px 24px rgba(0, 0, 0, 0.18);\n backdrop-filter: blur(14px);\n -webkit-backdrop-filter: blur(14px);\n}\n\n.fx-btn--glass:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.18);\n border-color: rgba(255, 255, 255, 0.4);\n transform: translateY(-1px);\n}\n\n.fx-btn--glass:active:not(:disabled) {\n transform: translateY(0) scale(0.98);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,17 @@
1
+ import * as react from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+
4
+ /** Built-in button looks. Pass any of these as `variant`. */
5
+ declare const BUTTON_VARIANTS: readonly ["solid", "outline", "soft", "glow", "neon", "shimmer", "chroma", "liquid", "wipe", "glass"];
6
+ type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
7
+
8
+ type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'style' | 'children'> & {
9
+ /** Switch look by name: solid | outline | soft | glow | neon | shimmer | chroma | liquid | wipe | glass. */
10
+ variant?: ButtonVariant | (string & {});
11
+ children?: ReactNode;
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ };
15
+ declare function Button({ variant, children, className, style, type, ...rest }: ButtonProps): react.JSX.Element;
16
+
17
+ export { BUTTON_VARIANTS, Button, type ButtonProps, type ButtonVariant };
@@ -0,0 +1,17 @@
1
+ import * as react from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, CSSProperties } from 'react';
3
+
4
+ /** Built-in button looks. Pass any of these as `variant`. */
5
+ declare const BUTTON_VARIANTS: readonly ["solid", "outline", "soft", "glow", "neon", "shimmer", "chroma", "liquid", "wipe", "glass"];
6
+ type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
7
+
8
+ type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'style' | 'children'> & {
9
+ /** Switch look by name: solid | outline | soft | glow | neon | shimmer | chroma | liquid | wipe | glass. */
10
+ variant?: ButtonVariant | (string & {});
11
+ children?: ReactNode;
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ };
15
+ declare function Button({ variant, children, className, style, type, ...rest }: ButtonProps): react.JSX.Element;
16
+
17
+ export { BUTTON_VARIANTS, Button, type ButtonProps, type ButtonVariant };
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ // src/react/Button.tsx
6
+
7
+ // src/core/variants.ts
8
+ var BUTTON_VARIANTS = [
9
+ "solid",
10
+ "outline",
11
+ "soft",
12
+ "glow",
13
+ "neon",
14
+ "shimmer",
15
+ "chroma",
16
+ "liquid",
17
+ "wipe",
18
+ "glass"
19
+ ];
20
+ var DEFAULT_VARIANT = "solid";
21
+ function resolveVariant(variant) {
22
+ if (variant != null && BUTTON_VARIANTS.includes(variant)) {
23
+ return variant;
24
+ }
25
+ return DEFAULT_VARIANT;
26
+ }
27
+ function variantClassName(variant) {
28
+ return `fx-btn fx-btn--${resolveVariant(variant)}`;
29
+ }
30
+ function Button({
31
+ variant = "solid",
32
+ children,
33
+ className,
34
+ style,
35
+ type = "button",
36
+ ...rest
37
+ }) {
38
+ const classes = [variantClassName(variant), className].filter(Boolean).join(" ");
39
+ return /* @__PURE__ */ jsx("button", { type, className: classes, style, ...rest, children });
40
+ }
41
+
42
+ export { BUTTON_VARIANTS, Button };
43
+ //# sourceMappingURL=index.js.map
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/variants.ts","../src/react/Button.tsx"],"names":[],"mappings":";;;;;;AACO,IAAM,eAAA,GAAkB;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF;AAIO,IAAM,eAAA,GAAiC,OAAA;AAEvC,SAAS,eAAe,OAAA,EAAiC;AAC9D,EAAA,IACE,OAAA,IAAW,IAAA,IACV,eAAA,CAAsC,QAAA,CAAS,OAAO,CAAA,EACvD;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AACA,EAAA,OAAO,eAAA;AACT;AAEO,SAAS,iBAAiB,OAAA,EAA0B;AACzD,EAAA,OAAO,CAAA,eAAA,EAAkB,cAAA,CAAe,OAAO,CAAC,CAAA,CAAA;AAClD;ACLO,SAAS,MAAA,CAAO;AAAA,EACrB,OAAA,GAAU,OAAA;AAAA,EACV,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA,GAAO,QAAA;AAAA,EACP,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,MAAM,OAAA,GAAU,CAAC,gBAAA,CAAiB,OAAO,CAAA,EAAG,SAAS,CAAA,CAClD,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AAEX,EAAA,uBACE,GAAA,CAAC,YAAO,IAAA,EAAY,SAAA,EAAW,SAAS,KAAA,EAAe,GAAG,MACvD,QAAA,EACH,CAAA;AAEJ","file":"index.js","sourcesContent":["/** Built-in button looks. Pass any of these as `variant`. */\nexport const BUTTON_VARIANTS = [\n 'solid',\n 'outline',\n 'soft',\n 'glow',\n 'neon',\n 'shimmer',\n 'chroma',\n 'liquid',\n 'wipe',\n 'glass',\n] as const\n\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number]\n\nexport const DEFAULT_VARIANT: ButtonVariant = 'solid'\n\nexport function resolveVariant(variant?: string): ButtonVariant {\n if (\n variant != null &&\n (BUTTON_VARIANTS as readonly string[]).includes(variant)\n ) {\n return variant as ButtonVariant\n }\n return DEFAULT_VARIANT\n}\n\nexport function variantClassName(variant?: string): string {\n return `fx-btn fx-btn--${resolveVariant(variant)}`\n}\n","'use client'\n\nimport {\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactNode,\n} from 'react'\nimport {\n BUTTON_VARIANTS,\n type ButtonVariant,\n variantClassName,\n} from '../core/variants'\nimport '../core/styles.css'\n\nexport type ButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'className' | 'style' | 'children'\n> & {\n /** Switch look by name: solid | outline | soft | glow | neon | shimmer | chroma | liquid | wipe | glass. */\n variant?: ButtonVariant | (string & {})\n children?: ReactNode\n className?: string\n style?: CSSProperties\n}\n\nexport function Button({\n variant = 'solid',\n children,\n className,\n style,\n type = 'button',\n ...rest\n}: ButtonProps) {\n const classes = [variantClassName(variant), className]\n .filter(Boolean)\n .join(' ')\n\n return (\n <button type={type} className={classes} style={style} {...rest}>\n {children}\n </button>\n )\n}\n\nexport { BUTTON_VARIANTS, type ButtonVariant }\nexport default Button\n"]}
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>@fxshelf/button-kit · script 直引示例</title>
7
+ <!--
8
+ @fxshelf/button-kit 浏览器直引示例:零构建工具,React UMD + button-kit 浏览器产物。
9
+
10
+ 资源走 npm CDN(需联网,包已发布为 @fxshelf/button-kit):
11
+ CSS: https://unpkg.com/@fxshelf/button-kit/dist/index.css
12
+ JS : https://unpkg.com/@fxshelf/button-kit/dist/button-kit.iife.js
13
+
14
+ 本地已 build 时也可改成相对路径:
15
+ ../dist/index.css
16
+ ../dist/button-kit.iife.js
17
+
18
+ 注意:不要用 jsDelivr 的 gh/.../dist 直链 —— dist/ 不进 Git,会 404。
19
+ 注意:React 需用 18.x 的 UMD 版本 —— React 19 起官方不再提供 UMD 构建。
20
+ -->
21
+ <link rel="stylesheet" href="https://unpkg.com/@fxshelf/button-kit/dist/index.css" />
22
+ <style>
23
+ * { box-sizing: border-box; }
24
+ body {
25
+ margin: 0;
26
+ min-height: 100vh;
27
+ display: grid;
28
+ place-items: center;
29
+ gap: 1rem;
30
+ padding: 2rem;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
32
+ "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
33
+ background: #0f0f12;
34
+ color: #fafafa;
35
+ }
36
+ h1 { margin: 0 0 0.5rem; font-size: 1.5rem; }
37
+ p { margin: 0 0 1.5rem; opacity: 0.7; font-size: 0.95rem; }
38
+ #app { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
39
+ </style>
40
+ </head>
41
+ <body>
42
+ <div>
43
+ <h1>Button Kit</h1>
44
+ <p>零构建:React 18 UMD + <code>button-kit.iife.js</code>,全局 <code>ButtonKit</code>。</p>
45
+ <div id="app"></div>
46
+ </div>
47
+
48
+ <script crossorigin src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
49
+ <script crossorigin src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
50
+ <script src="https://unpkg.com/@fxshelf/button-kit/dist/button-kit.iife.js"></script>
51
+
52
+ <script>
53
+ var Button = ButtonKit.Button
54
+ var variants = ['solid', 'outline', 'soft', 'glow', 'neon', 'shimmer', 'chroma', 'liquid', 'wipe', 'glass']
55
+
56
+ ReactDOM.createRoot(document.getElementById('app')).render(
57
+ React.createElement(
58
+ React.Fragment,
59
+ null,
60
+ variants.map(function (v) {
61
+ return React.createElement(Button, { key: v, variant: v }, v)
62
+ }),
63
+ ),
64
+ )
65
+ </script>
66
+ </body>
67
+ </html>
@@ -0,0 +1,72 @@
1
+ # 使用说明
2
+
3
+ ## 安装
4
+
5
+ ```bash
6
+ npm install @fxshelf/button-kit
7
+ ```
8
+
9
+ 记得引入样式:
10
+
11
+ ```ts
12
+ import '@fxshelf/button-kit/styles.css'
13
+ ```
14
+
15
+ ## React
16
+
17
+ ```tsx
18
+ import { Button } from '@fxshelf/button-kit'
19
+ import '@fxshelf/button-kit/styles.css'
20
+
21
+ <Button variant="glow">继续</Button>
22
+ ```
23
+
24
+ ## Vue
25
+
26
+ ```vue
27
+ <script setup lang="ts">
28
+ import { Button } from '@fxshelf/button-kit/vue'
29
+ import '@fxshelf/button-kit/styles.css'
30
+ </script>
31
+
32
+ <template>
33
+ <Button variant="neon">继续</Button>
34
+ </template>
35
+ ```
36
+
37
+ ## CDN(React 18 UMD)
38
+
39
+ 需先加载 React 18 UMD,再加载 IIFE,并引入 CSS。完整页面见 [CDN示例.html](./CDN示例.html)。
40
+
41
+ ```html
42
+ <link rel="stylesheet" href="https://unpkg.com/@fxshelf/button-kit/dist/index.css" />
43
+ <script crossorigin src="https://unpkg.com/react@18.3.1/umd/react.production.min.js"></script>
44
+ <script crossorigin src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
45
+ <script src="https://unpkg.com/@fxshelf/button-kit/dist/button-kit.iife.js"></script>
46
+ <script>
47
+ ReactDOM.createRoot(document.getElementById('app')).render(
48
+ React.createElement(ButtonKit.Button, { variant: 'glow' }, '继续'),
49
+ )
50
+ </script>
51
+ ```
52
+
53
+ ## 复制源码
54
+
55
+ 拷贝 `src/core`(含 `styles.css`)与 `src/react` 或 `src/vue`,保持同级目录即可。
56
+
57
+ ## variant
58
+
59
+ | 值 | 效果 |
60
+ |----|------|
61
+ | `solid` | 实心深色 |
62
+ | `outline` | 描边,悬停填实 |
63
+ | `soft` | 浅色软按钮 |
64
+ | `glow` | 呼吸光晕 |
65
+ | `neon` | 霓虹描边 |
66
+ | `shimmer` | 悬停扫光 |
67
+ | `chroma` | 炫彩流光(默认动画);hover 贴边高斯光晕 |
68
+ | `liquid` | 底部液体升起填充 |
69
+ | `wipe` | 斜向擦除填充 |
70
+ | `glass` | 毛玻璃半透明 |
71
+
72
+ 未知字符串会回退到 `solid`。
@@ -0,0 +1,14 @@
1
+ # 动效说明(专业)
2
+
3
+ Button Kit 是一组纯 CSS 按钮变体:共享 `.fx-btn` 基类,按 `variant` 挂载 `.fx-btn--*` 修饰符。
4
+
5
+ - `chroma`:默认渐变流光;hover 时 `::before`(`inset: -4px`)以轻微 blur 贴边发光
6
+ - `liquid`:`::before` 自下而上升起,hover 后轻微波浪形变
7
+ - `wipe`:斜向层从左擦入
8
+ - `glass`:半透明 + `backdrop-filter`
9
+ - `glow`:无限 `box-shadow` 脉冲
10
+ - `shimmer`:`::before` 斜向高光平移
11
+ - `neon`:描边 + 外发光 + 文字阴影
12
+ - 其余为 hover / active 过渡
13
+
14
+ 无 JS 动画循环(除 CSS `@keyframes`),无 Framer / GSAP。
@@ -0,0 +1,5 @@
1
+ # 动效说明(大白话)
2
+
3
+ 传一个字符串(比如 `"liquid"`),按钮就换一套样子。
4
+
5
+ 现在有:实心、描边、软色、发光、霓虹、扫光、炫彩、液体升起、斜擦填充、毛玻璃。不依赖动画库。