@purple-brock/burrow-web 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luke Price (The Purple Brock)
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 CHANGED
@@ -1,3 +1,14 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/lrprice79/badger-burrow/HEAD/assets/purple-brock-icon.png" width="120" alt="BadgerBurrow">
3
+ </p>
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ # @purple-brock/burrow-web
6
+
7
+ BadgerBurrow for React on the web — `<Chamber>` and `<Tunnel>` with pseudo states (`_hover`, `_focus`…), responsive props and SSR style collection.
8
+
9
+ **Needs:** React ≥ 18. ESM only.
10
+
11
+ Part of **BadgerBurrow** by The Purple Brock — see the
12
+ [main README and usage guide](https://github.com/lrprice79/badger-burrow#readme).
13
+
14
+ MIT © 2026 Luke Price (The Purple Brock)
@@ -0,0 +1,116 @@
1
+ import { BurrowSnapshot, ColorMode, BurrowBoxProps, BurrowTextProps } from '@purple-brock/burrow-core';
2
+ import React from 'react';
3
+
4
+ interface UseBurrowResult extends BurrowSnapshot {
5
+ setMode: (mode: ColorMode) => void;
6
+ }
7
+ /**
8
+ * Returns the current BadgerBurrow token snapshot and a setMode helper.
9
+ *
10
+ * Subscribes to BadgerBase via useSyncExternalStore — renders only when
11
+ * tokens or mode actually change. No ThemeProvider required anywhere in
12
+ * the tree.
13
+ *
14
+ * @example
15
+ * function MyButton() {
16
+ * const { tokens, mode, setMode } = useBurrow()
17
+ * return (
18
+ * <button style={{ background: tokens.primitive.color.primary[500] }}>
19
+ * Switch to {mode === 'light' ? 'dark' : 'light'}
20
+ * </button>
21
+ * )
22
+ * }
23
+ */
24
+ declare function useBurrow(): UseBurrowResult;
25
+
26
+ type ChamberTag = 'div' | 'section' | 'article' | 'aside' | 'header' | 'footer' | 'main' | 'nav' | 'button' | 'a' | 'form' | 'fieldset' | 'ul' | 'ol' | 'li' | 'figure' | 'figcaption' | 'label' | 'dialog' | 'details' | 'summary' | 'span';
27
+ interface ChamberProps extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>, BurrowBoxProps {
28
+ /** Element tag to render — defaults to div */
29
+ as?: ChamberTag;
30
+ /** Required when as="a" */
31
+ href?: string;
32
+ }
33
+ /**
34
+ * A styled box component backed by BadgerBurrow tokens.
35
+ * Accepts shorthand token props alongside all standard HTML props.
36
+ * Use `as` to render as any semantic element — button, nav, section, etc.
37
+ *
38
+ * Priority (lowest → highest): sx → named props → style
39
+ *
40
+ * Pseudo-state styling via _hover, _focus, _active, _focusVisible, _disabled.
41
+ * Smart hover bg: if `bg` is a primitive path, hover bg auto-steps one shade darker.
42
+ * Use `hoverScale` to specify which colour scale to step on, `hoverShade` for an
43
+ * exact shade, or `hoverScale={false}` to disable the smart default entirely.
44
+ *
45
+ * @example
46
+ * <Chamber
47
+ * as="button"
48
+ * bg="color.interactive.primary"
49
+ * px="space.4" py="space.2"
50
+ * radius="radius.md"
51
+ * _hover={{ bg: 'color.interactive.primary.hover', cursor: 'pointer' }}
52
+ * _disabled={{ opacity: 0.4, cursor: 'not-allowed' }}
53
+ * onClick={handleClick}
54
+ * />
55
+ */
56
+ declare const Chamber: React.ForwardRefExoticComponent<ChamberProps & React.RefAttributes<HTMLElement>>;
57
+
58
+ type TunnelTag = 'span' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label';
59
+ interface TunnelProps extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>, BurrowTextProps {
60
+ /** Element tag to render — defaults to span */
61
+ as?: TunnelTag;
62
+ }
63
+ /**
64
+ * The text component. Every piece of visible text in your UI goes in a Tunnel —
65
+ * headings, body copy, labels, captions, error messages.
66
+ *
67
+ * Tunnel has no layout props. Use a Chamber to position or space text alongside
68
+ * other elements.
69
+ *
70
+ * Priority (lowest → highest): sx → named props → style
71
+ *
72
+ * @example
73
+ * <Tunnel as="h1" fontSize="fontSize.2xl" fontWeight="fontWeight.bold" color="color.text.primary">
74
+ * Page title
75
+ * </Tunnel>
76
+ *
77
+ * <Tunnel as="p" color="color.text.secondary" lineHeight="lineHeight.relaxed">
78
+ * Body copy here.
79
+ * </Tunnel>
80
+ */
81
+ declare const Tunnel: React.ForwardRefExoticComponent<TunnelProps & React.RefAttributes<HTMLElement>>;
82
+
83
+ interface BurrowStyleRegistry {
84
+ /** Run a synchronous render with this registry active; returns its result. */
85
+ collect<T>(fn: () => T): T;
86
+ /** A single `<style>` tag string with every collected rule — emit in <head>. */
87
+ styleTags(): string;
88
+ /** Forget all collected rules (reuse the registry for another request). */
89
+ clear(): void;
90
+ }
91
+ /**
92
+ * Server-side style collection (provider-less, framework-agnostic). Pseudo and
93
+ * responsive rules aren't injected on the server (there's no DOM), so collect
94
+ * them during `renderToString` and emit them into the document `<head>`:
95
+ *
96
+ * const registry = createStyleRegistry()
97
+ * const html = registry.collect(() => renderToString(<App />))
98
+ * // <head> … {registry.styleTags()} … </head><body>{html}</body>
99
+ *
100
+ * On the client, the emitted tag carries `data-bb-ids`; `adoptServerStyles()`
101
+ * (run automatically on import) seeds the cache from it so hydration never
102
+ * re-injects or duplicates those rules.
103
+ *
104
+ * Synchronous SSR only (`renderToString`) — the active registry is a module
105
+ * global set around `collect`, which is safe because Node runs sync code without
106
+ * interleaving. Not for streaming/async SSR.
107
+ */
108
+ declare function createStyleRegistry(): BurrowStyleRegistry;
109
+ /**
110
+ * Seed the injection cache from a server-rendered `[data-bb-ssr]` tag so the
111
+ * client skips re-injecting (and thus never duplicates) SSR'd rules. Runs once
112
+ * automatically on import; exported for tests.
113
+ */
114
+ declare function adoptServerStyles(): void;
115
+
116
+ export { type BurrowStyleRegistry, Chamber, type ChamberProps, Tunnel, type TunnelProps, type UseBurrowResult, adoptServerStyles, createStyleRegistry, useBurrow };
package/dist/index.mjs ADDED
@@ -0,0 +1,330 @@
1
+ // src/useBurrow.ts
2
+ import { useSyncExternalStore } from "react";
3
+ import { BadgerBase } from "@purple-brock/burrow-core";
4
+ function useBurrow() {
5
+ const snapshot = useSyncExternalStore(
6
+ BadgerBase.subscribe,
7
+ BadgerBase.getSnapshot,
8
+ BadgerBase.getSnapshot
9
+ );
10
+ return {
11
+ tokens: snapshot.tokens,
12
+ mode: snapshot.mode,
13
+ setMode: BadgerBase.setMode
14
+ };
15
+ }
16
+
17
+ // src/Chamber.tsx
18
+ import React2 from "react";
19
+ import {
20
+ resolveSx,
21
+ buildBoxStyles,
22
+ buildPseudoStyles,
23
+ toClassName,
24
+ BURROW_BOX_KEYS,
25
+ splitResponsiveProps,
26
+ getBreakpointOrder
27
+ } from "@purple-brock/burrow-core";
28
+
29
+ // src/styleInjector.ts
30
+ var ATTR = "data-bb";
31
+ var RESPONSIVE_ATTR = "data-bb-responsive";
32
+ var _injected = /* @__PURE__ */ new Set();
33
+ var _registry = null;
34
+ function createStyleRegistry() {
35
+ const map = /* @__PURE__ */ new Map();
36
+ return {
37
+ collect(fn) {
38
+ const prev = _registry;
39
+ _registry = map;
40
+ try {
41
+ return fn();
42
+ } finally {
43
+ _registry = prev;
44
+ }
45
+ },
46
+ styleTags() {
47
+ if (map.size === 0) return "";
48
+ const ids = [...map.keys()].join(" ");
49
+ const css = [...map.values()].join("\n");
50
+ return `<style data-bb-ssr data-bb-ids="${ids}">${css}</style>`;
51
+ },
52
+ clear() {
53
+ map.clear();
54
+ }
55
+ };
56
+ }
57
+ function adoptServerStyles() {
58
+ if (typeof document === "undefined") return;
59
+ const ssr = document.querySelector("style[data-bb-ssr]");
60
+ const ids = ssr?.getAttribute("data-bb-ids");
61
+ if (ids) for (const id of ids.split(" ")) _injected.add(id);
62
+ }
63
+ adoptServerStyles();
64
+ function stableStringify(obj) {
65
+ const sorted = {};
66
+ for (const key of Object.keys(obj).sort()) {
67
+ const value = obj[key];
68
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
69
+ const inner = {};
70
+ for (const k of Object.keys(value).sort()) {
71
+ inner[k] = value[k];
72
+ }
73
+ sorted[key] = inner;
74
+ } else {
75
+ sorted[key] = value;
76
+ }
77
+ }
78
+ return JSON.stringify(sorted);
79
+ }
80
+ function toKebab(prop) {
81
+ return prop.replace(/([A-Z])/g, "-$1").toLowerCase();
82
+ }
83
+ function styleObjectToCss(styles, important = false) {
84
+ const suffix = important ? " !important" : "";
85
+ return Object.entries(styles).filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => `${toKebab(k)}: ${v}${suffix};`).join(" ");
86
+ }
87
+ function pseudoSelector(pseudo) {
88
+ if (pseudo === "focusVisible") return "focus-visible";
89
+ return pseudo;
90
+ }
91
+ function injectPseudoRule(className, pseudo, styles) {
92
+ const id = `${className}:${pseudo}`;
93
+ if (_registry) {
94
+ if (_registry.has(id)) return;
95
+ const css2 = styleObjectToCss(styles, true);
96
+ if (css2) _registry.set(id, `.${className}:${pseudoSelector(pseudo)} { ${css2} }`);
97
+ return;
98
+ }
99
+ if (typeof document === "undefined") return;
100
+ if (_injected.has(id)) return;
101
+ const css = styleObjectToCss(styles, true);
102
+ if (!css) return;
103
+ const rule = `.${className}:${pseudoSelector(pseudo)} { ${css} }`;
104
+ const existing = document.head.querySelector(`[${ATTR}="${id}"]`);
105
+ _injected.add(id);
106
+ if (existing) {
107
+ if (existing.textContent !== rule) existing.textContent = rule;
108
+ return;
109
+ }
110
+ const tag = document.createElement("style");
111
+ tag.setAttribute(ATTR, id);
112
+ tag.textContent = rule;
113
+ document.head.appendChild(tag);
114
+ }
115
+ function injectPseudoStyles(className, pseudoStyles) {
116
+ for (const [pseudo, styles] of Object.entries(pseudoStyles)) {
117
+ injectPseudoRule(className, pseudo, styles);
118
+ }
119
+ }
120
+ function injectResponsiveStyles(className, bpStyles, breakpoints) {
121
+ const id = `resp:${className}`;
122
+ const rules = [];
123
+ const baseStyles = bpStyles.base;
124
+ if (baseStyles) {
125
+ const css = styleObjectToCss(baseStyles);
126
+ if (css) rules.push(`.${className} { ${css} }`);
127
+ }
128
+ const ordered = Object.entries(breakpoints).map(([bp, minWidth]) => ({ bp, minWidth, px: parseInt(minWidth, 10) })).sort((a, b) => a.px - b.px);
129
+ for (const { bp, minWidth } of ordered) {
130
+ const styles = bpStyles[bp];
131
+ if (!styles) continue;
132
+ const css = styleObjectToCss(styles);
133
+ if (!css) continue;
134
+ rules.push(`@media (min-width: ${minWidth}) { .${className} { ${css} } }`);
135
+ }
136
+ if (rules.length === 0) return;
137
+ const content = rules.join("\n");
138
+ if (_registry) {
139
+ if (!_registry.has(id)) _registry.set(id, content);
140
+ return;
141
+ }
142
+ if (typeof document === "undefined") return;
143
+ if (_injected.has(id)) return;
144
+ const existing = document.head.querySelector(`[${RESPONSIVE_ATTR}="${className}"]`);
145
+ _injected.add(id);
146
+ if (existing) {
147
+ if (existing.textContent !== content) existing.textContent = content;
148
+ return;
149
+ }
150
+ const tag = document.createElement("style");
151
+ tag.setAttribute(RESPONSIVE_ATTR, className);
152
+ tag.textContent = content;
153
+ document.head.appendChild(tag);
154
+ }
155
+
156
+ // src/useDebug.ts
157
+ import { useRef, useLayoutEffect } from "react";
158
+ var DEBUG_COLOR = "#c026d3";
159
+ function useDebug(enabled, info) {
160
+ const ref = useRef(null);
161
+ const renders = useRef(0);
162
+ renders.current += 1;
163
+ const on = process.env.NODE_ENV !== "production" && !!enabled;
164
+ useLayoutEffect(() => {
165
+ if (!on) return;
166
+ const el = ref.current;
167
+ const r = el?.getBoundingClientRect();
168
+ const size = r ? `${Math.round(r.width)}\xD7${Math.round(r.height)}` : "?";
169
+ console.groupCollapsed(
170
+ `%c[bb] ${info.component} <${info.tag}> \u27F3${renders.current} \xB7 ${size} \xB7 ${info.mode}`,
171
+ `color:${DEBUG_COLOR};font-weight:bold`
172
+ );
173
+ console.table(info.style);
174
+ console.groupEnd();
175
+ });
176
+ if (!on) return { debugRef: ref };
177
+ return { debugRef: ref, outline: `1px dashed ${DEBUG_COLOR}`, attr: `\u27F3${renders.current}` };
178
+ }
179
+ function mergeRefs(...refs) {
180
+ return (node) => {
181
+ for (const ref of refs) {
182
+ if (!ref) continue;
183
+ if (typeof ref === "function") ref(node);
184
+ else ref.current = node;
185
+ }
186
+ };
187
+ }
188
+
189
+ // src/Chamber.tsx
190
+ import { jsx } from "react/jsx-runtime";
191
+ var Chamber = React2.forwardRef(function Chamber2({ as: Tag = "div", sx, style, children, __debug, ...props }, ref) {
192
+ const { tokens, mode } = useBurrow();
193
+ const burrowProps = {};
194
+ const htmlProps = {};
195
+ for (const [key, value] of Object.entries(props)) {
196
+ if (BURROW_BOX_KEYS.has(key)) burrowProps[key] = value;
197
+ else htmlProps[key] = value;
198
+ }
199
+ const { baseProps, responsiveProps } = splitResponsiveProps(burrowProps, tokens.breakpoints);
200
+ const boxPropsTyped = baseProps;
201
+ const inlineProps = {};
202
+ for (const key in baseProps) {
203
+ if (!(key in responsiveProps)) inlineProps[key] = baseProps[key];
204
+ }
205
+ const tokenStyles = buildBoxStyles(inlineProps, tokens, mode);
206
+ const sxStyles = sx ? resolveSx(sx, tokens, mode) : {};
207
+ const pseudoStyles = buildPseudoStyles(boxPropsTyped, tokens, mode);
208
+ const hasPseudo = Object.keys(pseudoStyles).length > 0;
209
+ const hasResponsive = Object.keys(responsiveProps).length > 0;
210
+ const breakpoints = tokens.breakpoints ?? {};
211
+ let bpStyles;
212
+ if (hasResponsive) {
213
+ const bpOrder = getBreakpointOrder(breakpoints);
214
+ bpStyles = {};
215
+ for (const bp of bpOrder) {
216
+ const bpProps = {};
217
+ for (const [key, obj] of Object.entries(responsiveProps)) {
218
+ const bpObj = obj;
219
+ if (bp in bpObj && bpObj[bp] !== void 0) bpProps[key] = bpObj[bp];
220
+ }
221
+ if (Object.keys(bpProps).length > 0) {
222
+ bpStyles[bp] = buildBoxStyles(bpProps, tokens, mode);
223
+ }
224
+ }
225
+ }
226
+ const className = hasPseudo || hasResponsive ? toClassName(JSON.stringify(pseudoStyles) + stableStringify(bpStyles ?? {}) + mode) : void 0;
227
+ if (hasPseudo && className) {
228
+ injectPseudoStyles(className, pseudoStyles);
229
+ }
230
+ if (hasResponsive && className && bpStyles) {
231
+ injectResponsiveStyles(className, bpStyles, breakpoints);
232
+ }
233
+ const resolvedStyle = { ...sxStyles, ...tokenStyles, ...style };
234
+ const dbg = useDebug(__debug, { component: "Chamber", tag: String(Tag), mode, style: resolvedStyle });
235
+ const Component = Tag;
236
+ const { className: userClassName, ...restHtmlProps } = htmlProps;
237
+ const mergedClassName = [className, userClassName].filter(Boolean).join(" ") || void 0;
238
+ const combinedRef = React2.useMemo(() => mergeRefs(ref, dbg.debugRef), [ref, dbg.debugRef]);
239
+ return /* @__PURE__ */ jsx(
240
+ Component,
241
+ {
242
+ ref: combinedRef,
243
+ className: mergedClassName,
244
+ style: dbg.outline ? { ...resolvedStyle, outline: dbg.outline } : resolvedStyle,
245
+ ...dbg.attr ? { "data-bb-debug": dbg.attr } : {},
246
+ ...restHtmlProps,
247
+ children
248
+ }
249
+ );
250
+ });
251
+
252
+ // src/Tunnel.tsx
253
+ import React3 from "react";
254
+ import {
255
+ resolveSx as resolveSx2,
256
+ buildTextStyles,
257
+ buildTextPseudoStyles,
258
+ toClassName as toClassName2,
259
+ BURROW_TEXT_KEYS,
260
+ splitResponsiveProps as splitResponsiveProps2,
261
+ getBreakpointOrder as getBreakpointOrder2
262
+ } from "@purple-brock/burrow-core";
263
+ import { jsx as jsx2 } from "react/jsx-runtime";
264
+ var Tunnel = React3.forwardRef(function Tunnel2({ as: Tag = "span", sx, style, children, __debug, ...props }, ref) {
265
+ const { tokens, mode } = useBurrow();
266
+ const burrowProps = {};
267
+ const htmlProps = {};
268
+ for (const [key, value] of Object.entries(props)) {
269
+ if (BURROW_TEXT_KEYS.has(key)) burrowProps[key] = value;
270
+ else htmlProps[key] = value;
271
+ }
272
+ const { baseProps, responsiveProps } = splitResponsiveProps2(burrowProps, tokens.breakpoints);
273
+ const textPropsTyped = baseProps;
274
+ const inlineProps = {};
275
+ for (const key in baseProps) {
276
+ if (!(key in responsiveProps)) inlineProps[key] = baseProps[key];
277
+ }
278
+ const tokenStyles = buildTextStyles(inlineProps, tokens, mode);
279
+ const sxStyles = sx ? resolveSx2(sx, tokens, mode) : {};
280
+ const pseudoStyles = buildTextPseudoStyles(textPropsTyped, tokens, mode);
281
+ const hasPseudo = Object.keys(pseudoStyles).length > 0;
282
+ const hasResponsive = Object.keys(responsiveProps).length > 0;
283
+ const breakpoints = tokens.breakpoints ?? {};
284
+ let bpStyles;
285
+ if (hasResponsive) {
286
+ const bpOrder = getBreakpointOrder2(breakpoints);
287
+ bpStyles = {};
288
+ for (const bp of bpOrder) {
289
+ const bpProps = {};
290
+ for (const [key, obj] of Object.entries(responsiveProps)) {
291
+ const bpObj = obj;
292
+ if (bp in bpObj && bpObj[bp] !== void 0) bpProps[key] = bpObj[bp];
293
+ }
294
+ if (Object.keys(bpProps).length > 0) {
295
+ bpStyles[bp] = buildTextStyles(bpProps, tokens, mode);
296
+ }
297
+ }
298
+ }
299
+ const className = hasPseudo || hasResponsive ? toClassName2(JSON.stringify(pseudoStyles) + stableStringify(bpStyles ?? {}) + mode) : void 0;
300
+ if (hasPseudo && className) {
301
+ injectPseudoStyles(className, pseudoStyles);
302
+ }
303
+ if (hasResponsive && className && bpStyles) {
304
+ injectResponsiveStyles(className, bpStyles, breakpoints);
305
+ }
306
+ const resolvedStyle = { ...sxStyles, ...tokenStyles, ...style };
307
+ const dbg = useDebug(__debug, { component: "Tunnel", tag: String(Tag), mode, style: resolvedStyle });
308
+ const Component = Tag;
309
+ const { className: userClassName, ...restHtmlProps } = htmlProps;
310
+ const mergedClassName = [className, userClassName].filter(Boolean).join(" ") || void 0;
311
+ const combinedRef = React3.useMemo(() => mergeRefs(ref, dbg.debugRef), [ref, dbg.debugRef]);
312
+ return /* @__PURE__ */ jsx2(
313
+ Component,
314
+ {
315
+ ref: combinedRef,
316
+ className: mergedClassName,
317
+ style: dbg.outline ? { ...resolvedStyle, outline: dbg.outline } : resolvedStyle,
318
+ ...dbg.attr ? { "data-bb-debug": dbg.attr } : {},
319
+ ...restHtmlProps,
320
+ children
321
+ }
322
+ );
323
+ });
324
+ export {
325
+ Chamber,
326
+ Tunnel,
327
+ adoptServerStyles,
328
+ createStyleRegistry,
329
+ useBurrow
330
+ };
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@purple-brock/burrow-web",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "main": "./dist/index.mjs",
5
+ "types": "./dist/index.d.mts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.mts",
9
+ "import": "./dist/index.mjs",
10
+ "default": "./dist/index.mjs"
11
+ }
12
+ },
13
+ "dependencies": {
14
+ "@purple-brock/burrow-core": "0.1.0",
15
+ "@purple-brock/burrow-tokens": "0.1.0"
16
+ },
17
+ "devDependencies": {
18
+ "@testing-library/react": "^14.3.1",
19
+ "@types/jest": "^29.5.14",
20
+ "@types/react": "^18.3.31",
21
+ "jest": "^29.7.0",
22
+ "jest-environment-jsdom": "^29.7.0",
23
+ "react": "^18.3.1",
24
+ "react-dom": "^18.3.1",
25
+ "ts-jest": "^29.4.15",
26
+ "tsup": "^8.5.1",
27
+ "typescript": "^5.9.3"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=18.0.0"
31
+ },
32
+ "license": "MIT",
33
+ "files": [
34
+ "dist",
35
+ "LICENSE",
36
+ "README.md"
37
+ ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "sideEffects": false,
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/lrprice79/badger-burrow.git",
45
+ "directory": "packages/web"
46
+ },
47
+ "scripts": {
48
+ "build": "tsup src/index.ts --format esm --dts",
49
+ "test": "jest --passWithNoTests",
50
+ "typecheck": "tsc --noEmit -p tsconfig.json"
51
+ }
6
52
  }