@tokshare/pick 0.0.0-stage → 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.
@@ -0,0 +1,65 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ButtonHTMLAttributes, ReactNode } from 'react';
3
+ import { PickOptions, FieldOptions, PickController } from '@tokshare/pick';
4
+
5
+ interface TokShareSettings {
6
+ /** Your publishable key (pk_live_… or pk_test_…). React reserves `key`, hence `pickKey`. */
7
+ pickKey?: string;
8
+ /** Relay URL. Defaults to the hosted relay. */
9
+ relay?: string;
10
+ locale?: PickOptions["locale"];
11
+ theme?: PickOptions["theme"];
12
+ }
13
+ /** Sets the key (and optionally relay, locale, theme) once for every TokShare component inside it. */
14
+ declare function TokShareProvider({ children, ...settings }: TokShareSettings & {
15
+ children?: ReactNode;
16
+ }): react.JSX.Element;
17
+ /** Options shared by the field, the button and the hook. Sizes take bytes or "5MB", "500KB". */
18
+ interface TokSharePickOptions extends Omit<PickOptions, "key" | "ui" | "maxFileBytes" | "signal"> {
19
+ /** Overrides the provider's key. */
20
+ pickKey?: string;
21
+ maxFileBytes?: number | string;
22
+ /** Phone shrinks photos so the longest side is at most this many pixels. Short for resizeImages. */
23
+ resize?: number;
24
+ }
25
+ /**
26
+ * `const { pick } = useTokSharePick({ accept: "image/*" })`, then `const files = await pick()` in a click
27
+ * handler. Options given to pick() override the hook's, which override the provider's.
28
+ */
29
+ declare function useTokSharePick(defaults?: TokSharePickOptions): {
30
+ /** Opens the phone window; resolves with the files, or [] if the person cancels. */
31
+ pick: (options?: TokSharePickOptions) => Promise<File[]>;
32
+ /** The same with live events (phone, progress, file) and your own UI if you pass ui: false. */
33
+ open: (options?: TokSharePickOptions & {
34
+ ui?: boolean;
35
+ }) => PickController;
36
+ };
37
+ interface TokSharePickProps extends TokSharePickOptions, Pick<FieldOptions, "name" | "phone" | "phoneOnMobile" | "label"> {
38
+ /** Every time the list changes: files from this computer and from the phone, in order. */
39
+ onChange?: (files: File[]) => void;
40
+ className?: string;
41
+ style?: CSSProperties;
42
+ id?: string;
43
+ }
44
+ interface TokSharePickHandle {
45
+ /** The files in the field right now. */
46
+ readonly files: readonly File[];
47
+ /** The hidden <input type="file" name> the files are kept in, for forms. */
48
+ readonly input: HTMLInputElement | null;
49
+ remove(file: File): void;
50
+ clear(): void;
51
+ }
52
+ /**
53
+ * The complete upload field: drop zone, "Browse files" and "Use your phone". With `name`, a normal
54
+ * form submit includes the files. Changing an option rebuilds the field (and empties it).
55
+ */
56
+ declare const TokSharePick: react.ForwardRefExoticComponent<TokSharePickProps & react.RefAttributes<TokSharePickHandle>>;
57
+ interface TokSharePickButtonProps extends TokSharePickOptions, Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof TokSharePickOptions | "onError"> {
58
+ /** The files the person sent (not called if they cancel). */
59
+ onFiles?: (files: File[]) => void;
60
+ onError?: (error: unknown) => void;
61
+ }
62
+ /** A button that opens the phone window and hands you the files. Takes every <button> prop too. */
63
+ declare const TokSharePickButton: react.ForwardRefExoticComponent<TokSharePickButtonProps & react.RefAttributes<HTMLButtonElement>>;
64
+
65
+ export { TokSharePick, TokSharePickButton, type TokSharePickButtonProps, type TokSharePickHandle, type TokSharePickOptions, type TokSharePickProps, TokShareProvider, type TokShareSettings, useTokSharePick };
@@ -0,0 +1,65 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ButtonHTMLAttributes, ReactNode } from 'react';
3
+ import { PickOptions, FieldOptions, PickController } from '@tokshare/pick';
4
+
5
+ interface TokShareSettings {
6
+ /** Your publishable key (pk_live_… or pk_test_…). React reserves `key`, hence `pickKey`. */
7
+ pickKey?: string;
8
+ /** Relay URL. Defaults to the hosted relay. */
9
+ relay?: string;
10
+ locale?: PickOptions["locale"];
11
+ theme?: PickOptions["theme"];
12
+ }
13
+ /** Sets the key (and optionally relay, locale, theme) once for every TokShare component inside it. */
14
+ declare function TokShareProvider({ children, ...settings }: TokShareSettings & {
15
+ children?: ReactNode;
16
+ }): react.JSX.Element;
17
+ /** Options shared by the field, the button and the hook. Sizes take bytes or "5MB", "500KB". */
18
+ interface TokSharePickOptions extends Omit<PickOptions, "key" | "ui" | "maxFileBytes" | "signal"> {
19
+ /** Overrides the provider's key. */
20
+ pickKey?: string;
21
+ maxFileBytes?: number | string;
22
+ /** Phone shrinks photos so the longest side is at most this many pixels. Short for resizeImages. */
23
+ resize?: number;
24
+ }
25
+ /**
26
+ * `const { pick } = useTokSharePick({ accept: "image/*" })`, then `const files = await pick()` in a click
27
+ * handler. Options given to pick() override the hook's, which override the provider's.
28
+ */
29
+ declare function useTokSharePick(defaults?: TokSharePickOptions): {
30
+ /** Opens the phone window; resolves with the files, or [] if the person cancels. */
31
+ pick: (options?: TokSharePickOptions) => Promise<File[]>;
32
+ /** The same with live events (phone, progress, file) and your own UI if you pass ui: false. */
33
+ open: (options?: TokSharePickOptions & {
34
+ ui?: boolean;
35
+ }) => PickController;
36
+ };
37
+ interface TokSharePickProps extends TokSharePickOptions, Pick<FieldOptions, "name" | "phone" | "phoneOnMobile" | "label"> {
38
+ /** Every time the list changes: files from this computer and from the phone, in order. */
39
+ onChange?: (files: File[]) => void;
40
+ className?: string;
41
+ style?: CSSProperties;
42
+ id?: string;
43
+ }
44
+ interface TokSharePickHandle {
45
+ /** The files in the field right now. */
46
+ readonly files: readonly File[];
47
+ /** The hidden <input type="file" name> the files are kept in, for forms. */
48
+ readonly input: HTMLInputElement | null;
49
+ remove(file: File): void;
50
+ clear(): void;
51
+ }
52
+ /**
53
+ * The complete upload field: drop zone, "Browse files" and "Use your phone". With `name`, a normal
54
+ * form submit includes the files. Changing an option rebuilds the field (and empties it).
55
+ */
56
+ declare const TokSharePick: react.ForwardRefExoticComponent<TokSharePickProps & react.RefAttributes<TokSharePickHandle>>;
57
+ interface TokSharePickButtonProps extends TokSharePickOptions, Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof TokSharePickOptions | "onError"> {
58
+ /** The files the person sent (not called if they cancel). */
59
+ onFiles?: (files: File[]) => void;
60
+ onError?: (error: unknown) => void;
61
+ }
62
+ /** A button that opens the phone window and hands you the files. Takes every <button> prop too. */
63
+ declare const TokSharePickButton: react.ForwardRefExoticComponent<TokSharePickButtonProps & react.RefAttributes<HTMLButtonElement>>;
64
+
65
+ export { TokSharePick, TokSharePickButton, type TokSharePickButtonProps, type TokSharePickHandle, type TokSharePickOptions, type TokSharePickProps, TokShareProvider, type TokShareSettings, useTokSharePick };
package/dist/react.js ADDED
@@ -0,0 +1,140 @@
1
+ "use client";
2
+
3
+ // src/react.tsx
4
+ import { mountField, open, parseSize, pick } from "@tokshare/pick";
5
+ import {
6
+ createContext,
7
+ forwardRef,
8
+ useCallback,
9
+ useContext,
10
+ useEffect,
11
+ useImperativeHandle,
12
+ useMemo,
13
+ useRef,
14
+ useState
15
+ } from "react";
16
+ import { jsx } from "react/jsx-runtime";
17
+ var TokShareContext = createContext({});
18
+ function TokShareProvider({ children, ...settings }) {
19
+ const parent = useContext(TokShareContext);
20
+ const { pickKey, relay, locale, theme } = settings;
21
+ const value = useMemo(() => ({ ...parent, ...defined({ pickKey, relay, locale, theme }) }), [parent, pickKey, relay, locale, theme]);
22
+ return /* @__PURE__ */ jsx(TokShareContext.Provider, { value, children });
23
+ }
24
+ function defined(value) {
25
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
26
+ }
27
+ function toCoreOptions(settings, props, component) {
28
+ const { pickKey, maxFileBytes, resize, ...rest } = props;
29
+ const key = pickKey ?? settings.pickKey;
30
+ if (!key) throw new Error(`${component}: pass pickKey, or wrap your app in <TokShareProvider pickKey="pk_\u2026">.`);
31
+ const bytes = parseSize(maxFileBytes);
32
+ return {
33
+ ...defined({ relay: settings.relay, locale: settings.locale, theme: settings.theme }),
34
+ ...defined(rest),
35
+ key,
36
+ ...bytes ? { maxFileBytes: bytes } : {},
37
+ ...resize && resize > 0 && rest.resizeImages === void 0 ? { resizeImages: { maxDimension: resize } } : {}
38
+ };
39
+ }
40
+ function useTokSharePick(defaults = {}) {
41
+ const settings = useContext(TokShareContext);
42
+ const latest = useRef({ settings, defaults });
43
+ latest.current = { settings, defaults };
44
+ return useMemo(() => ({
45
+ /** Opens the phone window; resolves with the files, or [] if the person cancels. */
46
+ pick: (options = {}) => pick(toCoreOptions(latest.current.settings, { ...latest.current.defaults, ...options }, "useTokSharePick")),
47
+ /** The same with live events (phone, progress, file) and your own UI if you pass ui: false. */
48
+ open: (options = {}) => {
49
+ const { ui, ...rest } = options;
50
+ return open({ ...toCoreOptions(latest.current.settings, { ...latest.current.defaults, ...rest }, "useTokSharePick"), ...ui === void 0 ? {} : { ui } });
51
+ }
52
+ }), []);
53
+ }
54
+ var TokSharePick = forwardRef(function TokSharePick2(props, ref) {
55
+ const { onChange, className, style, id, ...options } = props;
56
+ const settings = useContext(TokShareContext);
57
+ const core = toCoreOptions(settings, options, "<TokSharePick>");
58
+ const signature = JSON.stringify(core);
59
+ const container = useRef(null);
60
+ const controller = useRef(null);
61
+ const onChangeRef = useRef(onChange);
62
+ onChangeRef.current = onChange;
63
+ useEffect(() => {
64
+ const field = mountField(container.current, JSON.parse(signature));
65
+ controller.current = field;
66
+ const off = field.on("change", (files) => onChangeRef.current?.(files));
67
+ return () => {
68
+ off();
69
+ field.destroy();
70
+ if (controller.current === field) controller.current = null;
71
+ };
72
+ }, [signature]);
73
+ useImperativeHandle(ref, () => ({
74
+ get files() {
75
+ return controller.current?.files ?? [];
76
+ },
77
+ get input() {
78
+ return controller.current?.input ?? null;
79
+ },
80
+ remove: (file) => controller.current?.remove(file),
81
+ clear: () => controller.current?.clear()
82
+ }), []);
83
+ return /* @__PURE__ */ jsx("div", { ref: container, className, style, id });
84
+ });
85
+ var PICK_OPTION_NAMES = [
86
+ "pickKey",
87
+ "maxFileBytes",
88
+ "resize",
89
+ "accept",
90
+ "multiple",
91
+ "maxFiles",
92
+ "resizeImages",
93
+ "confirmPhone",
94
+ "siteName",
95
+ "relay",
96
+ "locale",
97
+ "theme",
98
+ "strings",
99
+ "direct",
100
+ "announce"
101
+ ];
102
+ var TokSharePickButton = forwardRef(function TokSharePickButton2(props, ref) {
103
+ const { onFiles, onError, onClick, children, disabled, type, ...rest } = props;
104
+ const options = {};
105
+ const buttonProps = {};
106
+ for (const [name, value] of Object.entries(rest)) {
107
+ (PICK_OPTION_NAMES.includes(name) ? options : buttonProps)[name] = value;
108
+ }
109
+ const { pick: pickFiles } = useTokSharePick(options);
110
+ const [busy, setBusy] = useState(false);
111
+ const mounted = useRef(true);
112
+ useEffect(() => {
113
+ mounted.current = true;
114
+ return () => {
115
+ mounted.current = false;
116
+ };
117
+ }, []);
118
+ const handleClick = useCallback(async (event) => {
119
+ onClick?.(event);
120
+ if (event.defaultPrevented) return;
121
+ setBusy(true);
122
+ try {
123
+ const files = await pickFiles();
124
+ if (files.length) onFiles?.(files);
125
+ } catch (error) {
126
+ if (onError) onError(error);
127
+ else console.error(error);
128
+ } finally {
129
+ if (mounted.current) setBusy(false);
130
+ }
131
+ }, [onClick, onFiles, onError, pickFiles]);
132
+ return /* @__PURE__ */ jsx("button", { ref, type: type ?? "button", disabled: disabled || busy, "aria-busy": busy || void 0, onClick: handleClick, ...buttonProps, children: children ?? "From my phone" });
133
+ });
134
+ export {
135
+ TokSharePick,
136
+ TokSharePickButton,
137
+ TokShareProvider,
138
+ useTokSharePick
139
+ };
140
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"sourcesContent":["\"use client\";\n// @tokshare/pick/react: the upload field, a phone button and a hook, as React components.\n//\n// <TokShareProvider pickKey=\"pk_live_…\"> once, near the top of the app\n// <TokSharePick name=\"photos\" accept=\"image/*\" maxFileBytes=\"5MB\" onChange={setFiles} />\n// <TokSharePickButton accept=\"image/*\" onFiles={addFiles}>From my phone</TokSharePickButton>\n// </TokShareProvider>\n//\n// The core is imported from \"@tokshare/pick\" (not bundled in), so an app that uses both gets one copy.\nimport { mountField, open, parseSize, pick, type FieldController, type FieldOptions, type PickController, type PickOptions } from \"@tokshare/pick\";\nimport {\n createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState,\n type ButtonHTMLAttributes, type CSSProperties, type MouseEvent, type ReactNode,\n} from \"react\";\n\n// ---- Shared settings ----------------------------------------------------------------------------\n\nexport interface TokShareSettings {\n /** Your publishable key (pk_live_… or pk_test_…). React reserves `key`, hence `pickKey`. */\n pickKey?: string;\n /** Relay URL. Defaults to the hosted relay. */\n relay?: string;\n locale?: PickOptions[\"locale\"];\n theme?: PickOptions[\"theme\"];\n}\n\nconst TokShareContext = createContext<TokShareSettings>({});\n\n/** Sets the key (and optionally relay, locale, theme) once for every TokShare component inside it. */\nexport function TokShareProvider({ children, ...settings }: TokShareSettings & { children?: ReactNode }) {\n const parent = useContext(TokShareContext);\n const { pickKey, relay, locale, theme } = settings;\n const value = useMemo(() => ({ ...parent, ...defined({ pickKey, relay, locale, theme }) }), [parent, pickKey, relay, locale, theme]);\n return <TokShareContext.Provider value={value}>{children}</TokShareContext.Provider>;\n}\n\n/** Options shared by the field, the button and the hook. Sizes take bytes or \"5MB\", \"500KB\". */\nexport interface TokSharePickOptions extends Omit<PickOptions, \"key\" | \"ui\" | \"maxFileBytes\" | \"signal\"> {\n /** Overrides the provider's key. */\n pickKey?: string;\n maxFileBytes?: number | string;\n /** Phone shrinks photos so the longest side is at most this many pixels. Short for resizeImages. */\n resize?: number;\n}\n\nfunction defined<T extends object>(value: T): Partial<T> {\n return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined)) as Partial<T>;\n}\n\n/** Provider settings + component props → core options. Throws early if no key was given anywhere. */\nfunction toCoreOptions(settings: TokShareSettings, props: TokSharePickOptions, component: string): PickOptions {\n const { pickKey, maxFileBytes, resize, ...rest } = props;\n const key = pickKey ?? settings.pickKey;\n if (!key) throw new Error(`${component}: pass pickKey, or wrap your app in <TokShareProvider pickKey=\"pk_…\">.`);\n const bytes = parseSize(maxFileBytes);\n return {\n ...defined({ relay: settings.relay, locale: settings.locale, theme: settings.theme }),\n ...defined(rest),\n key,\n ...(bytes ? { maxFileBytes: bytes } : {}),\n ...(resize && resize > 0 && rest.resizeImages === undefined ? { resizeImages: { maxDimension: resize } } : {}),\n };\n}\n\n// ---- Hook ---------------------------------------------------------------------------------------\n\n/**\n * `const { pick } = useTokSharePick({ accept: \"image/*\" })`, then `const files = await pick()` in a click\n * handler. Options given to pick() override the hook's, which override the provider's.\n */\nexport function useTokSharePick(defaults: TokSharePickOptions = {}) {\n const settings = useContext(TokShareContext);\n const latest = useRef({ settings, defaults });\n latest.current = { settings, defaults };\n return useMemo(() => ({\n /** Opens the phone window; resolves with the files, or [] if the person cancels. */\n pick: (options: TokSharePickOptions = {}): Promise<File[]> =>\n pick(toCoreOptions(latest.current.settings, { ...latest.current.defaults, ...options }, \"useTokSharePick\")),\n /** The same with live events (phone, progress, file) and your own UI if you pass ui: false. */\n open: (options: TokSharePickOptions & { ui?: boolean } = {}): PickController => {\n const { ui, ...rest } = options;\n return open({ ...toCoreOptions(latest.current.settings, { ...latest.current.defaults, ...rest }, \"useTokSharePick\"), ...(ui === undefined ? {} : { ui }) });\n },\n }), []);\n}\n\n// ---- Upload field -------------------------------------------------------------------------------\n\nexport interface TokSharePickProps extends TokSharePickOptions, Pick<FieldOptions, \"name\" | \"phone\" | \"phoneOnMobile\" | \"label\"> {\n /** Every time the list changes: files from this computer and from the phone, in order. */\n onChange?: (files: File[]) => void;\n className?: string;\n style?: CSSProperties;\n id?: string;\n}\n\nexport interface TokSharePickHandle {\n /** The files in the field right now. */\n readonly files: readonly File[];\n /** The hidden <input type=\"file\" name> the files are kept in, for forms. */\n readonly input: HTMLInputElement | null;\n remove(file: File): void;\n clear(): void;\n}\n\n/**\n * The complete upload field: drop zone, \"Browse files\" and \"Use your phone\". With `name`, a normal\n * form submit includes the files. Changing an option rebuilds the field (and empties it).\n */\nexport const TokSharePick = forwardRef<TokSharePickHandle, TokSharePickProps>(function TokSharePick(props, ref) {\n const { onChange, className, style, id, ...options } = props;\n const settings = useContext(TokShareContext);\n // name, phone, phoneOnMobile and label ride along with the pick options.\n const core = toCoreOptions(settings, options, \"<TokSharePick>\") as FieldOptions;\n // Inline objects (strings={{…}}) are new on every render: rebuild only when the values change.\n const signature = JSON.stringify(core);\n const container = useRef<HTMLDivElement>(null);\n const controller = useRef<FieldController | null>(null);\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n useEffect(() => {\n const field = mountField(container.current!, JSON.parse(signature) as FieldOptions);\n controller.current = field;\n const off = field.on(\"change\", (files) => onChangeRef.current?.(files));\n return () => {\n off();\n field.destroy();\n if (controller.current === field) controller.current = null;\n };\n }, [signature]);\n\n useImperativeHandle(ref, () => ({\n get files() { return controller.current?.files ?? []; },\n get input() { return controller.current?.input ?? null; },\n remove: (file: File) => controller.current?.remove(file),\n clear: () => controller.current?.clear(),\n }), []);\n\n return <div ref={container} className={className} style={style} id={id} />;\n});\n\n// ---- Button -------------------------------------------------------------------------------------\n\nexport interface TokSharePickButtonProps\n extends TokSharePickOptions, Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof TokSharePickOptions | \"onError\"> {\n /** The files the person sent (not called if they cancel). */\n onFiles?: (files: File[]) => void;\n onError?: (error: unknown) => void;\n}\n\nconst PICK_OPTION_NAMES = [\n \"pickKey\", \"maxFileBytes\", \"resize\", \"accept\", \"multiple\", \"maxFiles\", \"resizeImages\", \"confirmPhone\",\n \"siteName\", \"relay\", \"locale\", \"theme\", \"strings\", \"direct\", \"announce\",\n] as const satisfies readonly (keyof TokSharePickOptions)[];\n\n/** A button that opens the phone window and hands you the files. Takes every <button> prop too. */\nexport const TokSharePickButton = forwardRef<HTMLButtonElement, TokSharePickButtonProps>(function TokSharePickButton(props, ref) {\n const { onFiles, onError, onClick, children, disabled, type, ...rest } = props;\n const options: Record<string, unknown> = {};\n const buttonProps: Record<string, unknown> = {};\n for (const [name, value] of Object.entries(rest)) {\n ((PICK_OPTION_NAMES as readonly string[]).includes(name) ? options : buttonProps)[name] = value;\n }\n const { pick: pickFiles } = useTokSharePick(options as TokSharePickOptions);\n const [busy, setBusy] = useState(false);\n const mounted = useRef(true);\n useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);\n\n const handleClick = useCallback(async (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n setBusy(true);\n try {\n const files = await pickFiles();\n if (files.length) onFiles?.(files);\n } catch (error) {\n if (onError) onError(error);\n else console.error(error);\n } finally {\n if (mounted.current) setBusy(false);\n }\n }, [onClick, onFiles, onError, pickFiles]);\n\n return (\n <button ref={ref} type={type ?? \"button\"} disabled={disabled || busy} aria-busy={busy || undefined} onClick={handleClick} {...buttonProps}>\n {children ?? \"From my phone\"}\n </button>\n );\n});\n"],"mappings":"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","names":["TokSharePick","TokSharePickButton"]}
package/package.json CHANGED
@@ -1,6 +1,73 @@
1
1
  {
2
2
  "name": "@tokshare/pick",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Let visitors send files from their phone to your website: a button, a QR code, and File objects in your page.",
5
+ "keywords": [
6
+ "file upload",
7
+ "phone",
8
+ "qr code",
9
+ "mobile upload",
10
+ "file picker",
11
+ "camera upload",
12
+ "react"
13
+ ],
14
+ "author": "Peter Torki (https://petertorki.tech)",
15
+ "license": "MIT",
16
+ "homepage": "https://tokshare.vercel.app",
17
+ "type": "module",
18
+ "main": "./dist/index.cjs",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js",
25
+ "require": "./dist/index.cjs"
26
+ },
27
+ "./react": {
28
+ "types": "./dist/react.d.ts",
29
+ "import": "./dist/react.js",
30
+ "require": "./dist/react.cjs"
31
+ },
32
+ "./picker.js": "./dist/picker.global.js"
33
+ },
34
+ "unpkg": "./dist/picker.global.js",
35
+ "jsdelivr": "./dist/picker.global.js",
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "sideEffects": [
45
+ "./dist/picker.global.js"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "test": "vitest run",
50
+ "typecheck": "tsc --noEmit",
51
+ "prepublishOnly": "tsup && vitest run"
52
+ },
53
+ "peerDependencies": {
54
+ "react": ">=17"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "react": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@tokshare/pick-protocol": "workspace:*",
63
+ "@types/react": "^19.3.0",
64
+ "@types/react-dom": "^19.3.0",
65
+ "happy-dom": "^18.0.1",
66
+ "react": "^19.3.1",
67
+ "react-dom": "^19.3.1",
68
+ "tsup": "^8.5.0",
69
+ "typescript": "^5.8.3",
70
+ "uqr": "^0.1.3",
71
+ "vitest": "^3.2.4"
72
+ }
73
+ }