@sehv-oss/basketball-upload-react 1.0.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,7 @@
1
+ ISC License
2
+
3
+ Copyright 2026 sehv-oss
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,23 @@
1
+ # Notice
2
+
3
+ ## Design
4
+
5
+ The basketball file upload implemented here, from the dropzone that doubles as a backboard to the slingshot shot, the aiming dots, the swish of the net and the upload list, is a design by **Jorge Molina**, published on Figma Community.
6
+
7
+ - GitHub: [jm-fuster](https://github.com/jm-fuster)
8
+ - Figma Community: [@jm_fuster](https://www.figma.com/@jm_fuster)
9
+ - Website: [jorgemolinafuster.com](https://jorgemolinafuster.com)
10
+
11
+ This project is an independent code implementation of that design, made with admiration for the original work. It is not affiliated with or endorsed by the author.
12
+
13
+ Changes and additions made in this implementation:
14
+
15
+ - the Web Component and React APIs, and the upload pipeline behind the list;
16
+ - the physics of the shot, and keyboard (assisted) shots;
17
+ - the dark theme and the theming tokens;
18
+ - built-in and custom file types;
19
+ - form association, accessibility announcements and reduced motion support.
20
+
21
+ ## Code
22
+
23
+ The code is licensed under the [ISC License](LICENSE).
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # @sehv-oss/basketball-upload-react
2
+
3
+ React 19 component for [`<basketball-upload>`](../core): drag and drop, or take the shot.
4
+
5
+ `<BasketballUpload>` renders the Web Component; it is not a second implementation. Everything about the element — how files get in, uploads, forms, file types and theming — is documented in the [core README](../core/README.md).
6
+
7
+ **[Live demo](https://sehv-oss.github.io/basketball-upload/)**
8
+
9
+ Design by **Jorge Molina** ([jm-fuster](https://github.com/jm-fuster), [@jm_fuster](https://www.figma.com/@jm_fuster) on Figma Community). See [NOTICE.md](NOTICE.md).
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # npm
15
+ npm install @sehv-oss/basketball-upload-react
16
+
17
+ # pnpm
18
+ pnpm add @sehv-oss/basketball-upload-react
19
+
20
+ # yarn
21
+ yarn add @sehv-oss/basketball-upload-react
22
+ ```
23
+
24
+ `react` 19 or newer is a peer dependency. The element comes along as a dependency.
25
+
26
+ ## Usage
27
+
28
+ ```tsx
29
+ import {
30
+ BasketballUpload,
31
+ createXhrUploader,
32
+ type BasketballUploadElement,
33
+ type BasketballUploadProps,
34
+ } from '@sehv-oss/basketball-upload-react';
35
+ import * as React from 'react';
36
+
37
+ // Stable across renders: module scope, useMemo or useCallback.
38
+ const uploader = createXhrUploader({ url: '/api/uploads' });
39
+
40
+ export function Uploads() {
41
+ const hoop = React.useRef<BasketballUploadElement>(null);
42
+
43
+ const handleOnShot: BasketballUploadProps['onShot'] = ({ file, result }) =>
44
+ console.log(file.name, result);
45
+ const handleOnUploadSuccess: BasketballUploadProps['onUploadSuccess'] = ({
46
+ item,
47
+ }) => console.log('stored', item.response);
48
+ const handleOnClick = () => hoop.current?.clear();
49
+
50
+ return (
51
+ <>
52
+ <BasketballUpload
53
+ ref={hoop}
54
+ multiple
55
+ accept="image/*,.pdf"
56
+ maxSize={20_000_000}
57
+ uploader={uploader}
58
+ onShot={handleOnShot}
59
+ onUploadSuccess={handleOnUploadSuccess}
60
+ >
61
+ <span slot="hint">PDF or images, up to 20 MB</span>
62
+ </BasketballUpload>
63
+
64
+ <button onClick={handleOnClick}>Clear</button>
65
+ </>
66
+ );
67
+ }
68
+ ```
69
+
70
+ The component registers the element itself (`tagName` when it was registered under another name). The module starts with `'use client'`, for React Server Components frameworks such as Next.js.
71
+
72
+ ## Props
73
+
74
+ | Prop | Element API |
75
+ | -------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
76
+ | `theme`, `accept`, `multiple`, `maxSize`, `maxFiles`, `name`, `required`, `disabled`, `instant`, `concurrency` | attributes, rendered on the server too |
77
+ | `uploader`, `messages`, `fileTypes` | properties, applied after mount |
78
+ | `onFileReject`, `onShot`, `onUploadStart`, `onUploadProgress`, `onUploadSuccess`, `onUploadError`, `onChange` | events; the callback gets the `detail` |
79
+ | `ref` | the `<basketball-upload>` element |
80
+ | `children` | slotted content (`slot="title"`, …) |
81
+ | `id`, `className`, `style`, `tagName` | the host element |
82
+
83
+ Keep `uploader`, `messages` and `fileTypes` stable (module scope, `useMemo`, `useCallback`): a new value is assigned to the element on every change. Callbacks can change freely.
84
+
85
+ For forms, render it inside a `<form>` with a `name`, as you would an `<input type="file">`; with React 19 actions, the files arrive in the `FormData`.
86
+
87
+ The helpers and types needed to use the component are re-exported from the core: `createXhrUploader`, `UploadError`, `registerFileType`, `defaultMessages`, `defaultFileTypes`, and the types of the element, its props and events (`BasketballUploadElement`, `Uploader`, `UploadItem`, `FileType`, `Messages`, …). The ones for building around the element (`resolveFileType`, `matchesAccept`, `formatBytes`, `registerBasketballUpload`) come from [`@sehv-oss/basketball-upload`](../core).
88
+
89
+ ## License
90
+
91
+ [ISC](LICENSE). Design credit in [NOTICE.md](NOTICE.md).
@@ -0,0 +1,125 @@
1
+
2
+ import * as React from "react";
3
+ import { BasketballUploadElement, BasketballUploadElement as BasketballUploadElement$1, BasketballUploadEventMap, BasketballUploadEventMap as BasketballUploadEventMap$1, FileArtwork, FileType, FileType as FileType$1, Messages, Messages as Messages$1, RejectReason, ShotResult, Theme, Theme as Theme$1, UploadContext, UploadError, UploadItem, UploadStatus, Uploader, Uploader as Uploader$1, XhrUploaderOptions, createXhrUploader, defaultFileTypes, defaultMessages, registerFileType } from "@sehv-oss/basketball-upload";
4
+ //#region src/basketball-upload.d.ts
5
+ type Detail<TType extends keyof BasketballUploadEventMap$1> = BasketballUploadEventMap$1[TType]['detail'];
6
+ /**
7
+ * Props of `<BasketballUpload>`: the attributes and properties of the element,
8
+ * and its events as callbacks.
9
+ */
10
+ interface BasketballUploadProps {
11
+ /**
12
+ * The `<basketball-upload>` element, for its methods and properties.
13
+ */
14
+ ref?: React.Ref<BasketballUploadElement$1> | undefined;
15
+ /**
16
+ * Defaults to `system`.
17
+ */
18
+ theme?: Theme$1 | undefined;
19
+ /**
20
+ * Accepted files, with the syntax of `<input type="file" accept>`.
21
+ */
22
+ accept?: string | undefined;
23
+ /**
24
+ * Several files at a time. Without it, a new file replaces the previous one.
25
+ */
26
+ multiple?: boolean | undefined;
27
+ /**
28
+ * Largest accepted file, in bytes.
29
+ */
30
+ maxSize?: number | undefined;
31
+ /**
32
+ * Most files at once, staged and in the basket.
33
+ */
34
+ maxFiles?: number | undefined;
35
+ /**
36
+ * Form field the files are submitted under.
37
+ */
38
+ name?: string | undefined;
39
+ /**
40
+ * The form is invalid while the basket is empty.
41
+ */
42
+ required?: boolean | undefined;
43
+ /**
44
+ * Ignores files and shots.
45
+ */
46
+ disabled?: boolean | undefined;
47
+ /**
48
+ * No shooting: every file goes straight into the basket.
49
+ */
50
+ instant?: boolean | undefined;
51
+ /**
52
+ * Uploads running at the same time. Defaults to 3.
53
+ */
54
+ concurrency?: number | undefined;
55
+ /**
56
+ * Sends each file. Keep it stable (module scope or `useCallback`).
57
+ */
58
+ uploader?: Uploader$1 | null | undefined;
59
+ /**
60
+ * Copy overrides. Memoize them: a new object re-renders the copy.
61
+ */
62
+ messages?: Partial<Messages$1> | undefined;
63
+ /**
64
+ * File types for this element. Memoize them, like `messages`.
65
+ */
66
+ fileTypes?: readonly FileType$1[] | undefined;
67
+ /**
68
+ * Name the custom element was registered with, when not the default.
69
+ */
70
+ tagName?: string | undefined;
71
+ /**
72
+ * Set on the element.
73
+ */
74
+ id?: string | undefined;
75
+ /**
76
+ * Set on the element, as `class`.
77
+ */
78
+ className?: string | undefined;
79
+ /**
80
+ * Set on the element, custom properties (`--basketball-upload-*`) included.
81
+ */
82
+ style?: React.CSSProperties | undefined;
83
+ /**
84
+ * Slotted content, such as `<span slot="title">`.
85
+ */
86
+ children?: React.ReactNode | undefined;
87
+ /**
88
+ * A file did not pass `accept`, `maxSize` or `maxFiles`. Gets the `detail` of the `file-reject` event, not the event.
89
+ */
90
+ onFileReject?: ((detail: Detail<'file-reject'>) => void) | undefined;
91
+ /**
92
+ * A card went through the net, dunks included, or a shot missed. Gets the `detail` of the `shot` event.
93
+ */
94
+ onShot?: ((detail: Detail<'shot'>) => void) | undefined;
95
+ /**
96
+ * The uploader was called for an item. Gets the `detail` of the `upload-start` event.
97
+ */
98
+ onUploadStart?: ((detail: Detail<'upload-start'>) => void) | undefined;
99
+ /**
100
+ * The uploader reported progress. Gets the `detail` of the `upload-progress` event.
101
+ */
102
+ onUploadProgress?: ((detail: Detail<'upload-progress'>) => void) | undefined;
103
+ /**
104
+ * An upload resolved; `item.response` has its value. Gets the `detail` of the `upload-success` event.
105
+ */
106
+ onUploadSuccess?: ((detail: Detail<'upload-success'>) => void) | undefined;
107
+ /**
108
+ * An upload rejected; `item.error` has the reason. Gets the `detail` of the `upload-error` event.
109
+ */
110
+ onUploadError?: ((detail: Detail<'upload-error'>) => void) | undefined;
111
+ /**
112
+ * Files entered or left the basket, or one changed status. Gets the `detail` of the `change` event.
113
+ */
114
+ onChange?: ((detail: Detail<'change'>) => void) | undefined;
115
+ }
116
+ /**
117
+ * `<basketball-upload>` for React 19. Plain values travel as attributes, which
118
+ * the server renders and the client upgrades; functions and objects
119
+ * (`uploader`, `messages`, `fileTypes`) and the event callbacks are applied to
120
+ * the element after it mounts.
121
+ */
122
+ export declare function BasketballUpload(props: BasketballUploadProps): React.ReactNode;
123
+ //#endregion
124
+ export { type BasketballUploadElement, type BasketballUploadEventMap, type BasketballUploadProps, type FileArtwork, type FileType, type Messages, type RejectReason, type ShotResult, type Theme, type UploadContext, UploadError, type UploadItem, type UploadStatus, type Uploader, type XhrUploaderOptions, createXhrUploader, defaultFileTypes, defaultMessages, registerFileType };
125
+ //# sourceMappingURL=basketball-upload-react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basketball-upload-react.d.ts","names":["BasketballUploadEventMap","BasketballUploadElement","Theme","Uploader","Messages","FileType"],"sources":["../src/basketball-upload.ts"],"mappings":";;;;KAaK,OAAO,oBAAoBA,8BAC9BA,2BAAyB;;;;;UAMV;;;;EAIf,MAAM,MAAM,IAAIC;;;;EAKhB,QAAQC;;;;EAKR;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA;;;;EAKA,WAAWC;;;;EAKX,WAAW,QAAQC;;;;EAKnB,qBAAqBC;;;;EAKrB;;;;EAKA;;;;EAKA;;;;EAKA,QAAQ,MAAM;;;;EAKd,WAAW,MAAM;;;;EAKjB,iBAAiB,QAAQ;;;;EAKzB,WAAW,QAAQ;;;;EAKnB,kBAAkB,QAAQ;;;;EAK1B,qBAAqB,QAAQ;;;;EAK7B,oBAAoB,QAAQ;;;;EAK5B,kBAAkB,QAAQ;;;;EAK1B,aAAa,QAAQ;;;;;;;;wBA8BP,iBACd,OAAO,wBACN,MAAM"}
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { DEFAULT_TAG_NAME, UploadError, createXhrUploader, defaultFileTypes, defaultMessages, registerBasketballUpload, registerFileType } from "@sehv-oss/basketball-upload";
4
+ //#region src/basketball-upload.ts
5
+ const EVENTS = {
6
+ "file-reject": "onFileReject",
7
+ shot: "onShot",
8
+ "upload-start": "onUploadStart",
9
+ "upload-progress": "onUploadProgress",
10
+ "upload-success": "onUploadSuccess",
11
+ "upload-error": "onUploadError",
12
+ change: "onChange"
13
+ };
14
+ /**
15
+ * `<basketball-upload>` for React 19. Plain values travel as attributes, which
16
+ * the server renders and the client upgrades; functions and objects
17
+ * (`uploader`, `messages`, `fileTypes`) and the event callbacks are applied to
18
+ * the element after it mounts.
19
+ */
20
+ function BasketballUpload(props) {
21
+ const { ref, theme, accept, multiple, maxSize, maxFiles, name, required, disabled, instant, concurrency, uploader, messages, fileTypes, tagName = DEFAULT_TAG_NAME, children, onFileReject, onShot, onUploadStart, onUploadProgress, onUploadSuccess, onUploadError, onChange, ...rest } = props;
22
+ registerBasketballUpload({ tagName });
23
+ const elementRef = React.useRef(null);
24
+ React.useImperativeHandle(ref, () => elementRef.current, []);
25
+ const callbacks = React.useRef({});
26
+ callbacks.current = {
27
+ onFileReject,
28
+ onShot,
29
+ onUploadStart,
30
+ onUploadProgress,
31
+ onUploadSuccess,
32
+ onUploadError,
33
+ onChange
34
+ };
35
+ React.useEffect(() => {
36
+ const element = elementRef.current;
37
+ if (!element) return;
38
+ const listeners = new AbortController();
39
+ for (const [type, callback] of Object.entries(EVENTS)) element.addEventListener(type, (event) => {
40
+ const handle = callbacks.current[callback];
41
+ handle?.(event.detail);
42
+ }, { signal: listeners.signal });
43
+ return () => listeners.abort();
44
+ }, []);
45
+ React.useLayoutEffect(() => {
46
+ const element = elementRef.current;
47
+ if (element) element.uploader = uploader ?? null;
48
+ }, [uploader]);
49
+ React.useLayoutEffect(() => {
50
+ const element = elementRef.current;
51
+ if (element) element.messages = messages;
52
+ }, [messages]);
53
+ React.useLayoutEffect(() => {
54
+ const element = elementRef.current;
55
+ if (element) element.fileTypes = fileTypes;
56
+ }, [fileTypes]);
57
+ return React.createElement(tagName, {
58
+ ...rest,
59
+ ref: elementRef,
60
+ theme: theme === "light" || theme === "dark" ? theme : void 0,
61
+ accept: accept || void 0,
62
+ multiple: multiple || void 0,
63
+ "max-size": maxSize,
64
+ "max-files": maxFiles,
65
+ name: name || void 0,
66
+ required: required || void 0,
67
+ disabled: disabled || void 0,
68
+ instant: instant || void 0,
69
+ concurrency
70
+ }, children);
71
+ }
72
+ //#endregion
73
+ export { BasketballUpload, UploadError, createXhrUploader, defaultFileTypes, defaultMessages, registerFileType };
74
+
75
+ //# sourceMappingURL=basketball-upload-react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"basketball-upload-react.js","names":[],"sources":["../src/basketball-upload.ts"],"sourcesContent":["import * as React from 'react';\n\nimport {\n DEFAULT_TAG_NAME,\n registerBasketballUpload,\n type BasketballUploadElement,\n type BasketballUploadEventMap,\n type FileType,\n type Messages,\n type Theme,\n type Uploader,\n} from '@sehv-oss/basketball-upload';\n\ntype Detail<TType extends keyof BasketballUploadEventMap> =\n BasketballUploadEventMap[TType]['detail'];\n\n/**\n * Props of `<BasketballUpload>`: the attributes and properties of the element,\n * and its events as callbacks.\n */\nexport interface BasketballUploadProps {\n /**\n * The `<basketball-upload>` element, for its methods and properties.\n */\n ref?: React.Ref<BasketballUploadElement> | undefined;\n\n /**\n * Defaults to `system`.\n */\n theme?: Theme | undefined;\n\n /**\n * Accepted files, with the syntax of `<input type=\"file\" accept>`.\n */\n accept?: string | undefined;\n\n /**\n * Several files at a time. Without it, a new file replaces the previous one.\n */\n multiple?: boolean | undefined;\n\n /**\n * Largest accepted file, in bytes.\n */\n maxSize?: number | undefined;\n\n /**\n * Most files at once, staged and in the basket.\n */\n maxFiles?: number | undefined;\n\n /**\n * Form field the files are submitted under.\n */\n name?: string | undefined;\n\n /**\n * The form is invalid while the basket is empty.\n */\n required?: boolean | undefined;\n\n /**\n * Ignores files and shots.\n */\n disabled?: boolean | undefined;\n\n /**\n * No shooting: every file goes straight into the basket.\n */\n instant?: boolean | undefined;\n\n /**\n * Uploads running at the same time. Defaults to 3.\n */\n concurrency?: number | undefined;\n\n /**\n * Sends each file. Keep it stable (module scope or `useCallback`).\n */\n uploader?: Uploader | null | undefined;\n\n /**\n * Copy overrides. Memoize them: a new object re-renders the copy.\n */\n messages?: Partial<Messages> | undefined;\n\n /**\n * File types for this element. Memoize them, like `messages`.\n */\n fileTypes?: readonly FileType[] | undefined;\n\n /**\n * Name the custom element was registered with, when not the default.\n */\n tagName?: string | undefined;\n\n /**\n * Set on the element.\n */\n id?: string | undefined;\n\n /**\n * Set on the element, as `class`.\n */\n className?: string | undefined;\n\n /**\n * Set on the element, custom properties (`--basketball-upload-*`) included.\n */\n style?: React.CSSProperties | undefined;\n\n /**\n * Slotted content, such as `<span slot=\"title\">`.\n */\n children?: React.ReactNode | undefined;\n\n /**\n * A file did not pass `accept`, `maxSize` or `maxFiles`. Gets the `detail` of the `file-reject` event, not the event.\n */\n onFileReject?: ((detail: Detail<'file-reject'>) => void) | undefined;\n\n /**\n * A card went through the net, dunks included, or a shot missed. Gets the `detail` of the `shot` event.\n */\n onShot?: ((detail: Detail<'shot'>) => void) | undefined;\n\n /**\n * The uploader was called for an item. Gets the `detail` of the `upload-start` event.\n */\n onUploadStart?: ((detail: Detail<'upload-start'>) => void) | undefined;\n\n /**\n * The uploader reported progress. Gets the `detail` of the `upload-progress` event.\n */\n onUploadProgress?: ((detail: Detail<'upload-progress'>) => void) | undefined;\n\n /**\n * An upload resolved; `item.response` has its value. Gets the `detail` of the `upload-success` event.\n */\n onUploadSuccess?: ((detail: Detail<'upload-success'>) => void) | undefined;\n\n /**\n * An upload rejected; `item.error` has the reason. Gets the `detail` of the `upload-error` event.\n */\n onUploadError?: ((detail: Detail<'upload-error'>) => void) | undefined;\n\n /**\n * Files entered or left the basket, or one changed status. Gets the `detail` of the `change` event.\n */\n onChange?: ((detail: Detail<'change'>) => void) | undefined;\n}\n\ntype Callbacks = Pick<\n BasketballUploadProps,\n | 'onFileReject'\n | 'onShot'\n | 'onUploadStart'\n | 'onUploadProgress'\n | 'onUploadSuccess'\n | 'onUploadError'\n | 'onChange'\n>;\n\nconst EVENTS: { [TType in keyof BasketballUploadEventMap]: keyof Callbacks } = {\n 'file-reject': 'onFileReject',\n shot: 'onShot',\n 'upload-start': 'onUploadStart',\n 'upload-progress': 'onUploadProgress',\n 'upload-success': 'onUploadSuccess',\n 'upload-error': 'onUploadError',\n change: 'onChange',\n};\n\n/**\n * `<basketball-upload>` for React 19. Plain values travel as attributes, which\n * the server renders and the client upgrades; functions and objects\n * (`uploader`, `messages`, `fileTypes`) and the event callbacks are applied to\n * the element after it mounts.\n */\nexport function BasketballUpload(\n props: BasketballUploadProps\n): React.ReactNode {\n const {\n ref,\n theme,\n accept,\n multiple,\n maxSize,\n maxFiles,\n name,\n required,\n disabled,\n instant,\n concurrency,\n uploader,\n messages,\n fileTypes,\n tagName = DEFAULT_TAG_NAME,\n children,\n\n onFileReject,\n onShot,\n onUploadStart,\n onUploadProgress,\n onUploadSuccess,\n onUploadError,\n onChange,\n\n ...rest\n } = props;\n\n registerBasketballUpload({ tagName });\n\n const elementRef = React.useRef<BasketballUploadElement>(null);\n React.useImperativeHandle(\n ref,\n () => elementRef.current as BasketballUploadElement,\n []\n );\n\n const callbacks = React.useRef<Callbacks>({});\n callbacks.current = {\n onFileReject,\n onShot,\n onUploadStart,\n onUploadProgress,\n onUploadSuccess,\n onUploadError,\n onChange,\n };\n\n React.useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n\n const listeners = new AbortController();\n for (const [type, callback] of Object.entries(EVENTS)) {\n element.addEventListener(\n type,\n (event) => {\n const handle = callbacks.current[callback] as\n ((detail: unknown) => void) | undefined;\n handle?.((event as CustomEvent).detail);\n },\n { signal: listeners.signal }\n );\n }\n\n return () => listeners.abort();\n }, []);\n\n React.useLayoutEffect(() => {\n const element = elementRef.current;\n if (element) element.uploader = uploader ?? null;\n }, [uploader]);\n\n React.useLayoutEffect(() => {\n const element = elementRef.current;\n if (element) element.messages = messages;\n }, [messages]);\n\n React.useLayoutEffect(() => {\n const element = elementRef.current;\n if (element) element.fileTypes = fileTypes;\n }, [fileTypes]);\n\n return React.createElement(\n tagName,\n {\n ...rest,\n ref: elementRef,\n theme: theme === 'light' || theme === 'dark' ? theme : undefined,\n accept: accept || undefined,\n multiple: multiple || undefined,\n 'max-size': maxSize,\n 'max-files': maxFiles,\n name: name || undefined,\n required: required || undefined,\n disabled: disabled || undefined,\n instant: instant || undefined,\n concurrency,\n },\n children\n );\n}\n"],"mappings":";;;;AAmKA,MAAM,SAAyE;CAC7E,eAAe;CACf,MAAM;CACN,gBAAgB;CAChB,mBAAmB;CACnB,kBAAkB;CAClB,gBAAgB;CAChB,QAAQ;AACV;;;;;;;AAQA,SAAgB,iBACd,OACiB;CACjB,MAAM,EACJ,KACA,OACA,QACA,UACA,SACA,UACA,MACA,UACA,UACA,SACA,aACA,UACA,UACA,WACA,UAAU,kBACV,UAEA,cACA,QACA,eACA,kBACA,iBACA,eACA,UAEA,GAAG,SACD;CAEJ,yBAAyB,EAAE,QAAQ,CAAC;CAEpC,MAAM,aAAa,MAAM,OAAgC,IAAI;CAC7D,MAAM,oBACJ,WACM,WAAW,SACjB,CAAC,CACH;CAEA,MAAM,YAAY,MAAM,OAAkB,CAAC,CAAC;CAC5C,UAAU,UAAU;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,MAAM,gBAAgB;EACpB,MAAM,UAAU,WAAW;EAC3B,IAAI,CAAC,SAAS;EAEd,MAAM,YAAY,IAAI,gBAAgB;EACtC,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,MAAM,GAClD,QAAQ,iBACN,OACC,UAAU;GACT,MAAM,SAAS,UAAU,QAAQ;GAEjC,SAAU,MAAsB,MAAM;EACxC,GACA,EAAE,QAAQ,UAAU,OAAO,CAC7B;EAGF,aAAa,UAAU,MAAM;CAC/B,GAAG,CAAC,CAAC;CAEL,MAAM,sBAAsB;EAC1B,MAAM,UAAU,WAAW;EAC3B,IAAI,SAAS,QAAQ,WAAW,YAAY;CAC9C,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,sBAAsB;EAC1B,MAAM,UAAU,WAAW;EAC3B,IAAI,SAAS,QAAQ,WAAW;CAClC,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,sBAAsB;EAC1B,MAAM,UAAU,WAAW;EAC3B,IAAI,SAAS,QAAQ,YAAY;CACnC,GAAG,CAAC,SAAS,CAAC;CAEd,OAAO,MAAM,cACX,SACA;EACE,GAAG;EACH,KAAK;EACL,OAAO,UAAU,WAAW,UAAU,SAAS,QAAQ,KAAA;EACvD,QAAQ,UAAU,KAAA;EAClB,UAAU,YAAY,KAAA;EACtB,YAAY;EACZ,aAAa;EACb,MAAM,QAAQ,KAAA;EACd,UAAU,YAAY,KAAA;EACtB,UAAU,YAAY,KAAA;EACtB,SAAS,WAAW,KAAA;EACpB;CACF,GACA,QACF;AACF"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@sehv-oss/basketball-upload-react",
3
+ "version": "1.0.0",
4
+ "description": "React component for <basketball-upload>, the basketball-themed drag and drop file upload.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/basketball-upload-react.d.ts",
9
+ "default": "./dist/basketball-upload-react.js"
10
+ },
11
+ "./package.json": "./package.json"
12
+ },
13
+ "files": [
14
+ "./dist",
15
+ "NOTICE.md"
16
+ ],
17
+ "keywords": [
18
+ "react",
19
+ "file-upload",
20
+ "upload",
21
+ "dropzone",
22
+ "drag-and-drop",
23
+ "dnd",
24
+ "basketball",
25
+ "web-component"
26
+ ],
27
+ "license": "ISC",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/sehv-oss/basketball-upload.git",
31
+ "directory": "packages/react"
32
+ },
33
+ "homepage": "https://sehv-oss.github.io/basketball-upload/",
34
+ "bugs": {
35
+ "url": "https://github.com/sehv-oss/basketball-upload/issues"
36
+ },
37
+ "engines": {
38
+ "node": ">=24 <27"
39
+ },
40
+ "dependencies": {
41
+ "@sehv-oss/basketball-upload": "^1.0.0"
42
+ },
43
+ "peerDependencies": {
44
+ "@types/react": ">=19",
45
+ "react": ">=19"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@types/react": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "devDependencies": {
53
+ "@sehv-oss/typescript-config": "0.0.1",
54
+ "@types/node": "26.6.4",
55
+ "@types/react": "19.3.0",
56
+ "@types/react-dom": "19.3.0",
57
+ "@vitest/browser-playwright": "5.0.3",
58
+ "react": "19.3.0",
59
+ "react-dom": "19.3.0",
60
+ "tsdown": "0.23.0",
61
+ "typescript": "7.0.2",
62
+ "vitest": "5.0.3",
63
+ "vitest-browser-react": "2.3.0"
64
+ },
65
+ "scripts": {
66
+ "build": "tsc --project tsconfig.json && tsc --project tsconfig.tests.json && tsdown"
67
+ }
68
+ }