react-tilt-button 0.0.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.
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # React Tilt Button
2
+
3
+ > A physical, 3D tactile React button component with tilt, squish, and real depth.
4
+
5
+ đź”— **Live Demo:** https://react-tilt-button.vercel.app/
6
+
7
+ ![React Tilt Button Preview](https://react-tilt-button.vercel.app/og-image.png)
8
+
9
+ Features:
10
+
11
+ - Tilts on hover (left / middle / right)
12
+ - Squishes on press
13
+ - Has a visible “side wall” (depth)
14
+ - Enforces physical constraints so it never breaks
15
+ - Supports **predefined style variants**
16
+ - Is fully configurable via props
17
+
18
+ Inspired by `react-awesome-button`, but implemented as a small, dependency-free component.
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install react-tilt-button
26
+ ```
27
+
28
+ ```jsx
29
+ import { TiltButton } from 'react-tilt-button';
30
+ import '/node_modules/react-tilt-button/dist/react-tilt-button.css';
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Basic Usage
36
+
37
+ ```jsx
38
+ <TiltButton onClick={() => alert('Clicked!')}>Click me</TiltButton>
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Using Variants
44
+
45
+ Variants are **predefined visual styles** (material / theme presets).
46
+
47
+ ```jsx
48
+ <TiltButton variant="solid">Solid</TiltButton>
49
+ <TiltButton variant="outline">Outline</TiltButton>
50
+ <TiltButton variant="arcade">Arcade</TiltButton>
51
+ <TiltButton variant="carbon">Carbon</TiltButton>
52
+ <TiltButton variant="warning">Warning</TiltButton>
53
+ ```
54
+
55
+ You can still override any value manually:
56
+
57
+ ```jsx
58
+ <TiltButton
59
+ variant='solid'
60
+ surfaceColor='#10b981'
61
+ >
62
+ Custom Green
63
+ </TiltButton>
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Demo
69
+
70
+ Try it live here:
71
+
72
+ 👉 **https://react-tilt-button.vercel.app/**
73
+
74
+ The demo lets you:
75
+
76
+ - Test all variants
77
+ - Change geometry (depth, radius, tilt, etc.)
78
+ - See physical constraints in action
79
+ - Copy settings for your own usage
80
+
81
+ ## Full Example
82
+
83
+ ```jsx
84
+ <TiltButton
85
+ variant='arcade'
86
+ width={400}
87
+ height={120}
88
+ elevation={20}
89
+ pressInset={10}
90
+ tilt={4}
91
+ radius={14}
92
+ motion={160}
93
+ >
94
+ My Button
95
+ </TiltButton>
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Physical Constraints (Important)
101
+
102
+ The component automatically clamps values:
103
+
104
+ - `elevation` ≤ `height * 0.3`
105
+ - `pressInset` ≤ `elevation`
106
+ - `tilt` ≤ `elevation / 9`
107
+ - `radius` ≤ `(height - elevation) / 4`
108
+
109
+ So the button:
110
+
111
+ - Never crashes
112
+ - Never inverts
113
+ - Never visually breaks
114
+
115
+ ---
116
+
117
+ ## Props
118
+
119
+ ### Core
120
+
121
+ | Prop | Type | Default |
122
+ | ---------- | --------- | ------- |
123
+ | `children` | ReactNode | — |
124
+ | `onClick` | function | — |
125
+ | `disabled` | boolean | `false` |
126
+
127
+ ---
128
+
129
+ ### Variant
130
+
131
+ | Prop | Type | Default | Description |
132
+ | --------- | ------ | ------- | ------------------------------ |
133
+ | `variant` | string | `solid` | Predefined visual style preset |
134
+
135
+ ---
136
+
137
+ ### Geometry
138
+
139
+ | Prop | Type | Default | Notes |
140
+ | ------------ | ---------------- | ------- | ------------------------------ |
141
+ | `width` | number \| string | `260` | No max |
142
+ | `height` | number \| string | `64` | No max |
143
+ | `elevation` | number | `14` | Clamped to `height * 0.3` |
144
+ | `pressInset` | number | `5` | Clamped to `<= elevation` |
145
+ | `tilt` | number | `2` | Clamped to `<= elevation / 9` |
146
+ | `radius` | number | `14` | Clamped to `<= faceHeight / 4` |
147
+ | `motion` | number (ms) | `160` | Animation speed |
148
+
149
+ ---
150
+
151
+ ### Colors (Optional Overrides)
152
+
153
+ These override the selected variant.
154
+
155
+ | Prop |
156
+ | -------------- |
157
+ | `surfaceColor` |
158
+ | `sideColor` |
159
+ | `textColor` |
160
+
161
+ ---
162
+
163
+ ### Border (Optional Overrides)
164
+
165
+ | Prop |
166
+ | ------------- |
167
+ | `bordered` |
168
+ | `borderColor` |
169
+ | `borderWidth` |
170
+
171
+ ---
172
+
173
+ ### Misc
174
+
175
+ | Prop | Description |
176
+ | ----------- | ------------------------- |
177
+ | `className` | Extra classes |
178
+ | `style` | Merged into inline styles |
179
+ | `...props` | Passed to `<button>` |
180
+
181
+ ---
182
+
183
+ ## Behavior
184
+
185
+ - Action fires on **mouse release**
186
+ - Hover is split into left / middle / right zones
187
+ - This is a **physical UI primitive**, not a flat semantic button
188
+
189
+ ---
190
+
191
+ ## Styling
192
+
193
+ All visuals are driven by CSS variables:
194
+
195
+ - `--button-raise-level`
196
+ - `--press-inset`
197
+ - `--button-hover-pressure`
198
+ - `--radius`
199
+ - `--surface-color`
200
+ - `--side-color`
201
+ - `--text-color`
202
+ - `--border-color`
203
+ - `--border-width`
204
+
205
+ So you can theme it externally if needed.
206
+
207
+ ---
208
+
209
+ ## Philosophy
210
+
211
+ This is not a flat UI button.
212
+
213
+ It is a **physical, tactile UI primitive** that behaves like an object:
214
+
215
+ - It has depth
216
+ - It deforms
217
+ - It squishes
218
+ - It reacts to pressure
219
+
220
+ ---
221
+
222
+ ## License
223
+
224
+ Use it. Ship it. Modify it.
@@ -0,0 +1 @@
1
+ .soft-btn{--button-raise-level: 14px;--press-inset: 5px;--button-hover-pressure: 2;--transform-speed: .16s;--radius: 14px;--surface-color: #f3f4f6;--side-color: #d1d5db;--text-color: #111827;--border-color: rgba(0, 0, 0, .35);--border-width: 2px;position:relative;border:none;background:transparent;padding:0;cursor:pointer;-webkit-user-select:none;user-select:none}.soft-btn__wrapper{position:relative;display:block;width:100%;height:100%;transform-style:preserve-3d}.soft-btn__wrapper:before{content:"";position:absolute;left:0;right:0;bottom:0;height:calc(100% - var(--button-raise-level));background:var(--side-color);border-bottom-left-radius:var(--radius);border-bottom-right-radius:var(--radius);border-radius:var(--radius)}.soft-btn__content{position:relative;width:100%;height:calc(100% - var(--button-raise-level));background:var(--surface-color);color:var(--text-color);border-radius:var(--radius);display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:600;transform:translateY(0);transition:transform var(--transform-speed) ease-out;will-change:transform;backface-visibility:hidden;transform-origin:center}.soft-btn__inner{display:inline-flex;align-items:center;gap:10px}.soft-btn--bordered .soft-btn__content{box-shadow:inset 0 0 0 var(--border-width) var(--border-color)}.soft-btn--middle .soft-btn__content{transform:translateY(calc(1px * var(--button-hover-pressure)))}.soft-btn--left .soft-btn__content{transform:skewY(calc(-1deg * var(--button-hover-pressure)))}.soft-btn--right .soft-btn__content{transform:skewY(calc(1deg * var(--button-hover-pressure)))}.soft-btn--active .soft-btn__content{transform:translateY(var(--press-inset));transition:transform calc(var(--transform-speed) * .8) ease-out}.soft-btn--disabled{opacity:.6;pointer-events:none}
@@ -0,0 +1,424 @@
1
+ import me, { useRef as _e, useState as oe } from "react";
2
+ var U = { exports: {} }, S = {};
3
+ var ne;
4
+ function pe() {
5
+ if (ne) return S;
6
+ ne = 1;
7
+ var u = /* @__PURE__ */ Symbol.for("react.transitional.element"), f = /* @__PURE__ */ Symbol.for("react.fragment");
8
+ function a(i, s, c) {
9
+ var d = null;
10
+ if (c !== void 0 && (d = "" + c), s.key !== void 0 && (d = "" + s.key), "key" in s) {
11
+ c = {};
12
+ for (var b in s)
13
+ b !== "key" && (c[b] = s[b]);
14
+ } else c = s;
15
+ return s = c.ref, {
16
+ $$typeof: u,
17
+ type: i,
18
+ key: d,
19
+ ref: s !== void 0 ? s : null,
20
+ props: c
21
+ };
22
+ }
23
+ return S.Fragment = f, S.jsx = a, S.jsxs = a, S;
24
+ }
25
+ var N = {};
26
+ var ae;
27
+ function Ee() {
28
+ return ae || (ae = 1, process.env.NODE_ENV !== "production" && (function() {
29
+ function u(e) {
30
+ if (e == null) return null;
31
+ if (typeof e == "function")
32
+ return e.$$typeof === Q ? null : e.displayName || e.name || null;
33
+ if (typeof e == "string") return e;
34
+ switch (e) {
35
+ case C:
36
+ return "Fragment";
37
+ case T:
38
+ return "Profiler";
39
+ case J:
40
+ return "StrictMode";
41
+ case h:
42
+ return "Suspense";
43
+ case W:
44
+ return "SuspenseList";
45
+ case G:
46
+ return "Activity";
47
+ }
48
+ if (typeof e == "object")
49
+ switch (typeof e.tag == "number" && console.error(
50
+ "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
51
+ ), e.$$typeof) {
52
+ case q:
53
+ return "Portal";
54
+ case $:
55
+ return e.displayName || "Context";
56
+ case X:
57
+ return (e._context.displayName || "Context") + ".Consumer";
58
+ case z:
59
+ var r = e.render;
60
+ return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
61
+ case E:
62
+ return r = e.displayName || null, r !== null ? r : u(e.type) || "Memo";
63
+ case v:
64
+ r = e._payload, e = e._init;
65
+ try {
66
+ return u(e(r));
67
+ } catch {
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+ function f(e) {
73
+ return "" + e;
74
+ }
75
+ function a(e) {
76
+ try {
77
+ f(e);
78
+ var r = !1;
79
+ } catch {
80
+ r = !0;
81
+ }
82
+ if (r) {
83
+ r = console;
84
+ var t = r.error, o = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
85
+ return t.call(
86
+ r,
87
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
88
+ o
89
+ ), f(e);
90
+ }
91
+ }
92
+ function i(e) {
93
+ if (e === C) return "<>";
94
+ if (typeof e == "object" && e !== null && e.$$typeof === v)
95
+ return "<...>";
96
+ try {
97
+ var r = u(e);
98
+ return r ? "<" + r + ">" : "<...>";
99
+ } catch {
100
+ return "<...>";
101
+ }
102
+ }
103
+ function s() {
104
+ var e = A.A;
105
+ return e === null ? null : e.getOwner();
106
+ }
107
+ function c() {
108
+ return Error("react-stack-top-frame");
109
+ }
110
+ function d(e) {
111
+ if (m.call(e, "key")) {
112
+ var r = Object.getOwnPropertyDescriptor(e, "key").get;
113
+ if (r && r.isReactWarning) return !1;
114
+ }
115
+ return e.key !== void 0;
116
+ }
117
+ function b(e, r) {
118
+ function t() {
119
+ I || (I = !0, console.error(
120
+ "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
121
+ r
122
+ ));
123
+ }
124
+ t.isReactWarning = !0, Object.defineProperty(e, "key", {
125
+ get: t,
126
+ configurable: !0
127
+ });
128
+ }
129
+ function x() {
130
+ var e = u(this.type);
131
+ return Y[e] || (Y[e] = !0, console.error(
132
+ "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
133
+ )), e = this.props.ref, e !== void 0 ? e : null;
134
+ }
135
+ function _(e, r, t, o, R, w) {
136
+ var n = t.ref;
137
+ return e = {
138
+ $$typeof: M,
139
+ type: e,
140
+ key: r,
141
+ props: t,
142
+ _owner: o
143
+ }, (n !== void 0 ? n : null) !== null ? Object.defineProperty(e, "ref", {
144
+ enumerable: !1,
145
+ get: x
146
+ }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
147
+ configurable: !1,
148
+ enumerable: !1,
149
+ writable: !0,
150
+ value: 0
151
+ }), Object.defineProperty(e, "_debugInfo", {
152
+ configurable: !1,
153
+ enumerable: !1,
154
+ writable: !0,
155
+ value: null
156
+ }), Object.defineProperty(e, "_debugStack", {
157
+ configurable: !1,
158
+ enumerable: !1,
159
+ writable: !0,
160
+ value: R
161
+ }), Object.defineProperty(e, "_debugTask", {
162
+ configurable: !1,
163
+ enumerable: !1,
164
+ writable: !0,
165
+ value: w
166
+ }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
167
+ }
168
+ function P(e, r, t, o, R, w) {
169
+ var n = r.children;
170
+ if (n !== void 0)
171
+ if (o)
172
+ if (H(n)) {
173
+ for (o = 0; o < n.length; o++)
174
+ j(n[o]);
175
+ Object.freeze && Object.freeze(n);
176
+ } else
177
+ console.error(
178
+ "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
179
+ );
180
+ else j(n);
181
+ if (m.call(r, "key")) {
182
+ n = u(e);
183
+ var l = Object.keys(r).filter(function(Z) {
184
+ return Z !== "key";
185
+ });
186
+ o = 0 < l.length ? "{key: someKey, " + l.join(": ..., ") + ": ...}" : "{key: someKey}", L[n + o] || (l = 0 < l.length ? "{" + l.join(": ..., ") + ": ...}" : "{}", console.error(
187
+ `A props object containing a "key" prop is being spread into JSX:
188
+ let props = %s;
189
+ <%s {...props} />
190
+ React keys must be passed directly to JSX without using spread:
191
+ let props = %s;
192
+ <%s key={someKey} {...props} />`,
193
+ o,
194
+ n,
195
+ l,
196
+ n
197
+ ), L[n + o] = !0);
198
+ }
199
+ if (n = null, t !== void 0 && (a(t), n = "" + t), d(r) && (a(r.key), n = "" + r.key), "key" in r) {
200
+ t = {};
201
+ for (var O in r)
202
+ O !== "key" && (t[O] = r[O]);
203
+ } else t = r;
204
+ return n && b(
205
+ t,
206
+ typeof e == "function" ? e.displayName || e.name || "Unknown" : e
207
+ ), _(
208
+ e,
209
+ n,
210
+ t,
211
+ s(),
212
+ R,
213
+ w
214
+ );
215
+ }
216
+ function j(e) {
217
+ g(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === v && (e._payload.status === "fulfilled" ? g(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
218
+ }
219
+ function g(e) {
220
+ return typeof e == "object" && e !== null && e.$$typeof === M;
221
+ }
222
+ var p = me, M = /* @__PURE__ */ Symbol.for("react.transitional.element"), q = /* @__PURE__ */ Symbol.for("react.portal"), C = /* @__PURE__ */ Symbol.for("react.fragment"), J = /* @__PURE__ */ Symbol.for("react.strict_mode"), T = /* @__PURE__ */ Symbol.for("react.profiler"), X = /* @__PURE__ */ Symbol.for("react.consumer"), $ = /* @__PURE__ */ Symbol.for("react.context"), z = /* @__PURE__ */ Symbol.for("react.forward_ref"), h = /* @__PURE__ */ Symbol.for("react.suspense"), W = /* @__PURE__ */ Symbol.for("react.suspense_list"), E = /* @__PURE__ */ Symbol.for("react.memo"), v = /* @__PURE__ */ Symbol.for("react.lazy"), G = /* @__PURE__ */ Symbol.for("react.activity"), Q = /* @__PURE__ */ Symbol.for("react.client.reference"), A = p.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, m = Object.prototype.hasOwnProperty, H = Array.isArray, k = console.createTask ? console.createTask : function() {
223
+ return null;
224
+ };
225
+ p = {
226
+ react_stack_bottom_frame: function(e) {
227
+ return e();
228
+ }
229
+ };
230
+ var I, Y = {}, D = p.react_stack_bottom_frame.bind(
231
+ p,
232
+ c
233
+ )(), F = k(i(c)), L = {};
234
+ N.Fragment = C, N.jsx = function(e, r, t) {
235
+ var o = 1e4 > A.recentlyCreatedOwnerStacks++;
236
+ return P(
237
+ e,
238
+ r,
239
+ t,
240
+ !1,
241
+ o ? Error("react-stack-top-frame") : D,
242
+ o ? k(i(e)) : F
243
+ );
244
+ }, N.jsxs = function(e, r, t) {
245
+ var o = 1e4 > A.recentlyCreatedOwnerStacks++;
246
+ return P(
247
+ e,
248
+ r,
249
+ t,
250
+ !0,
251
+ o ? Error("react-stack-top-frame") : D,
252
+ o ? k(i(e)) : F
253
+ );
254
+ };
255
+ })()), N;
256
+ }
257
+ var se;
258
+ function ve() {
259
+ return se || (se = 1, process.env.NODE_ENV === "production" ? U.exports = pe() : U.exports = Ee()), U.exports;
260
+ }
261
+ var V = ve();
262
+ const le = {
263
+ solid: {
264
+ surfaceColor: "#3b82f6",
265
+ sideColor: "#1d4ed8",
266
+ textColor: "#ffffff",
267
+ bordered: !1,
268
+ borderColor: "transparent",
269
+ borderWidth: 0
270
+ },
271
+ outline: {
272
+ surfaceColor: "#ffffff",
273
+ sideColor: "#2563eb",
274
+ textColor: "#2563eb",
275
+ bordered: !0,
276
+ borderColor: "#2563eb",
277
+ borderWidth: 3
278
+ },
279
+ dark: {
280
+ surfaceColor: "#181818",
281
+ sideColor: "#494949",
282
+ textColor: "#e5e7eb",
283
+ bordered: !0,
284
+ borderColor: "#5e5e5e",
285
+ borderWidth: 3
286
+ },
287
+ arcade: {
288
+ surfaceColor: "#22b8c7",
289
+ sideColor: "#e5dd4a",
290
+ textColor: "#fef08a",
291
+ bordered: !0,
292
+ borderColor: "#fef08a",
293
+ borderWidth: 3
294
+ },
295
+ gum: {
296
+ surfaceColor: "#f472b6",
297
+ sideColor: "#db2777",
298
+ textColor: "#ffffff",
299
+ bordered: !1,
300
+ borderColor: "transparent",
301
+ borderWidth: 0
302
+ },
303
+ carbon: {
304
+ surfaceColor: "#2a2a37",
305
+ sideColor: "#8b5e3c",
306
+ textColor: "#c4a484",
307
+ bordered: !0,
308
+ borderColor: "#8b5f39",
309
+ borderWidth: 4
310
+ },
311
+ warning: {
312
+ surfaceColor: "#2c2c39",
313
+ sideColor: "#b22b3b",
314
+ textColor: "#fff7ed",
315
+ bordered: !0,
316
+ borderColor: "#d9445b",
317
+ borderWidth: 4
318
+ },
319
+ steel: {
320
+ surfaceColor: "#cbd5e1",
321
+ sideColor: "#64748b",
322
+ textColor: "#020617",
323
+ bordered: !0,
324
+ borderColor: "#475569",
325
+ borderWidth: 2
326
+ },
327
+ gold: {
328
+ surfaceColor: "#ffcf10",
329
+ sideColor: "#d29000",
330
+ textColor: "#422006",
331
+ bordered: !0,
332
+ borderColor: "#fff0a8",
333
+ borderWidth: 2
334
+ },
335
+ lavender: {
336
+ surfaceColor: "#cec3fd",
337
+ sideColor: "#b489ff",
338
+ textColor: "#2e1065",
339
+ bordered: !1,
340
+ borderColor: "#a36eff",
341
+ borderWidth: 4
342
+ }
343
+ };
344
+ function B(u, f, a) {
345
+ return Math.max(f, Math.min(a, u));
346
+ }
347
+ function Te({
348
+ children: u,
349
+ onClick: f,
350
+ disabled: a = !1,
351
+ variant: i = "solid",
352
+ elevation: s = 14,
353
+ pressInset: c = 5,
354
+ tilt: d = 2,
355
+ motion: b = 160,
356
+ width: x = 260,
357
+ height: _ = 64,
358
+ radius: P = 14,
359
+ surfaceColor: j,
360
+ sideColor: g,
361
+ textColor: p,
362
+ bordered: M,
363
+ borderColor: q,
364
+ borderWidth: C,
365
+ className: J = "",
366
+ style: T,
367
+ ...X
368
+ }) {
369
+ const $ = _e(null), [z, h] = oe(!1), [W, E] = oe(null), v = Math.max(0, Number(_) || 0), G = Math.max(0, Number(s) || 0), A = v * 0.3, m = B(G, 0, A), H = Math.max(0, Number(c) || 0), k = B(H, 0, m), I = Math.max(0, Number(d) || 0), Y = Number((m / 9).toFixed(2)), D = B(I, 0, Y), F = v - m, L = Math.max(0, Math.floor(F / 4)), e = Math.max(0, Number(P) || 0), r = B(e, 0, L), t = Math.max(0, Number(b) || 0), o = (y) => {
370
+ if (a) return;
371
+ const K = $.current;
372
+ if (!K) return;
373
+ const ee = K.getBoundingClientRect(), re = y.clientX - ee.left, te = ee.width || 1;
374
+ re < te * 0.33 ? E("left") : re > te * 0.66 ? E("right") : E("middle");
375
+ }, R = () => {
376
+ E(null), h(!1);
377
+ }, w = (y) => {
378
+ a || y.button === 0 && h(!0);
379
+ }, n = (y) => {
380
+ a || (h(!1), f && f(y));
381
+ }, l = le[i] || le.solid, O = j ?? l.surfaceColor, Z = g ?? l.sideColor, ce = p ?? l.textColor, ue = M ?? l.bordered, fe = q ?? l.borderColor, ie = C ?? l.borderWidth, de = {
382
+ ...{
383
+ "--button-raise-level": `${m}px`,
384
+ "--press-inset": `${k}px`,
385
+ "--button-hover-pressure": D,
386
+ "--transform-speed": `${t}ms`,
387
+ "--radius": `${r}px`,
388
+ "--surface-color": O,
389
+ "--side-color": Z,
390
+ "--text-color": ce,
391
+ "--border-color": fe,
392
+ "--border-width": `${ie}px`,
393
+ width: typeof x == "number" ? `${x}px` : x,
394
+ height: typeof _ == "number" ? `${_}px` : _
395
+ },
396
+ ...T && typeof T == "object" ? T : {}
397
+ }, be = [
398
+ "soft-btn",
399
+ z && "soft-btn--active",
400
+ W && `soft-btn--${W}`,
401
+ a && "soft-btn--disabled",
402
+ ue && "soft-btn--bordered",
403
+ J
404
+ ].filter(Boolean).join(" ");
405
+ return /* @__PURE__ */ V.jsx(
406
+ "button",
407
+ {
408
+ ...X,
409
+ ref: $,
410
+ className: be,
411
+ style: de,
412
+ onMouseMove: o,
413
+ onMouseLeave: R,
414
+ onMouseDown: w,
415
+ onMouseUp: n,
416
+ disabled: a,
417
+ children: /* @__PURE__ */ V.jsx("span", { className: "soft-btn__wrapper", children: /* @__PURE__ */ V.jsx("span", { className: "soft-btn__content", children: /* @__PURE__ */ V.jsx("span", { className: "soft-btn__inner", children: u }) }) })
418
+ }
419
+ );
420
+ }
421
+ export {
422
+ Te as TiltButton,
423
+ le as TiltButtonVariants
424
+ };
@@ -0,0 +1,6 @@
1
+ (function(i,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],d):(i=typeof globalThis<"u"?globalThis:i||self,d(i["react-tilt-button"]={},i.React))})(this,(function(i,d){"use strict";var g={exports:{}},C={};var re;function ue(){if(re)return C;re=1;var u=Symbol.for("react.transitional.element"),f=Symbol.for("react.fragment");function a(b,s,c){var m=null;if(c!==void 0&&(m=""+c),s.key!==void 0&&(m=""+s.key),"key"in s){c={};for(var p in s)p!=="key"&&(c[p]=s[p])}else c=s;return s=c.ref,{$$typeof:u,type:b,key:m,ref:s!==void 0?s:null,props:c}}return C.Fragment=f,C.jsx=a,C.jsxs=a,C}var h={};var te;function fe(){return te||(te=1,process.env.NODE_ENV!=="production"&&(function(){function u(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ne?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case y:return"Fragment";case O:return"Profiler";case q:return"StrictMode";case S:return"Suspense";case L:return"SuspenseList";case Q:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case G:return"Portal";case F:return e.displayName||"Context";case H:return(e._context.displayName||"Context")+".Consumer";case Z:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case R:return r=e.displayName||null,r!==null?r:u(e.type)||"Memo";case T:r=e._payload,e=e._init;try{return u(e(r))}catch{}}return null}function f(e){return""+e}function a(e){try{f(e);var r=!1}catch{r=!0}if(r){r=console;var t=r.error,o=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return t.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",o),f(e)}}function b(e){if(e===y)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===T)return"<...>";try{var r=u(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function s(){var e=k.A;return e===null?null:e.getOwner()}function c(){return Error("react-stack-top-frame")}function m(e){if(_.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function p(e,r){function t(){U||(U=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}function A(){var e=u(this.type);return V[e]||(V[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function v(e,r,t,o,x,N){var n=t.ref;return e={$$typeof:D,type:e,key:r,props:t,_owner:o},(n!==void 0?n:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:A}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:x}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:N}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function I(e,r,t,o,x,N){var n=r.children;if(n!==void 0)if(o)if(K(n)){for(o=0;o<n.length;o++)Y(n[o]);Object.freeze&&Object.freeze(n)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else Y(n);if(_.call(r,"key")){n=u(e);var l=Object.keys(r).filter(function(ee){return ee!=="key"});o=0<l.length?"{key: someKey, "+l.join(": ..., ")+": ...}":"{key: someKey}",X[n+o]||(l=0<l.length?"{"+l.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
+ let props = %s;
3
+ <%s {...props} />
4
+ React keys must be passed directly to JSX without using spread:
5
+ let props = %s;
6
+ <%s key={someKey} {...props} />`,o,n,l,n),X[n+o]=!0)}if(n=null,t!==void 0&&(a(t),n=""+t),m(r)&&(a(r.key),n=""+r.key),"key"in r){t={};for(var P in r)P!=="key"&&(t[P]=r[P])}else t=r;return n&&p(t,typeof e=="function"?e.displayName||e.name||"Unknown":e),v(e,n,t,s(),x,N)}function Y(e){$(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===T&&(e._payload.status==="fulfilled"?$(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function $(e){return typeof e=="object"&&e!==null&&e.$$typeof===D}var E=d,D=Symbol.for("react.transitional.element"),G=Symbol.for("react.portal"),y=Symbol.for("react.fragment"),q=Symbol.for("react.strict_mode"),O=Symbol.for("react.profiler"),H=Symbol.for("react.consumer"),F=Symbol.for("react.context"),Z=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),L=Symbol.for("react.suspense_list"),R=Symbol.for("react.memo"),T=Symbol.for("react.lazy"),Q=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),k=E.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,_=Object.prototype.hasOwnProperty,K=Array.isArray,w=console.createTask?console.createTask:function(){return null};E={react_stack_bottom_frame:function(e){return e()}};var U,V={},B=E.react_stack_bottom_frame.bind(E,c)(),J=w(b(c)),X={};h.Fragment=y,h.jsx=function(e,r,t){var o=1e4>k.recentlyCreatedOwnerStacks++;return I(e,r,t,!1,o?Error("react-stack-top-frame"):B,o?w(b(e)):J)},h.jsxs=function(e,r,t){var o=1e4>k.recentlyCreatedOwnerStacks++;return I(e,r,t,!0,o?Error("react-stack-top-frame"):B,o?w(b(e)):J)}})()),h}var oe;function ie(){return oe||(oe=1,process.env.NODE_ENV==="production"?g.exports=ue():g.exports=fe()),g.exports}var M=ie();const z={solid:{surfaceColor:"#3b82f6",sideColor:"#1d4ed8",textColor:"#ffffff",bordered:!1,borderColor:"transparent",borderWidth:0},outline:{surfaceColor:"#ffffff",sideColor:"#2563eb",textColor:"#2563eb",bordered:!0,borderColor:"#2563eb",borderWidth:3},dark:{surfaceColor:"#181818",sideColor:"#494949",textColor:"#e5e7eb",bordered:!0,borderColor:"#5e5e5e",borderWidth:3},arcade:{surfaceColor:"#22b8c7",sideColor:"#e5dd4a",textColor:"#fef08a",bordered:!0,borderColor:"#fef08a",borderWidth:3},gum:{surfaceColor:"#f472b6",sideColor:"#db2777",textColor:"#ffffff",bordered:!1,borderColor:"transparent",borderWidth:0},carbon:{surfaceColor:"#2a2a37",sideColor:"#8b5e3c",textColor:"#c4a484",bordered:!0,borderColor:"#8b5f39",borderWidth:4},warning:{surfaceColor:"#2c2c39",sideColor:"#b22b3b",textColor:"#fff7ed",bordered:!0,borderColor:"#d9445b",borderWidth:4},steel:{surfaceColor:"#cbd5e1",sideColor:"#64748b",textColor:"#020617",bordered:!0,borderColor:"#475569",borderWidth:2},gold:{surfaceColor:"#ffcf10",sideColor:"#d29000",textColor:"#422006",bordered:!0,borderColor:"#fff0a8",borderWidth:2},lavender:{surfaceColor:"#cec3fd",sideColor:"#b489ff",textColor:"#2e1065",bordered:!1,borderColor:"#a36eff",borderWidth:4}};function W(u,f,a){return Math.max(f,Math.min(a,u))}function de({children:u,onClick:f,disabled:a=!1,variant:b="solid",elevation:s=14,pressInset:c=5,tilt:m=2,motion:p=160,width:A=260,height:v=64,radius:I=14,surfaceColor:Y,sideColor:$,textColor:E,bordered:D,borderColor:G,borderWidth:y,className:q="",style:O,...H}){const F=d.useRef(null),[Z,S]=d.useState(!1),[L,R]=d.useState(null),T=Math.max(0,Number(v)||0),Q=Math.max(0,Number(s)||0),k=T*.3,_=W(Q,0,k),K=Math.max(0,Number(c)||0),w=W(K,0,_),U=Math.max(0,Number(m)||0),V=Number((_/9).toFixed(2)),B=W(U,0,V),J=T-_,X=Math.max(0,Math.floor(J/4)),e=Math.max(0,Number(I)||0),r=W(e,0,X),t=Math.max(0,Number(p)||0),o=j=>{if(a)return;const ae=F.current;if(!ae)return;const se=ae.getBoundingClientRect(),le=j.clientX-se.left,ce=se.width||1;le<ce*.33?R("left"):le>ce*.66?R("right"):R("middle")},x=()=>{R(null),S(!1)},N=j=>{a||j.button===0&&S(!0)},n=j=>{a||(S(!1),f&&f(j))},l=z[b]||z.solid,P=Y??l.surfaceColor,ee=$??l.sideColor,be=E??l.textColor,me=D??l.bordered,pe=G??l.borderColor,_e=y??l.borderWidth,ve={...{"--button-raise-level":`${_}px`,"--press-inset":`${w}px`,"--button-hover-pressure":B,"--transform-speed":`${t}ms`,"--radius":`${r}px`,"--surface-color":P,"--side-color":ee,"--text-color":be,"--border-color":pe,"--border-width":`${_e}px`,width:typeof A=="number"?`${A}px`:A,height:typeof v=="number"?`${v}px`:v},...O&&typeof O=="object"?O:{}},Ee=["soft-btn",Z&&"soft-btn--active",L&&`soft-btn--${L}`,a&&"soft-btn--disabled",me&&"soft-btn--bordered",q].filter(Boolean).join(" ");return M.jsx("button",{...H,ref:F,className:Ee,style:ve,onMouseMove:o,onMouseLeave:x,onMouseDown:N,onMouseUp:n,disabled:a,children:M.jsx("span",{className:"soft-btn__wrapper",children:M.jsx("span",{className:"soft-btn__content",children:M.jsx("span",{className:"soft-btn__inner",children:u})})})})}i.TiltButton=de,i.TiltButtonVariants=z,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "react-tilt-button",
3
+ "version": "0.0.6",
4
+ "description": "",
5
+ "license": "MIT",
6
+ "author": "archisvaze",
7
+ "keywords": [],
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "main": "./dist/react-tilt-button.umd.js",
13
+ "module": "./dist/react-tilt-button.es.js",
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/react-tilt-button.es.js",
17
+ "require": "./dist/react-tilt-button.umd.js"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "vite build",
23
+ "test": "vitest run",
24
+ "watch": "vitest",
25
+ "coverage": "vitest run --coverage"
26
+ },
27
+ "browserslist": {
28
+ "production": [
29
+ ">0.2%",
30
+ "not dead",
31
+ "not op_mini all"
32
+ ],
33
+ "development": [
34
+ "last 1 chrome version",
35
+ "last 1 firefox version",
36
+ "last 1 safari version"
37
+ ]
38
+ },
39
+ "eslintConfig": {
40
+ "env": {
41
+ "browser": true,
42
+ "node": true,
43
+ "es2020": true
44
+ },
45
+ "extends": [
46
+ "eslint:recommended",
47
+ "plugin:react/recommended"
48
+ ],
49
+ "parserOptions": {
50
+ "sourceType": "module"
51
+ }
52
+ },
53
+ "devDependencies": {
54
+ "@vitejs/plugin-react": "^5.1.2",
55
+ "react": "^19.2.3",
56
+ "react-dom": "^19.2.3",
57
+ "vite": "^7.3.1"
58
+ },
59
+ "peerDependencies": {
60
+ "react": "^19.2.3",
61
+ "react-dom": "^19.2.3"
62
+ }
63
+ }