floaty-widget 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 el_jijuna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # Floaty Widget
2
+
3
+ A beautiful, draggable, and collapsible floating widget library built with React 19, TypeScript, and Vite.
4
+
5
+ ## Features
6
+
7
+ ✨ **Draggable Header** - Click and drag the header to move the component anywhere on the screen
8
+ 📍 **Pin/Unpin** - Lock the component in place with the pin button to prevent dragging
9
+ 🔽 **Expand/Collapse** - Smooth animations when toggling content visibility
10
+ 🎨 **Customizable** - Flexible styling with CSS variables and inline styles
11
+ 📱 **Responsive** - Works seamlessly on different screen sizes
12
+ ♿ **Accessible** - Built with ARIA labels and semantic HTML
13
+ 🚀 **Optimized** - Tree-shaking enabled, minimal bundle size
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install floaty-widget
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```tsx
24
+ import { Floaty } from 'floaty-widget';
25
+ import 'floaty-widget/dist/style.css';
26
+
27
+ export function App() {
28
+ return (
29
+ <Floaty title="My Panel">
30
+ <p>Your content here</p>
31
+ </Floaty>
32
+ );
33
+ }
34
+ ```
35
+
36
+ ## Props
37
+
38
+ All props are optional.
39
+
40
+ ```tsx
41
+ interface FloatyProps {
42
+ /** Content to display inside the floaty body */
43
+ children?: ReactNode;
44
+
45
+ /** Header title text */
46
+ title?: string;
47
+
48
+ /** Additional inline styles */
49
+ style?: CSSProperties;
50
+ }
51
+ ```
52
+
53
+ ### Default Values
54
+
55
+ - `children`: `'Content'`
56
+ - `title`: `'Floaty'`
57
+ - `style`: `{}`
58
+
59
+ ## Examples
60
+
61
+ ### Basic Usage
62
+
63
+ ```tsx
64
+ <Floaty title="Dashboard">
65
+ <div>
66
+ <h3>Welcome!</h3>
67
+ <p>This is a floating panel.</p>
68
+ </div>
69
+ </Floaty>
70
+ ```
71
+
72
+ ### With Custom Styling
73
+
74
+ ```tsx
75
+ <Floaty
76
+ title="Settings"
77
+ style={{ width: '400px' }}
78
+ >
79
+ <form>
80
+ {/* Your form content */}
81
+ </form>
82
+ </Floaty>
83
+ ```
84
+
85
+ ### With Complex Content
86
+
87
+ ```tsx
88
+ <Floaty title="User Info">
89
+ <div>
90
+ <img src="avatar.jpg" alt="User" />
91
+ <h4>John Doe</h4>
92
+ <p>john@example.com</p>
93
+ <button>View Profile</button>
94
+ </div>
95
+ </Floaty>
96
+ ```
97
+
98
+ ## Features in Detail
99
+
100
+ ### 🖱️ Dragging
101
+
102
+ Click and hold the header to drag the component around. The component will stay within viewport boundaries automatically.
103
+
104
+ ### 📍 Pin/Unpin
105
+
106
+ Click the pin icon (📍) in the header to lock the component. When pinned (📌), the component cannot be dragged but can still be collapsed/expanded.
107
+
108
+ ### ➖ Expand/Collapse
109
+
110
+ Click the chevron icon in the top-right to toggle content visibility. The animation is smooth with spring easing.
111
+
112
+ ## Styling
113
+
114
+ The component uses CSS variables that you can customize:
115
+
116
+ ```css
117
+ :root {
118
+ --primary-color: #4f46e5;
119
+ --primary-hover: #4338ca;
120
+ --border-color: #e5e7eb;
121
+ --shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
122
+ --transition: all 0.3s ease;
123
+ }
124
+ ```
125
+
126
+ ## Development
127
+
128
+ ### Setup
129
+
130
+ ```bash
131
+ npm install
132
+ ```
133
+
134
+ ### Development Server
135
+
136
+ ```bash
137
+ npm run dev
138
+ ```
139
+
140
+ ### Storybook
141
+
142
+ ```bash
143
+ npm run storybook
144
+ ```
145
+
146
+ Open [http://localhost:6006](http://localhost:6006) to view the component stories.
147
+
148
+ ### Build
149
+
150
+ ```bash
151
+ npm run build
152
+ ```
153
+
154
+ Generates:
155
+ - ES module: `dist/floaty-widget.js`
156
+ - UMD bundle: `dist/floaty-widget.umd.cjs`
157
+ - CSS: `dist/style.css`
158
+
159
+ ## Browser Support
160
+
161
+ - Chrome (latest)
162
+ - Firefox (latest)
163
+ - Safari (latest)
164
+ - Edge (latest)
165
+
166
+ ## Performance
167
+
168
+ - **Optimized dragging** with global event listeners to prevent jank
169
+ - **Tree-shaking enabled** for smaller bundle sizes
170
+ - **CSS animations** for smooth expand/collapse transitions
171
+ - **Viewport constraints** to prevent layout shifts
172
+
173
+ ## Accessibility
174
+
175
+ - ♿ ARIA labels on interactive elements
176
+ - ⌨️ Keyboard accessible buttons
177
+ - 📱 Touch-friendly hit targets
178
+ - 🎯 Semantic HTML structure
179
+
180
+ ## TypeScript Support
181
+
182
+ Full TypeScript support with exported types:
183
+
184
+ ```tsx
185
+ import { Floaty, FloatyProps } from 'floaty-widget';
186
+
187
+ const MyComponent: React.FC<FloatyProps> = (props) => {
188
+ return <Floaty {...props} />;
189
+ };
190
+ ```
191
+
192
+ ## License
193
+
194
+ MIT © 2024
195
+
196
+ ---
197
+
198
+ **Built with** ❤️ using React 19, TypeScript, and Vite
@@ -0,0 +1,384 @@
1
+ import re, { useState as M, useRef as V, useEffect as te } from "react";
2
+ var D = { exports: {} }, x = {};
3
+ /**
4
+ * @license React
5
+ * react-jsx-runtime.production.js
6
+ *
7
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
8
+ *
9
+ * This source code is licensed under the MIT license found in the
10
+ * LICENSE file in the root directory of this source tree.
11
+ */
12
+ var z;
13
+ function ne() {
14
+ if (z) return x;
15
+ z = 1;
16
+ var s = Symbol.for("react.transitional.element"), h = Symbol.for("react.fragment");
17
+ function v(c, l, a) {
18
+ var E = null;
19
+ if (a !== void 0 && (E = "" + a), l.key !== void 0 && (E = "" + l.key), "key" in l) {
20
+ a = {};
21
+ for (var d in l)
22
+ d !== "key" && (a[d] = l[d]);
23
+ } else a = l;
24
+ return l = a.ref, {
25
+ $$typeof: s,
26
+ type: c,
27
+ key: E,
28
+ ref: l !== void 0 ? l : null,
29
+ props: a
30
+ };
31
+ }
32
+ return x.Fragment = h, x.jsx = v, x.jsxs = v, x;
33
+ }
34
+ var y = {};
35
+ /**
36
+ * @license React
37
+ * react-jsx-runtime.development.js
38
+ *
39
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
40
+ *
41
+ * This source code is licensed under the MIT license found in the
42
+ * LICENSE file in the root directory of this source tree.
43
+ */
44
+ var q;
45
+ function oe() {
46
+ return q || (q = 1, process.env.NODE_ENV !== "production" && function() {
47
+ function s(e) {
48
+ if (e == null) return null;
49
+ if (typeof e == "function")
50
+ return e.$$typeof === Q ? null : e.displayName || e.name || null;
51
+ if (typeof e == "string") return e;
52
+ switch (e) {
53
+ case b:
54
+ return "Fragment";
55
+ case S:
56
+ return "Profiler";
57
+ case T:
58
+ return "StrictMode";
59
+ case G:
60
+ return "Suspense";
61
+ case J:
62
+ return "SuspenseList";
63
+ case Z:
64
+ return "Activity";
65
+ }
66
+ if (typeof e == "object")
67
+ switch (typeof e.tag == "number" && console.error(
68
+ "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
69
+ ), e.$$typeof) {
70
+ case g:
71
+ return "Portal";
72
+ case j:
73
+ return e.displayName || "Context";
74
+ case O:
75
+ return (e._context.displayName || "Context") + ".Consumer";
76
+ case B:
77
+ var r = e.render;
78
+ return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
79
+ case H:
80
+ return r = e.displayName || null, r !== null ? r : s(e.type) || "Memo";
81
+ case A:
82
+ r = e._payload, e = e._init;
83
+ try {
84
+ return s(e(r));
85
+ } catch {
86
+ }
87
+ }
88
+ return null;
89
+ }
90
+ function h(e) {
91
+ return "" + e;
92
+ }
93
+ function v(e) {
94
+ try {
95
+ h(e);
96
+ var r = !1;
97
+ } catch {
98
+ r = !0;
99
+ }
100
+ if (r) {
101
+ r = console;
102
+ var t = r.error, n = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
103
+ return t.call(
104
+ r,
105
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
106
+ n
107
+ ), h(e);
108
+ }
109
+ }
110
+ function c(e) {
111
+ if (e === b) return "<>";
112
+ if (typeof e == "object" && e !== null && e.$$typeof === A)
113
+ return "<...>";
114
+ try {
115
+ var r = s(e);
116
+ return r ? "<" + r + ">" : "<...>";
117
+ } catch {
118
+ return "<...>";
119
+ }
120
+ }
121
+ function l() {
122
+ var e = C.A;
123
+ return e === null ? null : e.getOwner();
124
+ }
125
+ function a() {
126
+ return Error("react-stack-top-frame");
127
+ }
128
+ function E(e) {
129
+ if (I.call(e, "key")) {
130
+ var r = Object.getOwnPropertyDescriptor(e, "key").get;
131
+ if (r && r.isReactWarning) return !1;
132
+ }
133
+ return e.key !== void 0;
134
+ }
135
+ function d(e, r) {
136
+ function t() {
137
+ L || (L = !0, console.error(
138
+ "%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)",
139
+ r
140
+ ));
141
+ }
142
+ t.isReactWarning = !0, Object.defineProperty(e, "key", {
143
+ get: t,
144
+ configurable: !0
145
+ });
146
+ }
147
+ function P() {
148
+ var e = s(this.type);
149
+ return F[e] || (F[e] = !0, console.error(
150
+ "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."
151
+ )), e = this.props.ref, e !== void 0 ? e : null;
152
+ }
153
+ function R(e, r, t, n, w, Y) {
154
+ var o = t.ref;
155
+ return e = {
156
+ $$typeof: p,
157
+ type: e,
158
+ key: r,
159
+ props: t,
160
+ _owner: n
161
+ }, (o !== void 0 ? o : null) !== null ? Object.defineProperty(e, "ref", {
162
+ enumerable: !1,
163
+ get: P
164
+ }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
165
+ configurable: !1,
166
+ enumerable: !1,
167
+ writable: !0,
168
+ value: 0
169
+ }), Object.defineProperty(e, "_debugInfo", {
170
+ configurable: !1,
171
+ enumerable: !1,
172
+ writable: !0,
173
+ value: null
174
+ }), Object.defineProperty(e, "_debugStack", {
175
+ configurable: !1,
176
+ enumerable: !1,
177
+ writable: !0,
178
+ value: w
179
+ }), Object.defineProperty(e, "_debugTask", {
180
+ configurable: !1,
181
+ enumerable: !1,
182
+ writable: !0,
183
+ value: Y
184
+ }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
185
+ }
186
+ function f(e, r, t, n, w, Y) {
187
+ var o = r.children;
188
+ if (o !== void 0)
189
+ if (n)
190
+ if (K(o)) {
191
+ for (n = 0; n < o.length; n++)
192
+ k(o[n]);
193
+ Object.freeze && Object.freeze(o);
194
+ } else
195
+ console.error(
196
+ "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
197
+ );
198
+ else k(o);
199
+ if (I.call(r, "key")) {
200
+ o = s(e);
201
+ var _ = Object.keys(r).filter(function(ee) {
202
+ return ee !== "key";
203
+ });
204
+ n = 0 < _.length ? "{key: someKey, " + _.join(": ..., ") + ": ...}" : "{key: someKey}", X[o + n] || (_ = 0 < _.length ? "{" + _.join(": ..., ") + ": ...}" : "{}", console.error(
205
+ `A props object containing a "key" prop is being spread into JSX:
206
+ let props = %s;
207
+ <%s {...props} />
208
+ React keys must be passed directly to JSX without using spread:
209
+ let props = %s;
210
+ <%s key={someKey} {...props} />`,
211
+ n,
212
+ o,
213
+ _,
214
+ o
215
+ ), X[o + n] = !0);
216
+ }
217
+ if (o = null, t !== void 0 && (v(t), o = "" + t), E(r) && (v(r.key), o = "" + r.key), "key" in r) {
218
+ t = {};
219
+ for (var $ in r)
220
+ $ !== "key" && (t[$] = r[$]);
221
+ } else t = r;
222
+ return o && d(
223
+ t,
224
+ typeof e == "function" ? e.displayName || e.name || "Unknown" : e
225
+ ), R(
226
+ e,
227
+ o,
228
+ t,
229
+ l(),
230
+ w,
231
+ Y
232
+ );
233
+ }
234
+ function k(e) {
235
+ m(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === A && (e._payload.status === "fulfilled" ? m(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
236
+ }
237
+ function m(e) {
238
+ return typeof e == "object" && e !== null && e.$$typeof === p;
239
+ }
240
+ var u = re, p = Symbol.for("react.transitional.element"), g = Symbol.for("react.portal"), b = Symbol.for("react.fragment"), T = Symbol.for("react.strict_mode"), S = Symbol.for("react.profiler"), O = Symbol.for("react.consumer"), j = Symbol.for("react.context"), B = Symbol.for("react.forward_ref"), G = Symbol.for("react.suspense"), J = Symbol.for("react.suspense_list"), H = Symbol.for("react.memo"), A = Symbol.for("react.lazy"), Z = Symbol.for("react.activity"), Q = Symbol.for("react.client.reference"), C = u.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, I = Object.prototype.hasOwnProperty, K = Array.isArray, N = console.createTask ? console.createTask : function() {
241
+ return null;
242
+ };
243
+ u = {
244
+ react_stack_bottom_frame: function(e) {
245
+ return e();
246
+ }
247
+ };
248
+ var L, F = {}, W = u.react_stack_bottom_frame.bind(
249
+ u,
250
+ a
251
+ )(), U = N(c(a)), X = {};
252
+ y.Fragment = b, y.jsx = function(e, r, t) {
253
+ var n = 1e4 > C.recentlyCreatedOwnerStacks++;
254
+ return f(
255
+ e,
256
+ r,
257
+ t,
258
+ !1,
259
+ n ? Error("react-stack-top-frame") : W,
260
+ n ? N(c(e)) : U
261
+ );
262
+ }, y.jsxs = function(e, r, t) {
263
+ var n = 1e4 > C.recentlyCreatedOwnerStacks++;
264
+ return f(
265
+ e,
266
+ r,
267
+ t,
268
+ !0,
269
+ n ? Error("react-stack-top-frame") : W,
270
+ n ? N(c(e)) : U
271
+ );
272
+ };
273
+ }()), y;
274
+ }
275
+ process.env.NODE_ENV === "production" ? D.exports = ne() : D.exports = oe();
276
+ var i = D.exports;
277
+ const ae = ({ pinned: s }) => /* @__PURE__ */ i.jsx(
278
+ "svg",
279
+ {
280
+ width: "16",
281
+ height: "16",
282
+ viewBox: "0 0 24 24",
283
+ fill: "none",
284
+ stroke: "currentColor",
285
+ strokeWidth: "2",
286
+ strokeLinecap: "round",
287
+ strokeLinejoin: "round",
288
+ children: s ? /* @__PURE__ */ i.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m3-13h-2v4h-2v-4h-2v2h4v2h-4v2h6v-6" }) : /* @__PURE__ */ i.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m3.5-9h-7v2h7v-2" })
289
+ }
290
+ ), se = ({ collapsed: s }) => /* @__PURE__ */ i.jsx(
291
+ "svg",
292
+ {
293
+ width: "16",
294
+ height: "16",
295
+ viewBox: "0 0 24 24",
296
+ fill: "none",
297
+ stroke: "currentColor",
298
+ strokeWidth: "2.5",
299
+ strokeLinecap: "round",
300
+ strokeLinejoin: "round",
301
+ className: `chevron ${s ? "collapsed" : ""}`,
302
+ children: /* @__PURE__ */ i.jsx("polyline", { points: "6 9 12 15 18 9" })
303
+ }
304
+ ), ie = ({
305
+ children: s = "Content",
306
+ title: h = "Floaty",
307
+ style: v = {}
308
+ }) => {
309
+ const [c, l] = M(!1), [a, E] = M(!1), [d, P] = M({ x: 100, y: 100 }), R = V(null), f = V({ isDragging: !1, offsetX: 0, offsetY: 0 }), k = (m) => {
310
+ var p;
311
+ if (a) return;
312
+ const u = (p = R.current) == null ? void 0 : p.getBoundingClientRect();
313
+ u && (f.current = {
314
+ isDragging: !0,
315
+ offsetX: m.clientX - u.left,
316
+ offsetY: m.clientY - u.top
317
+ });
318
+ };
319
+ return te(() => {
320
+ const m = (p) => {
321
+ var j;
322
+ if (!f.current.isDragging) return;
323
+ const g = (j = R.current) == null ? void 0 : j.getBoundingClientRect();
324
+ if (!g) return;
325
+ let b = p.clientX - f.current.offsetX, T = p.clientY - f.current.offsetY;
326
+ const S = window.innerWidth - g.width, O = window.innerHeight - g.height;
327
+ b = Math.max(0, Math.min(b, S)), T = Math.max(0, Math.min(T, O)), P({
328
+ x: b,
329
+ y: T
330
+ });
331
+ }, u = () => {
332
+ f.current.isDragging = !1;
333
+ };
334
+ return globalThis.addEventListener("mousemove", m), globalThis.addEventListener("mouseup", u), () => {
335
+ globalThis.removeEventListener("mousemove", m), globalThis.removeEventListener("mouseup", u);
336
+ };
337
+ }, []), /* @__PURE__ */ i.jsxs(
338
+ "div",
339
+ {
340
+ ref: R,
341
+ className: `floaty ${a ? "pinned" : ""} ${c ? "collapsed" : ""} ${f.current.isDragging ? "dragging" : ""}`,
342
+ style: {
343
+ transform: `translate(${d.x}px, ${d.y}px)`,
344
+ ...v
345
+ },
346
+ children: [
347
+ /* @__PURE__ */ i.jsxs(
348
+ "header",
349
+ {
350
+ className: `floaty-header ${a ? "pinned" : ""}`,
351
+ onMouseDown: k,
352
+ children: [
353
+ /* @__PURE__ */ i.jsx(
354
+ "button",
355
+ {
356
+ className: "floaty-button floaty-button--pin",
357
+ onClick: () => E(!a),
358
+ title: a ? "Unpin" : "Pin",
359
+ "aria-label": a ? "Unpin floaty" : "Pin floaty",
360
+ children: /* @__PURE__ */ i.jsx(ae, { pinned: a })
361
+ }
362
+ ),
363
+ /* @__PURE__ */ i.jsx("span", { className: "floaty-title", children: h }),
364
+ /* @__PURE__ */ i.jsx(
365
+ "button",
366
+ {
367
+ className: "floaty-button floaty-button--expand",
368
+ onClick: () => l(!c),
369
+ title: c ? "Expand" : "Collapse",
370
+ "aria-label": c ? "Expand floaty" : "Collapse floaty",
371
+ children: /* @__PURE__ */ i.jsx(se, { collapsed: c })
372
+ }
373
+ )
374
+ ]
375
+ }
376
+ ),
377
+ !c && /* @__PURE__ */ i.jsx("div", { className: "floaty-body", children: s })
378
+ ]
379
+ }
380
+ );
381
+ };
382
+ export {
383
+ ie as Floaty
384
+ };
@@ -0,0 +1,22 @@
1
+ (function(E,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],u):(E=typeof globalThis<"u"?globalThis:E||self,u(E.FloatyWidget={},E.React))})(this,function(E,u){"use strict";var O={exports:{}},T={};/**
2
+ * @license React
3
+ * react-jsx-runtime.production.js
4
+ *
5
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */var F;function G(){if(F)return T;F=1;var l=Symbol.for("react.transitional.element"),R=Symbol.for("react.fragment");function h(c,i,a){var b=null;if(a!==void 0&&(b=""+a),i.key!==void 0&&(b=""+i.key),"key"in i){a={};for(var m in i)m!=="key"&&(a[m]=i[m])}else a=i;return i=a.ref,{$$typeof:l,type:c,key:b,ref:i!==void 0?i:null,props:a}}return T.Fragment=R,T.jsx=h,T.jsxs=h,T}var y={};/**
10
+ * @license React
11
+ * react-jsx-runtime.development.js
12
+ *
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ */var W;function J(){return W||(W=1,process.env.NODE_ENV!=="production"&&function(){function l(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 _:return"Fragment";case C:return"Profiler";case j:return"StrictMode";case K:return"Suspense";case ee:return"SuspenseList";case re: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 k:return"Portal";case S:return e.displayName||"Context";case N:return(e._context.displayName||"Context")+".Consumer";case q:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return t=e.displayName||null,t!==null?t:l(e.type)||"Memo";case Y:t=e._payload,e=e._init;try{return l(e(t))}catch{}}return null}function R(e){return""+e}function h(e){try{R(e);var t=!1}catch{t=!0}if(t){t=console;var r=t.error,n=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return r.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n),R(e)}}function c(e){if(e===_)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===Y)return"<...>";try{var t=l(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function i(){var e=M.A;return e===null?null:e.getOwner()}function a(){return Error("react-stack-top-frame")}function b(e){if(U.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function m(e,t){function r(){X||(X=!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)",t))}r.isReactWarning=!0,Object.defineProperty(e,"key",{get:r,configurable:!0})}function A(){var e=l(this.type);return $[e]||($[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 x(e,t,r,n,P,I){var o=r.ref;return e={$$typeof:v,type:e,key:t,props:r,_owner:n},(o!==void 0?o: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:P}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:I}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function d(e,t,r,n,P,I){var o=t.children;if(o!==void 0)if(n)if(oe(o)){for(n=0;n<o.length;n++)w(o[n]);Object.freeze&&Object.freeze(o)}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 w(o);if(U.call(t,"key")){o=l(e);var g=Object.keys(t).filter(function(ae){return ae!=="key"});n=0<g.length?"{key: someKey, "+g.join(": ..., ")+": ...}":"{key: someKey}",B[o+n]||(g=0<g.length?"{"+g.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
18
+ let props = %s;
19
+ <%s {...props} />
20
+ React keys must be passed directly to JSX without using spread:
21
+ let props = %s;
22
+ <%s key={someKey} {...props} />`,n,o,g,o),B[o+n]=!0)}if(o=null,r!==void 0&&(h(r),o=""+r),b(t)&&(h(t.key),o=""+t.key),"key"in t){r={};for(var L in t)L!=="key"&&(r[L]=t[L])}else r=t;return o&&m(r,typeof e=="function"?e.displayName||e.name||"Unknown":e),x(e,o,r,i(),P,I)}function w(e){p(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===Y&&(e._payload.status==="fulfilled"?p(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function p(e){return typeof e=="object"&&e!==null&&e.$$typeof===v}var f=u,v=Symbol.for("react.transitional.element"),k=Symbol.for("react.portal"),_=Symbol.for("react.fragment"),j=Symbol.for("react.strict_mode"),C=Symbol.for("react.profiler"),N=Symbol.for("react.consumer"),S=Symbol.for("react.context"),q=Symbol.for("react.forward_ref"),K=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),Y=Symbol.for("react.lazy"),re=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),M=f.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,U=Object.prototype.hasOwnProperty,oe=Array.isArray,D=console.createTask?console.createTask:function(){return null};f={react_stack_bottom_frame:function(e){return e()}};var X,$={},V=f.react_stack_bottom_frame.bind(f,a)(),z=D(c(a)),B={};y.Fragment=_,y.jsx=function(e,t,r){var n=1e4>M.recentlyCreatedOwnerStacks++;return d(e,t,r,!1,n?Error("react-stack-top-frame"):V,n?D(c(e)):z)},y.jsxs=function(e,t,r){var n=1e4>M.recentlyCreatedOwnerStacks++;return d(e,t,r,!0,n?Error("react-stack-top-frame"):V,n?D(c(e)):z)}}()),y}process.env.NODE_ENV==="production"?O.exports=G():O.exports=J();var s=O.exports;const H=({pinned:l})=>s.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:l?s.jsx("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m3-13h-2v4h-2v-4h-2v2h4v2h-4v2h6v-6"}):s.jsx("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m3.5-9h-7v2h7v-2"})}),Z=({collapsed:l})=>s.jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:`chevron ${l?"collapsed":""}`,children:s.jsx("polyline",{points:"6 9 12 15 18 9"})}),Q=({children:l="Content",title:R="Floaty",style:h={}})=>{const[c,i]=u.useState(!1),[a,b]=u.useState(!1),[m,A]=u.useState({x:100,y:100}),x=u.useRef(null),d=u.useRef({isDragging:!1,offsetX:0,offsetY:0}),w=p=>{var v;if(a)return;const f=(v=x.current)==null?void 0:v.getBoundingClientRect();f&&(d.current={isDragging:!0,offsetX:p.clientX-f.left,offsetY:p.clientY-f.top})};return u.useEffect(()=>{const p=v=>{var S;if(!d.current.isDragging)return;const k=(S=x.current)==null?void 0:S.getBoundingClientRect();if(!k)return;let _=v.clientX-d.current.offsetX,j=v.clientY-d.current.offsetY;const C=window.innerWidth-k.width,N=window.innerHeight-k.height;_=Math.max(0,Math.min(_,C)),j=Math.max(0,Math.min(j,N)),A({x:_,y:j})},f=()=>{d.current.isDragging=!1};return globalThis.addEventListener("mousemove",p),globalThis.addEventListener("mouseup",f),()=>{globalThis.removeEventListener("mousemove",p),globalThis.removeEventListener("mouseup",f)}},[]),s.jsxs("div",{ref:x,className:`floaty ${a?"pinned":""} ${c?"collapsed":""} ${d.current.isDragging?"dragging":""}`,style:{transform:`translate(${m.x}px, ${m.y}px)`,...h},children:[s.jsxs("header",{className:`floaty-header ${a?"pinned":""}`,onMouseDown:w,children:[s.jsx("button",{className:"floaty-button floaty-button--pin",onClick:()=>b(!a),title:a?"Unpin":"Pin","aria-label":a?"Unpin floaty":"Pin floaty",children:s.jsx(H,{pinned:a})}),s.jsx("span",{className:"floaty-title",children:R}),s.jsx("button",{className:"floaty-button floaty-button--expand",onClick:()=>i(!c),title:c?"Expand":"Collapse","aria-label":c?"Expand floaty":"Collapse floaty",children:s.jsx(Z,{collapsed:c})})]}),!c&&s.jsx("div",{className:"floaty-body",children:l})]})};E.Floaty=Q,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .floaty{--primary-color: #4f46e5;--primary-hover: #4338ca;--border-color: #e5e7eb;--shadow: 0 10px 25px rgba(0, 0, 0, .1);--transition: all .3s ease;--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;position:fixed;width:320px;background:#fff;border:1px solid var(--border-color);border-radius:8px;box-shadow:var(--shadow);z-index:1000;-webkit-user-select:none;user-select:none;font-family:var(--font-family)}.floaty:not(.dragging){transition:var(--transition)}.floaty.dragging{box-shadow:0 20px 35px #0003;opacity:.95}.floaty.pinned{opacity:1;border-color:var(--primary-color)}.floaty.collapsed{min-width:auto}.floaty-header{display:flex;align-items:center;gap:8px;padding:12px 16px;background:linear-gradient(135deg,var(--primary-color) 0%,var(--primary-hover) 100%);color:#fff;font-weight:600;font-size:14px;border-radius:7px 7px 0 0;cursor:grab;transition:border-radius .3s ease;-webkit-user-select:none;user-select:none}.floaty.collapsed .floaty-header{border-radius:7px}.floaty-header:active{cursor:grabbing}.floaty-header.pinned{background:linear-gradient(135deg,#10b981,#059669)}.floaty-button{background:none;border:none;color:#fff;cursor:pointer;padding:4px 8px;border-radius:4px;transition:var(--transition);display:flex;align-items:center;justify-content:center;flex-shrink:0}.floaty-button svg{width:16px;height:16px;stroke:currentColor;fill:none}.floaty-button:hover{background:#fff3;transform:scale(1.1)}.floaty-button:active{transform:scale(.95)}.floaty-button--pin{order:-1}.floaty-button--expand{order:1;margin-left:auto}.floaty-title{flex:1;text-align:center;order:0}.floaty-body{padding:16px;background:#f9fafb;border-radius:0 0 7px 7px;font-size:14px;line-height:1.6;color:#374151;max-height:500px;overflow:hidden;opacity:1;transform-origin:top;animation:expandIn .3s cubic-bezier(.34,1.56,.64,1)}.floaty.collapsed .floaty-body{animation:collapseOut .3s cubic-bezier(.34,1.56,.64,1) forwards}@keyframes expandIn{0%{opacity:0;max-height:0;transform:scaleY(.8)}to{opacity:1;max-height:500px;transform:scaleY(1)}}@keyframes collapseOut{0%{opacity:1;max-height:500px;transform:scaleY(1)}to{opacity:0;max-height:0;transform:scaleY(.8)}}.chevron{display:inline-flex;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}.chevron.collapsed{transform:rotate(180deg)}@media (max-width: 480px){.floaty{min-width:200px}.floaty-header{padding:10px 12px;font-size:13px}.floaty-body{padding:12px;max-height:300px}}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "floaty-widget",
3
+ "version": "0.1.0",
4
+ "description": "A floating component with drag, collapse/expand, and pin functionality",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.es.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.es.js",
12
+ "require": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "vite build",
22
+ "preview": "vite preview",
23
+ "storybook": "storybook dev -p 6006",
24
+ "build-storybook": "storybook build"
25
+ },
26
+ "dependencies": {
27
+ "react": "^19.0.0",
28
+ "react-dom": "^19.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@storybook/addon-docs": "^10.3.4",
32
+ "@storybook/react": "^10.3.4",
33
+ "@storybook/react-vite": "^10.3.4",
34
+ "@types/react": "^19.0.0",
35
+ "@types/react-dom": "^19.0.0",
36
+ "@vitejs/plugin-react": "^4.3.0",
37
+ "typescript": "^5.3.0",
38
+ "vite": "^5.0.0",
39
+ "storybook": "^10.3.4"
40
+ }
41
+ }