From 9103997b1c96c9926fc5c1d5494235ae08b34d35 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Tue, 4 Aug 2026 19:10:01 +0000
Subject: [PATCH 01/16] =?UTF-8?q?feat(release):=20LinkButton=20(inherit/ac?=
=?UTF-8?q?cent=20color,=20sizes=20=E2=80=94=20fixes=20the=20"fixed=20ambe?=
=?UTF-8?q?r=20style"=20complaint)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Refs: IDEA-3
---
papercamp/config.json | 3 +-
papercamp/ideas/IDEA-3.md | 2 +-
papercamp/run-order.md | 1 -
src/components/link-button/index.ts | 2 +
.../link-button/link-button.module.scss | 60 +++++++++++++++++++
src/components/link-button/link-button.tsx | 28 +++++++++
src/index.ts | 3 +
7 files changed, 96 insertions(+), 3 deletions(-)
create mode 100644 src/components/link-button/index.ts
create mode 100644 src/components/link-button/link-button.module.scss
create mode 100644 src/components/link-button/link-button.tsx
diff --git a/papercamp/config.json b/papercamp/config.json
index 9dc702d..6139b61 100644
--- a/papercamp/config.json
+++ b/papercamp/config.json
@@ -26,5 +26,6 @@
"model": "sonnet",
"effort": "low"
}
- }
+ },
+ "port": 3041
}
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index bf9ae5b..601429a 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -14,7 +14,7 @@ The bespoke-UI census found ~28 hand-rolled chrome-less buttons across 10 files,
Skipped for the initial release (no demand from either target inventory): Accordion, Pagination, Avatar, PropTable, Swatch, Island, and the Layout/Page god-components (Backdrop+Glass composition replaces them). Radio/RadioGroup, Tabs, and the table story moved to the radio-parity tier ([[IDEA-7]]) now that the radio project is the target consumer.
### Phases
-- [ ] LinkButton (inherit/accent color, sizes — fixes the "fixed amber style" complaint)
+- [x] LinkButton (inherit/accent color, sizes — fixes the "fixed amber style" complaint)
- [ ] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
- [ ] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
- [ ] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
diff --git a/papercamp/run-order.md b/papercamp/run-order.md
index a2e30ee..073faa8 100644
--- a/papercamp/run-order.md
+++ b/papercamp/run-order.md
@@ -1,4 +1,3 @@
-IDEA-2 — Tier 2 — form controls and overlays
IDEA-3 — Tier 3 — gap-fillers paper-ui never had
IDEA-4 — Showcase gallery entries for every release component
IDEA-7 — Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu
diff --git a/src/components/link-button/index.ts b/src/components/link-button/index.ts
new file mode 100644
index 0000000..54a7133
--- /dev/null
+++ b/src/components/link-button/index.ts
@@ -0,0 +1,2 @@
+export { LinkButton } from './link-button';
+export type { LinkButtonProps } from './link-button';
diff --git a/src/components/link-button/link-button.module.scss b/src/components/link-button/link-button.module.scss
new file mode 100644
index 0000000..f8837da
--- /dev/null
+++ b/src/components/link-button/link-button.module.scss
@@ -0,0 +1,60 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.linkButton {
+ display: inline-flex;
+ align-items: center;
+ gap: $space-1;
+ padding: 0;
+ border: none;
+ background: none;
+ cursor: pointer;
+ font-family: $font-family-sans;
+ font-weight: 600;
+ line-height: 1.2;
+ text-decoration: underline;
+ text-underline-offset: 3px;
+ text-decoration-thickness: 1px;
+ transition:
+ color 200ms ease,
+ text-decoration-thickness 120ms ease,
+ opacity 200ms ease;
+
+ &:hover:not(:disabled) {
+ text-decoration-thickness: 2px;
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+.inherit {
+ color: inherit;
+}
+
+.accent {
+ color: var(--fui-accent);
+}
+
+.sm {
+ font-size: $font-size-sm;
+}
+
+.md {
+ font-size: $font-size-md;
+}
+
+.lg {
+ font-size: $font-size-lg;
+}
+
+.iconSlot {
+ display: inline-flex;
+ align-items: center;
+}
diff --git a/src/components/link-button/link-button.tsx b/src/components/link-button/link-button.tsx
new file mode 100644
index 0000000..1c0dc44
--- /dev/null
+++ b/src/components/link-button/link-button.tsx
@@ -0,0 +1,28 @@
+import { type ButtonHTMLAttributes, type ReactNode, forwardRef } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './link-button.module.scss';
+
+export interface LinkButtonProps extends ButtonHTMLAttributes {
+ color?: 'inherit' | 'accent';
+ size?: 'sm' | 'md' | 'lg';
+ icon?: ReactNode;
+ iconRight?: ReactNode;
+}
+
+export const LinkButton = forwardRef(function LinkButton(
+ { color = 'accent', size = 'md', icon, iconRight, className, children, ...props },
+ ref,
+) {
+ return (
+
+ );
+});
diff --git a/src/index.ts b/src/index.ts
index c6d522b..62c40fa 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,6 +18,9 @@ export type { ButtonProps } from './components/button';
export { IconButton } from './components/icon-button';
export type { IconButtonProps } from './components/icon-button';
+export { LinkButton } from './components/link-button';
+export type { LinkButtonProps } from './components/link-button';
+
export { Stamp } from './components/stamp';
export type { StampProps, StampVariant } from './components/stamp';
From 0cc7e18e999fe8c05d7a9b44f99840ffab4c5a97 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 15:28:48 +0000
Subject: [PATCH 02/16] =?UTF-8?q?feat(repo):=20Tier=203=20=E2=80=94=20gap-?=
=?UTF-8?q?fillers=20paper-ui=20never=20had?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package.json | 13 +-
papercamp/config.json | 2 +-
papercamp/ideas/IDEA-3.md | 8 +
papercamp/ideas/IDEA-9.md | 24 +
papercamp/ideas/index.md | 14 +-
papercamp/run-order.md | 1 +
pnpm-lock.yaml | 1557 +---------------------
src/components/glass/glass.tsx | 5 +-
src/components/select/select.module.scss | 4 +-
src/showcase.tsx | 4 +-
src/styles/_mixins.scss | 26 +-
vite.config.ts | 2 +
12 files changed, 93 insertions(+), 1567 deletions(-)
create mode 100644 papercamp/ideas/IDEA-9.md
diff --git a/package.json b/package.json
index e55295e..0b339be 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,10 @@
"version": "0.1.1",
"description": "Glossy, noisy, cosy React component library — frosted glass, film grain, and lava glow",
"type": "module",
- "sideEffects": ["**/*.css", "**/*.scss"],
+ "sideEffects": [
+ "**/*.css",
+ "**/*.scss"
+ ],
"packageManager": "pnpm@10.12.1",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
@@ -74,7 +77,7 @@
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
- "@dendelion/paper-camp": "^0.13.1",
+ "@dendelion/paper-camp": "link:../paper-camp-island",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.7.1",
@@ -93,6 +96,10 @@
"vite-plugin-dts": "^4.5.4"
},
"pnpm": {
- "onlyBuiltDependencies": ["@biomejs/biome", "@swc/core", "esbuild"]
+ "onlyBuiltDependencies": [
+ "@biomejs/biome",
+ "@swc/core",
+ "esbuild"
+ ]
}
}
diff --git a/papercamp/config.json b/papercamp/config.json
index 6139b61..16efe15 100644
--- a/papercamp/config.json
+++ b/papercamp/config.json
@@ -3,7 +3,7 @@
"projectName": "film-ui",
"initializedAt": "2026-08-04T14:52:35.357Z",
"nextId": {
- "idea": 9
+ "idea": 10
},
"defaultAgents": {
"phase": {
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 601429a..5863922 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -4,9 +4,11 @@ title: Tier 3 — gap-fillers paper-ui never had
type: feat
status: planned
created: 2026-08-04
+updated: 2026-08-07
tags:
- components
- release
+order: 1
---
The bespoke-UI census found ~28 hand-rolled chrome-less buttons across 10 files, ~20 loading/empty/error text states, 13 app-local icons plus text-glyph fallbacks with comments naming the missing icon, two inconsistent drawers, and duplicated diff/code/chip/dot patterns. These components make func-ui a genuine upgrade rather than a re-skin.
@@ -22,3 +24,9 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [ ] CopyButton + Breadcrumb + Menu + FileButton
- [ ] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [ ] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
+
+### Thread
+- [x] 2026-08-07 [chat] Quick test from the embedded toolbar — just reply with a short hello.
+- [x] 2026-08-07 [chat] [agent] Hello — Paper Scout here, reading you loud and clear.
+- [x] 2026-08-07 [chat] just checking
+- [x] 2026-08-07 [chat] [agent] Just checking, got it — nothing to change here.
diff --git a/papercamp/ideas/IDEA-9.md b/papercamp/ideas/IDEA-9.md
new file mode 100644
index 0000000..a6e0613
--- /dev/null
+++ b/papercamp/ideas/IDEA-9.md
@@ -0,0 +1,24 @@
+---
+id: IDEA-9
+title: Glass frost flickers on scroll — move the filter off the scroller's ancestry
+type: fix
+status: review
+created: 2026-08-05
+tags:
+ - components
+ - rendering
+---
+
+The frosted panel flickered during small scrolls on macOS Chrome, reproduced and diagnosed live in the owner's browser via a striped test element behind the panel: in steady state the blur smears it correctly; on a scroll tick the blurred wash vanished for a frame — the backdrop-filter transiently drops while its render surface is invalidated.
+
+Root cause: the original flicker fix moved the blur off the scroll *element* but the Glass host remained the scroller's **ancestor**, so inner-scroll invalidations still propagated into the filter's render surface. Chromium then transiently mis-composites the blur.
+
+Fix: the frost now lives on a `::before` layer inside Glass — a *sibling* of the scrolling content, absolutely positioned behind it (`z-index: -1`, host gets `z-index: 0`, no `isolation` — that would create a backdrop root and break sampling). Inner scrolling can no longer touch the filter. `blur={0}` travels as `--fui-glass-backdrop: none`; the blur radius stays on `--fui-glass-blur`. Verified with the same probe: the wash now survives scroll ticks in both directions.
+
+Also fixed in passing: Select's dropdown carried a raw `backdrop-filter: blur(12px)` without the `--fui-nested-backdrop` switch — a latent nested-filter regression whenever it opens inside a Glass surface.
+
+### Phases
+- [x] Move the frost to a ::before sibling layer in the glass mixin
+- [x] Route blur={0} and blur radius through custom properties to the pseudo
+- [x] Verify live on the affected machine (probe wash survives scroll ticks)
+- [x] Give Select's dropdown the --fui-nested-backdrop switch
diff --git a/papercamp/ideas/index.md b/papercamp/ideas/index.md
index 8ee5fd2..0b36dbf 100644
--- a/papercamp/ideas/index.md
+++ b/papercamp/ideas/index.md
@@ -1,3 +1,13 @@
-# film-ui
+# Ideas
-What are you building, and why?
+| Id | Title | Type | Status | Tags |
+|----|-------|------|--------|------|
+| IDEA-1 | Tier 1 — the six workhorse components | feat | done | components, release |
+| IDEA-2 | Tier 2 — form controls and overlays | feat | done | components, release |
+| IDEA-3 | Tier 3 — gap-fillers paper-ui never had | feat | in-progress | components, release |
+| IDEA-4 | Showcase gallery entries for every release component | docs | planned | showcase, release |
+| IDEA-5 | Migrate paper-camp from paper-ui to func-ui | feat | dropped | migration |
+| IDEA-6 | Adopt func-ui in the radio project (replace mojo-ui) | feat | idea | migration, radio |
+| IDEA-7 | Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu | feat | planned | components, release, radio |
+| IDEA-8 | Adopt branch-per-idea working flow | chore | idea | workflow |
+| IDEA-9 | Glass frost flickers on scroll — move the filter off the scroller's ancestry | fix | review | components, rendering |
diff --git a/papercamp/run-order.md b/papercamp/run-order.md
index 073faa8..aa0ecf6 100644
--- a/papercamp/run-order.md
+++ b/papercamp/run-order.md
@@ -1,3 +1,4 @@
IDEA-3 — Tier 3 — gap-fillers paper-ui never had
IDEA-4 — Showcase gallery entries for every release component
IDEA-7 — Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu
+IDEA-9 — Glass frost flickers on scroll — move the filter off the scroller's ancestry
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 89674ef..6cee49e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -22,8 +22,8 @@ importers:
specifier: ^1.9.4
version: 1.9.4
'@dendelion/paper-camp':
- specifier: ^0.13.1
- version: 0.13.1(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ specifier: link:../paper-camp-island
+ version: link:../paper-camp-island
'@types/react':
specifier: ^18.3.12
version: 18.3.31
@@ -206,20 +206,6 @@ packages:
peerDependencies:
postcss-selector-parser: ^7.1.1
- '@dendelion/paper-camp@0.13.1':
- resolution: {integrity: sha512-NL2JCXZaenGXdKJRRdd8ymPGOjMYdMowppOj/s3NfEpf6ItaAIEdFmU4x2Gi9jbcs7h3XtchHkMk76aArcysKA==}
- engines: {bun: '>=1.0.0', node: '>=18.0.0'}
- hasBin: true
- peerDependencies:
- react: ^18.0.0
- react-dom: ^18.0.0
-
- '@dendelion/paper-ui@0.12.0':
- resolution: {integrity: sha512-okEW7dVGnEQMDUyOV0zL05C5ebDNvzH+LK81YARvFdYqyG60TlB/mBp0+U31ZF616HMNkNBOdAWQrI6vRCFSuw==}
- peerDependencies:
- react: ^18.0.0
- react-dom: ^18.0.0
-
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
@@ -358,12 +344,6 @@ packages:
cpu: [x64]
os: [win32]
- '@hono/node-server@2.1.0':
- resolution: {integrity: sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==}
- engines: {node: '>=20'}
- peerDependencies:
- hono: ^4
-
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -399,16 +379,6 @@ packages:
'@microsoft/tsdoc@0.16.0':
resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==}
- '@modelcontextprotocol/sdk@1.30.0':
- resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==}
- engines: {node: '>=18'}
- peerDependencies:
- '@cfworker/json-schema': ^4.1.1
- zod: ^3.25 || ^4.0
- peerDependenciesMeta:
- '@cfworker/json-schema':
- optional: true
-
'@napi-rs/lzma-linux-x64-gnu@1.5.1':
resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==}
engines: {node: ^22.20 || ^24.12 || >=25}
@@ -765,51 +735,12 @@ packages:
'@swc/types@0.1.28':
resolution: {integrity: sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==}
- '@tanstack/history@1.162.0':
- resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==}
- engines: {node: '>=20.19'}
-
- '@tanstack/react-router@1.170.18':
- resolution: {integrity: sha512-wpbGYZEp/fmz1q4bn7BD8VZ+/VZ7GBqSJv5V969pU+chP8y7dquWDmKTFMohvUegb9lg12m1uPVvD6kB2wORvQ==}
- engines: {node: '>=20.19'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
- '@tanstack/react-store@0.9.3':
- resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- '@tanstack/router-core@1.171.15':
- resolution: {integrity: sha512-IILCDcLaItMZQ2jEmCABHY1Nhjjn5XUvwpQp3e4Nmu+vfg0BgYFuu/QASz2SwE2ZNbVMrvt8X/wxa+Gg5aErxA==}
- engines: {node: '>=20.19'}
-
- '@tanstack/store@0.9.3':
- resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==}
-
'@types/argparse@1.0.38':
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
- '@types/debug@4.1.13':
- resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==}
-
- '@types/estree-jsx@1.0.5':
- resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
-
'@types/estree@1.0.9':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
- '@types/hast@3.0.5':
- resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==}
-
- '@types/mdast@4.0.4':
- resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
-
- '@types/ms@2.1.0':
- resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
-
'@types/prop-types@15.7.15':
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
@@ -821,15 +752,6 @@ packages:
'@types/react@18.3.31':
resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==}
- '@types/unist@2.0.11':
- resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
-
- '@types/unist@3.0.3':
- resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
-
- '@ungap/structured-clone@1.3.3':
- resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==}
-
'@vitejs/plugin-react-swc@3.11.0':
resolution: {integrity: sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==}
peerDependencies:
@@ -864,10 +786,6 @@ packages:
'@vue/shared@3.5.40':
resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==}
- accepts@2.0.0:
- resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
- engines: {node: '>= 0.6'}
-
acorn@8.18.0:
resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==}
engines: {node: '>=0.4.0'}
@@ -937,9 +855,6 @@ packages:
peerDependencies:
postcss: ^8.1.0
- bail@2.0.2:
- resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
-
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -956,10 +871,6 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- body-parser@2.3.0:
- resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==}
- engines: {node: '>=18'}
-
brace-expansion@2.1.4:
resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==}
@@ -976,21 +887,9 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
- bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
-
cacheable@2.5.0:
resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==}
- call-bind-apply-helpers@1.0.2:
- resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
- engines: {node: '>= 0.4'}
-
- call-bound@1.0.4:
- resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
- engines: {node: '>= 0.4'}
-
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -1002,21 +901,6 @@ packages:
caniuse-lite@1.0.30001806:
resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==}
- ccount@2.0.1:
- resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
-
- character-entities-html4@2.1.0:
- resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
-
- character-entities-legacy@3.0.0:
- resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
-
- character-entities@2.0.2:
- resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
-
- character-reference-invalid@2.0.1:
- resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
-
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -1042,13 +926,6 @@ packages:
colorjs.io@0.5.2:
resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==}
- comma-separated-tokens@2.0.3:
- resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
-
- commander@12.1.0:
- resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
- engines: {node: '>=18'}
-
commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
@@ -1062,33 +939,6 @@ packages:
confbox@0.2.4:
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
- content-disposition@1.1.0:
- resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==}
- engines: {node: '>=18'}
-
- content-type@1.0.5:
- resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
- engines: {node: '>= 0.6'}
-
- content-type@2.0.0:
- resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==}
- engines: {node: '>=18'}
-
- cookie-es@3.1.1:
- resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==}
-
- cookie-signature@1.2.2:
- resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
- engines: {node: '>=6.6.0'}
-
- cookie@0.7.2:
- resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
- engines: {node: '>= 0.6'}
-
- cors@2.8.6:
- resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
- engines: {node: '>= 0.10'}
-
cosmiconfig@9.0.2:
resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==}
engines: {node: '>=14'}
@@ -1098,10 +948,6 @@ packages:
typescript:
optional: true
- cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
-
css-functions-list@3.3.3:
resolution: {integrity: sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==}
engines: {node: '>=12'}
@@ -1130,24 +976,10 @@ packages:
supports-color:
optional: true
- decode-named-character-reference@1.3.0:
- resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
-
- depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
-
- dequal@2.0.3:
- resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
- engines: {node: '>=6'}
-
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
- devlop@1.1.0:
- resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
-
didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
@@ -1158,23 +990,12 @@ packages:
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
- dunder-proto@1.0.1:
- resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
- engines: {node: '>= 0.4'}
-
- ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
-
electron-to-chromium@1.5.399:
resolution: {integrity: sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
- encodeurl@2.0.0:
- resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
- engines: {node: '>= 0.8'}
-
entities@7.0.1:
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
engines: {node: '>=0.12'}
@@ -1186,18 +1007,10 @@ packages:
error-ex@1.3.4:
resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
- es-define-property@1.0.1:
- resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
- engines: {node: '>= 0.4'}
-
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
- es-object-atoms@1.1.2:
- resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
- engines: {node: '>= 0.4'}
-
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -1207,43 +1020,12 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
- escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
-
- estree-util-is-identifier-name@3.0.0:
- resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==}
-
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
- etag@1.8.1:
- resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
- engines: {node: '>= 0.6'}
-
- eventsource-parser@3.1.0:
- resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==}
- engines: {node: '>=18.0.0'}
-
- eventsource@3.0.7:
- resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
- engines: {node: '>=18.0.0'}
-
- express-rate-limit@8.6.2:
- resolution: {integrity: sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==}
- engines: {node: '>= 16'}
- peerDependencies:
- express: '>= 4.11'
-
- express@5.2.1:
- resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
- engines: {node: '>= 18'}
-
exsolve@1.1.1:
resolution: {integrity: sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==}
- extend@3.0.2:
- resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
-
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1277,20 +1059,12 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
- finalhandler@2.1.1:
- resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
- engines: {node: '>= 18.0.0'}
-
flat-cache@6.1.23:
resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==}
flatted@3.4.4:
resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==}
- forwarded@0.2.0:
- resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
- engines: {node: '>= 0.6'}
-
fraction.js@5.3.4:
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
@@ -1308,10 +1082,6 @@ packages:
react-dom:
optional: true
- fresh@2.0.0:
- resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
- engines: {node: '>= 0.8'}
-
fs-extra@11.3.6:
resolution: {integrity: sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==}
engines: {node: '>=14.14'}
@@ -1328,14 +1098,6 @@ packages:
resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==}
engines: {node: '>=18'}
- get-intrinsic@1.3.0:
- resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
- engines: {node: '>= 0.4'}
-
- get-proto@1.0.1:
- resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
- engines: {node: '>= 0.4'}
-
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -1359,19 +1121,12 @@ packages:
globjoin@0.1.4:
resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==}
- gopd@1.2.0:
- resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
- engines: {node: '>= 0.4'}
-
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
gsap@3.15.0:
resolution: {integrity: sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==}
- hachure-fill@0.5.2:
- resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==}
-
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -1380,10 +1135,6 @@ packages:
resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==}
engines: {node: '>=12'}
- has-symbols@1.1.0:
- resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
- engines: {node: '>= 0.4'}
-
hashery@1.5.1:
resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==}
engines: {node: '>=20'}
@@ -1392,20 +1143,10 @@ packages:
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
- hast-util-to-jsx-runtime@2.3.6:
- resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
-
- hast-util-whitespace@3.0.0:
- resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
-
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
- hono@4.13.0:
- resolution: {integrity: sha512-jhunvfHWxd7J5EFfSgH4xsYJzSe/lfqbUCxiyyeaQasUsXeEHXtzVid+7EOGByc5JnFa23SSFL3Y2RV/z1T+eQ==}
- engines: {node: '>=16.9.0'}
-
hookified@1.15.1:
resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==}
@@ -1416,17 +1157,6 @@ packages:
resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==}
engines: {node: '>=20.10'}
- html-url-attributes@3.0.1:
- resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
-
- http-errors@2.0.1:
- resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
- engines: {node: '>= 0.8'}
-
- iconv-lite@0.7.3:
- resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==}
- engines: {node: '>=0.10.0'}
-
ignore@7.0.6:
resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==}
engines: {node: '>= 4'}
@@ -1445,29 +1175,9 @@ packages:
import-meta-resolve@4.2.0:
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
- inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
-
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
- inline-style-parser@0.2.7:
- resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
-
- ip-address@10.4.0:
- resolution: {integrity: sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==}
- engines: {node: '>= 12'}
-
- ipaddr.js@1.9.1:
- resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
- engines: {node: '>= 0.10'}
-
- is-alphabetical@2.0.1:
- resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
-
- is-alphanumerical@2.0.1:
- resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
-
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
@@ -1479,9 +1189,6 @@ packages:
resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==}
engines: {node: '>= 0.4'}
- is-decimal@2.0.1:
- resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
-
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -1494,9 +1201,6 @@ packages:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
- is-hexadecimal@2.0.1:
- resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==}
-
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
@@ -1505,17 +1209,6 @@ packages:
resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==}
engines: {node: '>=12'}
- is-plain-obj@4.1.0:
- resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
- engines: {node: '>=12'}
-
- is-promise@4.0.0:
- resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
-
- isbot@5.2.1:
- resolution: {integrity: sha512-dJ+LpKyClQZ7NG+j3OensC/mAZkGpukE9YUrgPYvAZj2doVL0edfDgywTUh5CXa0o+nW9a1V9e5+CJTX8+SxRw==}
- engines: {node: '>=18'}
-
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -1526,9 +1219,6 @@ packages:
jju@1.4.0:
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
- jose@6.2.8:
- resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==}
-
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1542,9 +1232,6 @@ packages:
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
- json-schema-typed@8.0.2:
- resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==}
-
jsonfile@6.2.1:
resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==}
@@ -1572,9 +1259,6 @@ packages:
lodash.truncate@4.4.2:
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
- longest-streak@3.1.0:
- resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
-
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -1582,131 +1266,24 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- math-intrinsics@1.1.0:
- resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
- engines: {node: '>= 0.4'}
-
mathml-tag-names@4.0.0:
resolution: {integrity: sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==}
- mdast-util-from-markdown@2.0.3:
- resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==}
-
- mdast-util-mdx-expression@2.0.1:
- resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==}
-
- mdast-util-mdx-jsx@3.2.0:
- resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==}
-
- mdast-util-mdxjs-esm@2.0.1:
- resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==}
-
- mdast-util-phrasing@4.1.0:
- resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
-
- mdast-util-to-hast@13.2.1:
- resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==}
-
- mdast-util-to-markdown@2.1.2:
- resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
-
- mdast-util-to-string@4.0.0:
- resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
-
mdn-data@2.27.1:
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
- media-typer@1.1.1:
- resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==}
- engines: {node: '>= 0.8'}
-
meow@14.1.0:
resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==}
engines: {node: '>=20'}
- merge-descriptors@2.0.0:
- resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
- engines: {node: '>=18'}
-
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
- micromark-core-commonmark@2.0.3:
- resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
-
- micromark-factory-destination@2.0.1:
- resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
-
- micromark-factory-label@2.0.1:
- resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==}
-
- micromark-factory-space@2.0.1:
- resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==}
-
- micromark-factory-title@2.0.1:
- resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==}
-
- micromark-factory-whitespace@2.0.1:
- resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==}
-
- micromark-util-character@2.1.1:
- resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
-
- micromark-util-chunked@2.0.1:
- resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==}
-
- micromark-util-classify-character@2.0.1:
- resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==}
-
- micromark-util-combine-extensions@2.0.1:
- resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==}
-
- micromark-util-decode-numeric-character-reference@2.0.2:
- resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==}
-
- micromark-util-decode-string@2.0.1:
- resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==}
-
- micromark-util-encode@2.0.1:
- resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
-
- micromark-util-html-tag-name@2.0.1:
- resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==}
-
- micromark-util-normalize-identifier@2.0.1:
- resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==}
-
- micromark-util-resolve-all@2.0.1:
- resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==}
-
- micromark-util-sanitize-uri@2.0.1:
- resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
-
- micromark-util-subtokenize@2.1.0:
- resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==}
-
- micromark-util-symbol@2.0.1:
- resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
-
- micromark-util-types@2.0.2:
- resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
-
- micromark@4.0.2:
- resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
-
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
- mime-db@1.54.0:
- resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
- engines: {node: '>= 0.6'}
-
- mime-types@3.0.2:
- resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
- engines: {node: '>=18'}
-
minimatch@10.2.3:
resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==}
engines: {node: 18 || 20 || >=22}
@@ -1742,16 +1319,9 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- negotiator@1.0.0:
- resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
- engines: {node: '>= 0.6'}
-
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
- node-pty@1.1.0:
- resolution: {integrity: sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==}
-
node-releases@2.0.51:
resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==}
engines: {node: '>=18'}
@@ -1768,17 +1338,6 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
- object-inspect@1.13.4:
- resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
- engines: {node: '>= 0.4'}
-
- on-finished@2.4.1:
- resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
- engines: {node: '>= 0.8'}
-
- once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
-
package-manager-detector@1.8.0:
resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==}
@@ -1786,33 +1345,16 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
- parse-entities@4.0.2:
- resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
-
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
- parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
-
path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
- path-data-parser@0.1.0:
- resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==}
-
- path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
-
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- path-to-regexp@8.4.2:
- resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
-
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
@@ -1835,22 +1377,12 @@ packages:
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
engines: {node: '>= 6'}
- pkce-challenge@5.0.1:
- resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
- engines: {node: '>=16.20.0'}
-
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
pkg-types@2.3.1:
resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==}
- points-on-curve@0.2.0:
- resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==}
-
- points-on-path@0.2.1:
- resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==}
-
postcss-import@15.1.0:
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
@@ -1914,13 +1446,6 @@ packages:
resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==}
engines: {node: ^10 || ^12 || >=14}
- property-information@7.2.0:
- resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==}
-
- proxy-addr@2.0.7:
- resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
- engines: {node: '>= 0.10'}
-
publint@0.3.22:
resolution: {integrity: sha512-6Z/scsr5CA7APdwyF35EY88CqgDj1textWuY788DVTJYPCWVv/Wn9G6KmLnrVRnStgYcahqN4wCDLZGSbQJ69w==}
engines: {node: '>=18'}
@@ -1930,35 +1455,17 @@ packages:
resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==}
engines: {node: '>=20'}
- qs@6.15.3:
- resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==}
- engines: {node: '>=0.6'}
-
quansync@0.2.11:
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- range-parser@1.3.0:
- resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==}
- engines: {node: '>= 0.6'}
-
- raw-body@3.0.2:
- resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
- engines: {node: '>= 0.10'}
-
react-dom@18.3.1:
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
peerDependencies:
react: ^18.3.1
- react-markdown@10.1.0:
- resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==}
- peerDependencies:
- '@types/react': '>=18'
- react: '>=18'
-
react@18.3.1:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
@@ -1974,12 +1481,6 @@ packages:
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
engines: {node: '>= 20.19.0'}
- remark-parse@11.0.0:
- resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
-
- remark-rehype@11.1.2:
- resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==}
-
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
@@ -2002,13 +1503,6 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- roughjs@4.6.6:
- resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
-
- router@2.2.0:
- resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
- engines: {node: '>= 18'}
-
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -2019,9 +1513,6 @@ packages:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
- safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
-
sass-embedded-all-unknown@1.100.0:
resolution: {integrity: sha512-auFtXY/kwYILmSVjtBDwyj0axcLbYYiffOKWoaXHnI5bsYwiRbBh3EneR1rpbX2ZIZCrwX93i5pxKLTZF/662Q==}
cpu: ['!arm', '!arm64', '!riscv64', '!x64']
@@ -2144,51 +1635,6 @@ packages:
engines: {node: '>=10'}
hasBin: true
- send@1.2.1:
- resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
- engines: {node: '>= 18'}
-
- seroval-plugins@1.6.2:
- resolution: {integrity: sha512-TfxuUjlbBESzUOWdTkTKqvSmav0ABym+itetDXLK6mDz8SmrpdI30aF8RTXE8Bvq+tH/1yIDkvy3W0lfQb1ipQ==}
- engines: {node: '>=10'}
- peerDependencies:
- seroval: ^1.0
-
- seroval@1.6.2:
- resolution: {integrity: sha512-mPT+SD2TrlB6wvte1KkYOYUkubaTbd6pZ/6Kk3C9nxzrHmCZyhxOO7XGAeL7f+yLKZglzGtM9odUVvg/EhO+vQ==}
- engines: {node: '>=10'}
-
- serve-static@2.2.1:
- resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
- engines: {node: '>= 18'}
-
- setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
-
- shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
-
- side-channel-list@1.0.1:
- resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
- engines: {node: '>= 0.4'}
-
- side-channel-map@1.0.1:
- resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
- engines: {node: '>= 0.4'}
-
- side-channel-weakmap@1.0.2:
- resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
- engines: {node: '>= 0.4'}
-
- side-channel@1.1.1:
- resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==}
- engines: {node: '>= 0.4'}
-
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@@ -2209,16 +1655,9 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
- space-separated-tokens@2.0.2:
- resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
-
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- statuses@2.0.2:
- resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
- engines: {node: '>= 0.8'}
-
string-argv@0.3.2:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
engines: {node: '>=0.6.19'}
@@ -2231,9 +1670,6 @@ packages:
resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==}
engines: {node: '>=20'}
- stringify-entities@4.0.4:
- resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
-
strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
@@ -2242,12 +1678,6 @@ packages:
resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
engines: {node: '>=12'}
- style-to-js@1.1.21:
- resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==}
-
- style-to-object@1.0.14:
- resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==}
-
stylelint@17.14.1:
resolution: {integrity: sha512-xVQwyiuxALUBNB2fBe0tmNemg9KqLtdj3T64mioFDar79B2cU8LIyz+3KL6LdiHs9NkeNfwxpKSaIVOY8f112g==}
engines: {node: '>=20.19.0'}
@@ -2316,26 +1746,12 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
- toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
-
- trim-lines@3.0.1:
- resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
-
- trough@2.2.0:
- resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
-
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
- type-is@2.1.0:
- resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
- engines: {node: '>= 18'}
-
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@@ -2348,59 +1764,22 @@ packages:
resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==}
engines: {node: '>=20'}
- unified@11.0.5:
- resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
-
- unist-util-is@6.0.1:
- resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
-
- unist-util-position@5.0.0:
- resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
-
- unist-util-stringify-position@4.0.0:
- resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
-
- unist-util-visit-parents@6.0.2:
- resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==}
-
- unist-util-visit@5.1.0:
- resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
-
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
- unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
-
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
- use-sync-external-store@1.6.0:
- resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
varint@6.0.0:
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
- vary@1.1.2:
- resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
- engines: {node: '>= 0.8'}
-
- vfile-message@4.0.3:
- resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==}
-
- vfile@6.0.3:
- resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
-
vite-plugin-dts@4.5.4:
resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==}
peerDependencies:
@@ -2448,14 +1827,6 @@ packages:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
- which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
-
- wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
-
write-file-atomic@7.0.1:
resolution: {integrity: sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==}
engines: {node: ^20.17.0 || >=22.9.0}
@@ -2465,32 +1836,6 @@ packages:
engines: {node: '>= 14.6'}
hasBin: true
- zod-to-json-schema@3.25.2:
- resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==}
- peerDependencies:
- zod: ^3.25.28 || ^4
-
- zod@4.4.3:
- resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
-
- zustand@4.5.7:
- resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
- engines: {node: '>=12.7.0'}
- peerDependencies:
- '@types/react': '>=16.8'
- immer: '>=9.0.6'
- react: '>=16.8'
- peerDependenciesMeta:
- '@types/react':
- optional: true
- immer:
- optional: true
- react:
- optional: true
-
- zwitch@2.0.4:
- resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
-
snapshots:
'@alloc/quick-lru@5.2.0': {}
@@ -2591,38 +1936,6 @@ snapshots:
dependencies:
postcss-selector-parser: 7.1.4
- '@dendelion/paper-camp@0.13.1(@types/react@18.3.31)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@dendelion/paper-ui': 0.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3)
- '@tanstack/react-router': 1.170.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- commander: 12.1.0
- framer-motion: 12.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- node-pty: 1.1.0
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- react-markdown: 10.1.0(@types/react@18.3.31)(react@18.3.1)
- yaml: 2.9.0
- zod: 4.4.3
- zustand: 4.5.7(@types/react@18.3.31)(react@18.3.1)
- transitivePeerDependencies:
- - '@cfworker/json-schema'
- - '@emotion/is-prop-valid'
- - '@types/react'
- - immer
- - supports-color
-
- '@dendelion/paper-ui@0.12.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- clsx: 2.1.1
- framer-motion: 12.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- roughjs: 4.6.6
- tailwind-merge: 2.6.1
- transitivePeerDependencies:
- - '@emotion/is-prop-valid'
-
'@esbuild/aix-ppc64@0.21.5':
optional: true
@@ -2692,10 +2005,6 @@ snapshots:
'@esbuild/win32-x64@0.21.5':
optional: true
- '@hono/node-server@2.1.0(hono@4.13.0)':
- dependencies:
- hono: 4.13.0
-
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -2753,28 +2062,6 @@ snapshots:
'@microsoft/tsdoc@0.16.0': {}
- '@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)':
- dependencies:
- '@hono/node-server': 2.1.0(hono@4.13.0)
- ajv: 8.20.0
- ajv-formats: 3.0.1(ajv@8.20.0)
- content-type: 1.0.5
- cors: 2.8.6
- cross-spawn: 7.0.6
- eventsource: 3.0.7
- eventsource-parser: 3.1.0
- express: 5.2.1
- express-rate-limit: 8.6.2(express@5.2.1)
- hono: 4.13.0
- jose: 6.2.8
- json-schema-typed: 8.0.2
- pkce-challenge: 5.0.1
- raw-body: 3.0.2
- zod: 4.4.3
- zod-to-json-schema: 3.25.2(zod@4.4.3)
- transitivePeerDependencies:
- - supports-color
-
'@napi-rs/lzma-linux-x64-gnu@1.5.1':
optional: true
@@ -3031,55 +2318,10 @@ snapshots:
dependencies:
'@swc/counter': 0.1.3
- '@tanstack/history@1.162.0': {}
-
- '@tanstack/react-router@1.170.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@tanstack/history': 1.162.0
- '@tanstack/react-store': 0.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@tanstack/router-core': 1.171.15
- isbot: 5.2.1
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
-
- '@tanstack/react-store@0.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@tanstack/store': 0.9.3
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- use-sync-external-store: 1.6.0(react@18.3.1)
-
- '@tanstack/router-core@1.171.15':
- dependencies:
- '@tanstack/history': 1.162.0
- cookie-es: 3.1.1
- seroval: 1.6.2
- seroval-plugins: 1.6.2(seroval@1.6.2)
-
- '@tanstack/store@0.9.3': {}
-
'@types/argparse@1.0.38': {}
- '@types/debug@4.1.13':
- dependencies:
- '@types/ms': 2.1.0
-
- '@types/estree-jsx@1.0.5':
- dependencies:
- '@types/estree': 1.0.9
-
'@types/estree@1.0.9': {}
- '@types/hast@3.0.5':
- dependencies:
- '@types/unist': 3.0.3
-
- '@types/mdast@4.0.4':
- dependencies:
- '@types/unist': 3.0.3
-
- '@types/ms@2.1.0': {}
-
'@types/prop-types@15.7.15': {}
'@types/react-dom@18.3.7(@types/react@18.3.31)':
@@ -3091,12 +2333,6 @@ snapshots:
'@types/prop-types': 15.7.15
csstype: 3.2.3
- '@types/unist@2.0.11': {}
-
- '@types/unist@3.0.3': {}
-
- '@ungap/structured-clone@1.3.3': {}
-
'@vitejs/plugin-react-swc@3.11.0(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.27
@@ -3150,11 +2386,6 @@ snapshots:
'@vue/shared@3.5.40': {}
- accepts@2.0.0:
- dependencies:
- mime-types: 3.0.2
- negotiator: 1.0.0
-
acorn@8.18.0: {}
ajv-draft-04@1.0.0(ajv@8.20.0):
@@ -3215,8 +2446,6 @@ snapshots:
postcss: 8.5.25
postcss-value-parser: 4.2.0
- bail@2.0.2: {}
-
balanced-match@1.0.2: {}
balanced-match@4.0.4: {}
@@ -3225,20 +2454,6 @@ snapshots:
binary-extensions@2.3.0: {}
- body-parser@2.3.0:
- dependencies:
- bytes: 3.1.2
- content-type: 2.0.0
- debug: 4.4.3
- http-errors: 2.0.1
- iconv-lite: 0.7.3
- on-finished: 2.4.1
- qs: 6.15.3
- raw-body: 3.0.2
- type-is: 2.1.0
- transitivePeerDependencies:
- - supports-color
-
brace-expansion@2.1.4:
dependencies:
balanced-match: 1.0.2
@@ -3259,8 +2474,6 @@ snapshots:
node-releases: 2.0.51
update-browserslist-db: 1.2.3(browserslist@4.28.7)
- bytes@3.1.2: {}
-
cacheable@2.5.0:
dependencies:
'@cacheable/memory': 2.2.0
@@ -3269,32 +2482,12 @@ snapshots:
keyv: 5.6.0
qified: 0.10.1
- call-bind-apply-helpers@1.0.2:
- dependencies:
- es-errors: 1.3.0
- function-bind: 1.1.2
-
- call-bound@1.0.4:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- get-intrinsic: 1.3.0
-
callsites@3.1.0: {}
camelcase-css@2.0.1: {}
caniuse-lite@1.0.30001806: {}
- ccount@2.0.1: {}
-
- character-entities-html4@2.1.0: {}
-
- character-entities-legacy@3.0.0: {}
-
- character-entities@2.0.2: {}
-
- character-reference-invalid@2.0.1: {}
-
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -3324,10 +2517,6 @@ snapshots:
colorjs.io@0.5.2: {}
- comma-separated-tokens@2.0.3: {}
-
- commander@12.1.0: {}
-
commander@4.1.1: {}
compare-versions@6.1.1: {}
@@ -3336,23 +2525,6 @@ snapshots:
confbox@0.2.4: {}
- content-disposition@1.1.0: {}
-
- content-type@1.0.5: {}
-
- content-type@2.0.0: {}
-
- cookie-es@3.1.1: {}
-
- cookie-signature@1.2.2: {}
-
- cookie@0.7.2: {}
-
- cors@2.8.6:
- dependencies:
- object-assign: 4.1.1
- vary: 1.1.2
-
cosmiconfig@9.0.2(typescript@5.9.3):
dependencies:
env-paths: 2.2.1
@@ -3362,12 +2534,6 @@ snapshots:
optionalDependencies:
typescript: 5.9.3
- cross-spawn@7.0.6:
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
css-functions-list@3.3.3: {}
css-tree@3.2.1:
@@ -3385,41 +2551,19 @@ snapshots:
dependencies:
ms: 2.1.3
- decode-named-character-reference@1.3.0:
- dependencies:
- character-entities: 2.0.2
-
- depd@2.0.0: {}
-
- dequal@2.0.3: {}
-
detect-libc@2.1.2:
optional: true
- devlop@1.1.0:
- dependencies:
- dequal: 2.0.3
-
didyoumean@1.2.2: {}
diff@8.0.4: {}
dlv@1.1.3: {}
- dunder-proto@1.0.1:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- es-errors: 1.3.0
- gopd: 1.2.0
-
- ee-first@1.1.1: {}
-
electron-to-chromium@1.5.399: {}
emoji-regex@8.0.0: {}
- encodeurl@2.0.0: {}
-
entities@7.0.1: {}
env-paths@2.2.1: {}
@@ -3428,14 +2572,8 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
- es-define-property@1.0.1: {}
-
es-errors@1.3.0: {}
- es-object-atoms@1.1.2:
- dependencies:
- es-errors: 1.3.0
-
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -3464,65 +2602,10 @@ snapshots:
escalade@3.2.0: {}
- escape-html@1.0.3: {}
-
- estree-util-is-identifier-name@3.0.0: {}
-
estree-walker@2.0.2: {}
- etag@1.8.1: {}
-
- eventsource-parser@3.1.0: {}
-
- eventsource@3.0.7:
- dependencies:
- eventsource-parser: 3.1.0
-
- express-rate-limit@8.6.2(express@5.2.1):
- dependencies:
- debug: 4.4.3
- express: 5.2.1
- ip-address: 10.4.0
- transitivePeerDependencies:
- - supports-color
-
- express@5.2.1:
- dependencies:
- accepts: 2.0.0
- body-parser: 2.3.0
- content-disposition: 1.1.0
- content-type: 1.0.5
- cookie: 0.7.2
- cookie-signature: 1.2.2
- debug: 4.4.3
- depd: 2.0.0
- encodeurl: 2.0.0
- escape-html: 1.0.3
- etag: 1.8.1
- finalhandler: 2.1.1
- fresh: 2.0.0
- http-errors: 2.0.1
- merge-descriptors: 2.0.0
- mime-types: 3.0.2
- on-finished: 2.4.1
- once: 1.4.0
- parseurl: 1.3.3
- proxy-addr: 2.0.7
- qs: 6.15.3
- range-parser: 1.3.0
- router: 2.2.0
- send: 1.2.1
- serve-static: 2.2.1
- statuses: 2.0.2
- type-is: 2.1.0
- vary: 1.1.2
- transitivePeerDependencies:
- - supports-color
-
exsolve@1.1.1: {}
- extend@3.0.2: {}
-
fast-deep-equal@3.1.3: {}
fast-glob@3.3.3:
@@ -3553,17 +2636,6 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
- finalhandler@2.1.1:
- dependencies:
- debug: 4.4.3
- encodeurl: 2.0.0
- escape-html: 1.0.3
- on-finished: 2.4.1
- parseurl: 1.3.3
- statuses: 2.0.2
- transitivePeerDependencies:
- - supports-color
-
flat-cache@6.1.23:
dependencies:
cacheable: 2.5.0
@@ -3572,8 +2644,6 @@ snapshots:
flatted@3.4.4: {}
- forwarded@0.2.0: {}
-
fraction.js@5.3.4: {}
framer-motion@12.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
@@ -3585,8 +2655,6 @@ snapshots:
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- fresh@2.0.0: {}
-
fs-extra@11.3.6:
dependencies:
graceful-fs: 4.2.11
@@ -3600,24 +2668,6 @@ snapshots:
get-east-asian-width@1.6.0: {}
- get-intrinsic@1.3.0:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- es-define-property: 1.0.1
- es-errors: 1.3.0
- es-object-atoms: 1.1.2
- function-bind: 1.1.2
- get-proto: 1.0.1
- gopd: 1.2.0
- has-symbols: 1.1.0
- hasown: 2.0.4
- math-intrinsics: 1.1.0
-
- get-proto@1.0.1:
- dependencies:
- dunder-proto: 1.0.1
- es-object-atoms: 1.1.2
-
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -3647,20 +2697,14 @@ snapshots:
globjoin@0.1.4: {}
- gopd@1.2.0: {}
-
graceful-fs@4.2.11: {}
gsap@3.15.0: {}
- hachure-fill@0.5.2: {}
-
has-flag@4.0.0: {}
has-flag@5.0.1: {}
- has-symbols@1.1.0: {}
-
hashery@1.5.1:
dependencies:
hookified: 1.15.1
@@ -3669,54 +2713,14 @@ snapshots:
dependencies:
function-bind: 1.1.2
- hast-util-to-jsx-runtime@2.3.6:
- dependencies:
- '@types/estree': 1.0.9
- '@types/hast': 3.0.5
- '@types/unist': 3.0.3
- comma-separated-tokens: 2.0.3
- devlop: 1.1.0
- estree-util-is-identifier-name: 3.0.0
- hast-util-whitespace: 3.0.0
- mdast-util-mdx-expression: 2.0.1
- mdast-util-mdx-jsx: 3.2.0
- mdast-util-mdxjs-esm: 2.0.1
- property-information: 7.2.0
- space-separated-tokens: 2.0.2
- style-to-js: 1.1.21
- unist-util-position: 5.0.0
- vfile-message: 4.0.3
- transitivePeerDependencies:
- - supports-color
-
- hast-util-whitespace@3.0.0:
- dependencies:
- '@types/hast': 3.0.5
-
he@1.2.0: {}
- hono@4.13.0: {}
-
hookified@1.15.1: {}
hookified@2.2.0: {}
html-tags@5.1.0: {}
- html-url-attributes@3.0.1: {}
-
- http-errors@2.0.1:
- dependencies:
- depd: 2.0.0
- inherits: 2.0.4
- setprototypeof: 1.2.0
- statuses: 2.0.2
- toidentifier: 1.0.1
-
- iconv-lite@0.7.3:
- dependencies:
- safer-buffer: 2.1.2
-
ignore@7.0.6: {}
immutable@5.1.9: {}
@@ -3730,23 +2734,8 @@ snapshots:
import-meta-resolve@4.2.0: {}
- inherits@2.0.4: {}
-
ini@1.3.8: {}
- inline-style-parser@0.2.7: {}
-
- ip-address@10.4.0: {}
-
- ipaddr.js@1.9.1: {}
-
- is-alphabetical@2.0.1: {}
-
- is-alphanumerical@2.0.1:
- dependencies:
- is-alphabetical: 2.0.1
- is-decimal: 2.0.1
-
is-arrayish@0.2.1: {}
is-binary-path@2.1.0:
@@ -3757,8 +2746,6 @@ snapshots:
dependencies:
hasown: 2.0.4
- is-decimal@2.0.1: {}
-
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
@@ -3767,26 +2754,16 @@ snapshots:
dependencies:
is-extglob: 2.1.1
- is-hexadecimal@2.0.1: {}
-
is-number@7.0.0: {}
is-path-inside@4.0.0: {}
- is-plain-obj@4.1.0: {}
-
- is-promise@4.0.0: {}
-
- isbot@5.2.1: {}
-
isexe@2.0.0: {}
jiti@1.21.7: {}
jju@1.4.0: {}
- jose@6.2.8: {}
-
js-tokens@4.0.0: {}
js-yaml@4.3.1:
@@ -3797,8 +2774,6 @@ snapshots:
json-schema-traverse@1.0.0: {}
- json-schema-typed@8.0.2: {}
-
jsonfile@6.2.1:
dependencies:
universalify: 2.0.1
@@ -3825,8 +2800,6 @@ snapshots:
lodash.truncate@4.4.2: {}
- longest-streak@3.1.0: {}
-
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -3835,253 +2808,19 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- math-intrinsics@1.1.0: {}
-
mathml-tag-names@4.0.0: {}
- mdast-util-from-markdown@2.0.3:
- dependencies:
- '@types/mdast': 4.0.4
- '@types/unist': 3.0.3
- decode-named-character-reference: 1.3.0
- devlop: 1.1.0
- mdast-util-to-string: 4.0.0
- micromark: 4.0.2
- micromark-util-decode-numeric-character-reference: 2.0.2
- micromark-util-decode-string: 2.0.1
- micromark-util-normalize-identifier: 2.0.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
- unist-util-stringify-position: 4.0.0
- transitivePeerDependencies:
- - supports-color
-
- mdast-util-mdx-expression@2.0.1:
- dependencies:
- '@types/estree-jsx': 1.0.5
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- devlop: 1.1.0
- mdast-util-from-markdown: 2.0.3
- mdast-util-to-markdown: 2.1.2
- transitivePeerDependencies:
- - supports-color
-
- mdast-util-mdx-jsx@3.2.0:
- dependencies:
- '@types/estree-jsx': 1.0.5
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- '@types/unist': 3.0.3
- ccount: 2.0.1
- devlop: 1.1.0
- mdast-util-from-markdown: 2.0.3
- mdast-util-to-markdown: 2.1.2
- parse-entities: 4.0.2
- stringify-entities: 4.0.4
- unist-util-stringify-position: 4.0.0
- vfile-message: 4.0.3
- transitivePeerDependencies:
- - supports-color
-
- mdast-util-mdxjs-esm@2.0.1:
- dependencies:
- '@types/estree-jsx': 1.0.5
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- devlop: 1.1.0
- mdast-util-from-markdown: 2.0.3
- mdast-util-to-markdown: 2.1.2
- transitivePeerDependencies:
- - supports-color
-
- mdast-util-phrasing@4.1.0:
- dependencies:
- '@types/mdast': 4.0.4
- unist-util-is: 6.0.1
-
- mdast-util-to-hast@13.2.1:
- dependencies:
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- '@ungap/structured-clone': 1.3.3
- devlop: 1.1.0
- micromark-util-sanitize-uri: 2.0.1
- trim-lines: 3.0.1
- unist-util-position: 5.0.0
- unist-util-visit: 5.1.0
- vfile: 6.0.3
-
- mdast-util-to-markdown@2.1.2:
- dependencies:
- '@types/mdast': 4.0.4
- '@types/unist': 3.0.3
- longest-streak: 3.1.0
- mdast-util-phrasing: 4.1.0
- mdast-util-to-string: 4.0.0
- micromark-util-classify-character: 2.0.1
- micromark-util-decode-string: 2.0.1
- unist-util-visit: 5.1.0
- zwitch: 2.0.4
-
- mdast-util-to-string@4.0.0:
- dependencies:
- '@types/mdast': 4.0.4
-
mdn-data@2.27.1: {}
- media-typer@1.1.1: {}
-
meow@14.1.0: {}
- merge-descriptors@2.0.0: {}
-
merge2@1.4.1: {}
- micromark-core-commonmark@2.0.3:
- dependencies:
- decode-named-character-reference: 1.3.0
- devlop: 1.1.0
- micromark-factory-destination: 2.0.1
- micromark-factory-label: 2.0.1
- micromark-factory-space: 2.0.1
- micromark-factory-title: 2.0.1
- micromark-factory-whitespace: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-chunked: 2.0.1
- micromark-util-classify-character: 2.0.1
- micromark-util-html-tag-name: 2.0.1
- micromark-util-normalize-identifier: 2.0.1
- micromark-util-resolve-all: 2.0.1
- micromark-util-subtokenize: 2.1.0
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-factory-destination@2.0.1:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-factory-label@2.0.1:
- dependencies:
- devlop: 1.1.0
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-factory-space@2.0.1:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-types: 2.0.2
-
- micromark-factory-title@2.0.1:
- dependencies:
- micromark-factory-space: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-factory-whitespace@2.0.1:
- dependencies:
- micromark-factory-space: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-util-character@2.1.1:
- dependencies:
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-util-chunked@2.0.1:
- dependencies:
- micromark-util-symbol: 2.0.1
-
- micromark-util-classify-character@2.0.1:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-util-combine-extensions@2.0.1:
- dependencies:
- micromark-util-chunked: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-util-decode-numeric-character-reference@2.0.2:
- dependencies:
- micromark-util-symbol: 2.0.1
-
- micromark-util-decode-string@2.0.1:
- dependencies:
- decode-named-character-reference: 1.3.0
- micromark-util-character: 2.1.1
- micromark-util-decode-numeric-character-reference: 2.0.2
- micromark-util-symbol: 2.0.1
-
- micromark-util-encode@2.0.1: {}
-
- micromark-util-html-tag-name@2.0.1: {}
-
- micromark-util-normalize-identifier@2.0.1:
- dependencies:
- micromark-util-symbol: 2.0.1
-
- micromark-util-resolve-all@2.0.1:
- dependencies:
- micromark-util-types: 2.0.2
-
- micromark-util-sanitize-uri@2.0.1:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-encode: 2.0.1
- micromark-util-symbol: 2.0.1
-
- micromark-util-subtokenize@2.1.0:
- dependencies:
- devlop: 1.1.0
- micromark-util-chunked: 2.0.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
- micromark-util-symbol@2.0.1: {}
-
- micromark-util-types@2.0.2: {}
-
- micromark@4.0.2:
- dependencies:
- '@types/debug': 4.1.13
- debug: 4.4.3
- decode-named-character-reference: 1.3.0
- devlop: 1.1.0
- micromark-core-commonmark: 2.0.3
- micromark-factory-space: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-chunked: 2.0.1
- micromark-util-combine-extensions: 2.0.1
- micromark-util-decode-numeric-character-reference: 2.0.2
- micromark-util-encode: 2.0.1
- micromark-util-normalize-identifier: 2.0.1
- micromark-util-resolve-all: 2.0.1
- micromark-util-sanitize-uri: 2.0.1
- micromark-util-subtokenize: 2.1.0
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
- transitivePeerDependencies:
- - supports-color
-
micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.2
- mime-db@1.54.0: {}
-
- mime-types@3.0.2:
- dependencies:
- mime-db: 1.54.0
-
minimatch@10.2.3:
dependencies:
brace-expansion: 5.0.9
@@ -4117,13 +2856,8 @@ snapshots:
nanoid@3.3.17: {}
- negotiator@1.0.0: {}
-
- node-addon-api@7.1.1: {}
-
- node-pty@1.1.0:
- dependencies:
- node-addon-api: 7.1.1
+ node-addon-api@7.1.1:
+ optional: true
node-releases@2.0.51: {}
@@ -4133,32 +2867,12 @@ snapshots:
object-hash@3.0.0: {}
- object-inspect@1.13.4: {}
-
- on-finished@2.4.1:
- dependencies:
- ee-first: 1.1.1
-
- once@1.4.0:
- dependencies:
- wrappy: 1.0.2
-
package-manager-detector@1.8.0: {}
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
- parse-entities@4.0.2:
- dependencies:
- '@types/unist': 2.0.11
- character-entities-legacy: 3.0.0
- character-reference-invalid: 2.0.1
- decode-named-character-reference: 1.3.0
- is-alphanumerical: 2.0.1
- is-decimal: 2.0.1
- is-hexadecimal: 2.0.1
-
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.29.7
@@ -4166,18 +2880,10 @@ snapshots:
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
- parseurl@1.3.3: {}
-
path-browserify@1.0.1: {}
- path-data-parser@0.1.0: {}
-
- path-key@3.1.1: {}
-
path-parse@1.0.7: {}
- path-to-regexp@8.4.2: {}
-
pathe@2.0.3: {}
picocolors@1.1.1: {}
@@ -4190,8 +2896,6 @@ snapshots:
pirates@4.0.7: {}
- pkce-challenge@5.0.1: {}
-
pkg-types@1.3.1:
dependencies:
confbox: 0.1.8
@@ -4204,13 +2908,6 @@ snapshots:
exsolve: 1.1.1
pathe: 2.0.3
- points-on-curve@0.2.0: {}
-
- points-on-path@0.2.1:
- dependencies:
- path-data-parser: 0.1.0
- points-on-curve: 0.2.0
-
postcss-import@15.1.0(postcss@8.5.25):
dependencies:
postcss: 8.5.25
@@ -4262,13 +2959,6 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- property-information@7.2.0: {}
-
- proxy-addr@2.0.7:
- dependencies:
- forwarded: 0.2.0
- ipaddr.js: 1.9.1
-
publint@0.3.22:
dependencies:
'@publint/pack': 0.1.6
@@ -4280,48 +2970,16 @@ snapshots:
dependencies:
hookified: 2.2.0
- qs@6.15.3:
- dependencies:
- es-define-property: 1.0.1
- side-channel: 1.1.1
-
quansync@0.2.11: {}
queue-microtask@1.2.3: {}
- range-parser@1.3.0: {}
-
- raw-body@3.0.2:
- dependencies:
- bytes: 3.1.2
- http-errors: 2.0.1
- iconv-lite: 0.7.3
- unpipe: 1.0.0
-
react-dom@18.3.1(react@18.3.1):
dependencies:
loose-envify: 1.4.0
react: 18.3.1
scheduler: 0.23.2
- react-markdown@10.1.0(@types/react@18.3.31)(react@18.3.1):
- dependencies:
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- '@types/react': 18.3.31
- devlop: 1.1.0
- hast-util-to-jsx-runtime: 2.3.6
- html-url-attributes: 3.0.1
- mdast-util-to-hast: 13.2.1
- react: 18.3.1
- remark-parse: 11.0.0
- remark-rehype: 11.1.2
- unified: 11.0.5
- unist-util-visit: 5.1.0
- vfile: 6.0.3
- transitivePeerDependencies:
- - supports-color
-
react@18.3.1:
dependencies:
loose-envify: 1.4.0
@@ -4337,23 +2995,6 @@ snapshots:
readdirp@5.0.0:
optional: true
- remark-parse@11.0.0:
- dependencies:
- '@types/mdast': 4.0.4
- mdast-util-from-markdown: 2.0.3
- micromark-util-types: 2.0.2
- unified: 11.0.5
- transitivePeerDependencies:
- - supports-color
-
- remark-rehype@11.1.2:
- dependencies:
- '@types/hast': 3.0.5
- '@types/mdast': 4.0.4
- mdast-util-to-hast: 13.2.1
- unified: 11.0.5
- vfile: 6.0.3
-
require-from-string@2.0.2: {}
resolve-from@4.0.0: {}
@@ -4399,23 +3040,6 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.62.4
fsevents: 2.3.3
- roughjs@4.6.6:
- dependencies:
- hachure-fill: 0.5.2
- path-data-parser: 0.1.0
- points-on-curve: 0.2.0
- points-on-path: 0.2.1
-
- router@2.2.0:
- dependencies:
- debug: 4.4.3
- depd: 2.0.0
- is-promise: 4.0.0
- parseurl: 1.3.3
- path-to-regexp: 8.4.2
- transitivePeerDependencies:
- - supports-color
-
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -4428,8 +3052,6 @@ snapshots:
dependencies:
mri: 1.2.0
- safer-buffer@2.1.2: {}
-
sass-embedded-all-unknown@1.100.0:
dependencies:
sass: 1.100.0
@@ -4532,73 +3154,6 @@ snapshots:
semver@7.7.4: {}
- send@1.2.1:
- dependencies:
- debug: 4.4.3
- encodeurl: 2.0.0
- escape-html: 1.0.3
- etag: 1.8.1
- fresh: 2.0.0
- http-errors: 2.0.1
- mime-types: 3.0.2
- ms: 2.1.3
- on-finished: 2.4.1
- range-parser: 1.3.0
- statuses: 2.0.2
- transitivePeerDependencies:
- - supports-color
-
- seroval-plugins@1.6.2(seroval@1.6.2):
- dependencies:
- seroval: 1.6.2
-
- seroval@1.6.2: {}
-
- serve-static@2.2.1:
- dependencies:
- encodeurl: 2.0.0
- escape-html: 1.0.3
- parseurl: 1.3.3
- send: 1.2.1
- transitivePeerDependencies:
- - supports-color
-
- setprototypeof@1.2.0: {}
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- side-channel-list@1.0.1:
- dependencies:
- es-errors: 1.3.0
- object-inspect: 1.13.4
-
- side-channel-map@1.0.1:
- dependencies:
- call-bound: 1.0.4
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- object-inspect: 1.13.4
-
- side-channel-weakmap@1.0.2:
- dependencies:
- call-bound: 1.0.4
- es-errors: 1.3.0
- get-intrinsic: 1.3.0
- object-inspect: 1.13.4
- side-channel-map: 1.0.1
-
- side-channel@1.1.1:
- dependencies:
- es-errors: 1.3.0
- object-inspect: 1.13.4
- side-channel-list: 1.0.1
- side-channel-map: 1.0.1
- side-channel-weakmap: 1.0.2
-
signal-exit@4.1.0: {}
slash@5.1.0: {}
@@ -4613,12 +3168,8 @@ snapshots:
source-map@0.6.1: {}
- space-separated-tokens@2.0.2: {}
-
sprintf-js@1.0.3: {}
- statuses@2.0.2: {}
-
string-argv@0.3.2: {}
string-width@4.2.3:
@@ -4632,11 +3183,6 @@ snapshots:
get-east-asian-width: 1.6.0
strip-ansi: 7.2.0
- stringify-entities@4.0.4:
- dependencies:
- character-entities-html4: 2.1.0
- character-entities-legacy: 3.0.0
-
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
@@ -4645,14 +3191,6 @@ snapshots:
dependencies:
ansi-regex: 6.2.2
- style-to-js@1.1.21:
- dependencies:
- style-to-object: 1.0.14
-
- style-to-object@1.0.14:
- dependencies:
- inline-style-parser: 0.2.7
-
stylelint@17.14.1(typescript@5.9.3):
dependencies:
'@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
@@ -4782,91 +3320,28 @@ snapshots:
dependencies:
is-number: 7.0.0
- toidentifier@1.0.1: {}
-
- trim-lines@3.0.1: {}
-
- trough@2.2.0: {}
-
ts-interface-checker@0.1.13: {}
tslib@2.8.1: {}
- type-is@2.1.0:
- dependencies:
- content-type: 2.0.0
- media-typer: 1.1.1
- mime-types: 3.0.2
-
typescript@5.9.3: {}
ufo@1.6.4: {}
unicorn-magic@0.4.0: {}
- unified@11.0.5:
- dependencies:
- '@types/unist': 3.0.3
- bail: 2.0.2
- devlop: 1.1.0
- extend: 3.0.2
- is-plain-obj: 4.1.0
- trough: 2.2.0
- vfile: 6.0.3
-
- unist-util-is@6.0.1:
- dependencies:
- '@types/unist': 3.0.3
-
- unist-util-position@5.0.0:
- dependencies:
- '@types/unist': 3.0.3
-
- unist-util-stringify-position@4.0.0:
- dependencies:
- '@types/unist': 3.0.3
-
- unist-util-visit-parents@6.0.2:
- dependencies:
- '@types/unist': 3.0.3
- unist-util-is: 6.0.1
-
- unist-util-visit@5.1.0:
- dependencies:
- '@types/unist': 3.0.3
- unist-util-is: 6.0.1
- unist-util-visit-parents: 6.0.2
-
universalify@2.0.1: {}
- unpipe@1.0.0: {}
-
update-browserslist-db@1.2.3(browserslist@4.28.7):
dependencies:
browserslist: 4.28.7
escalade: 3.2.0
picocolors: 1.1.1
- use-sync-external-store@1.6.0(react@18.3.1):
- dependencies:
- react: 18.3.1
-
util-deprecate@1.0.2: {}
varint@6.0.0: {}
- vary@1.1.2: {}
-
- vfile-message@4.0.3:
- dependencies:
- '@types/unist': 3.0.3
- unist-util-stringify-position: 4.0.0
-
- vfile@6.0.3:
- dependencies:
- '@types/unist': 3.0.3
- vfile-message: 4.0.3
-
vite-plugin-dts@4.5.4(rollup@4.62.4)(typescript@5.9.3)(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0)):
dependencies:
'@microsoft/api-extractor': 7.58.12
@@ -4902,29 +3377,9 @@ snapshots:
dependencies:
isexe: 2.0.0
- which@2.0.2:
- dependencies:
- isexe: 2.0.0
-
- wrappy@1.0.2: {}
-
write-file-atomic@7.0.1:
dependencies:
signal-exit: 4.1.0
- yaml@2.9.0: {}
-
- zod-to-json-schema@3.25.2(zod@4.4.3):
- dependencies:
- zod: 4.4.3
-
- zod@4.4.3: {}
-
- zustand@4.5.7(@types/react@18.3.31)(react@18.3.1):
- dependencies:
- use-sync-external-store: 1.6.0(react@18.3.1)
- optionalDependencies:
- '@types/react': 18.3.31
- react: 18.3.1
-
- zwitch@2.0.4: {}
+ yaml@2.9.0:
+ optional: true
diff --git a/src/components/glass/glass.tsx b/src/components/glass/glass.tsx
index df0d542..f2fe476 100644
--- a/src/components/glass/glass.tsx
+++ b/src/components/glass/glass.tsx
@@ -21,10 +21,11 @@ export const Glass = forwardRef(function Glass(
) {
// blur={0} must remove the filter, not apply blur(0px) — a zero-radius
// backdrop-filter still forces the browser to isolate and re-composite a
- // render surface on every backdrop change.
+ // render surface on every backdrop change. The frost lives on the ::before
+ // layer, so both knobs travel as custom properties.
const vars: CSSProperties | undefined =
blur === 0
- ? { backdropFilter: 'none', WebkitBackdropFilter: 'none' }
+ ? ({ '--fui-glass-backdrop': 'none' } as CSSProperties)
: blur != null
? ({ '--fui-glass-blur': `${blur}px` } as CSSProperties)
: undefined;
diff --git a/src/components/select/select.module.scss b/src/components/select/select.module.scss
index 9fe1d9d..3ab7539 100644
--- a/src/components/select/select.module.scss
+++ b/src/components/select/select.module.scss
@@ -102,7 +102,9 @@
box-shadow:
inset 0 0 0 2px var(--fui-shadow-color),
$glass-shadow;
- backdrop-filter: blur(12px);
+ // Frost only when standing on the raw page background — inside a Glass
+ // surface --fui-nested-backdrop resolves to `none`.
+ backdrop-filter: var(--fui-nested-backdrop, blur(12px));
}
.option {
diff --git a/src/showcase.tsx b/src/showcase.tsx
index 9e8fb1f..ee2dac2 100644
--- a/src/showcase.tsx
+++ b/src/showcase.tsx
@@ -20,7 +20,7 @@ const sections = ['welcome', 'components', 'tokens', 'docs'] as const;
// Long enough that one copy always exceeds the panel width; rendered twice
// for the seamless -50% marquee loop.
-const marqueeText = 'frosted · noisy · cosy · funky · '.repeat(3);
+const marqueeText = 'funky · noisy · cosy · '.repeat(3);
// Titles and title-refrains only — song titles aren't copyrightable,
// full lyric verses are.
@@ -294,7 +294,7 @@ function Showcase() {
func ui
- Frosted.
+ Funky.
Noisy.
diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss
index 798282c..b772d63 100644
--- a/src/styles/_mixins.scss
+++ b/src/styles/_mixins.scss
@@ -9,17 +9,33 @@
// ─── Frosted glass ─────────────────────────────────────────────
// The core "glossy transparent" surface: translucent fill behind a
// heavy backdrop blur. Blur radius is var-backed so consumers can tune it.
+//
+// The frost lives on a ::before layer, NOT on the host: when the host is an
+// ancestor of a scrolling element, inner scrolls invalidate the filter's
+// render surface and Chromium transiently drops the blur (visible flicker,
+// reproduced on macOS). As a sibling layer behind the content, the frost is
+// untouched by scrolling. The host gets z-index: 0 so the -1 pseudo stays
+// inside it without creating a backdrop root (isolation would break sampling).
@mixin glass($blur: $blur-glass) {
- background-color: var(--fui-surface);
- backdrop-filter: blur(var(--fui-glass-blur, #{$blur}));
- -webkit-backdrop-filter: blur(var(--fui-glass-blur, #{$blur}));
+ position: relative;
+ z-index: 0;
box-shadow: $glass-shadow;
- // Follow the body's theme fade instead of snapping on toggle.
- transition: background-color 0.3s ease;
// Descendants standing on this surface are already frosted — components
// that read this var (Card, secondary Button) drop their own backdrop
// blur, which would otherwise re-sample the panel on every scroll tick.
--fui-nested-backdrop: none;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+ background-color: var(--fui-surface);
+ backdrop-filter: var(--fui-glass-backdrop, blur(var(--fui-glass-blur, #{$blur})));
+ -webkit-backdrop-filter: var(--fui-glass-backdrop, blur(var(--fui-glass-blur, #{$blur})));
+ // Follow the body's theme fade instead of snapping on toggle.
+ transition: background-color 0.3s ease;
+ }
}
// ─── Reduced motion ────────────────────────────────────────────
diff --git a/vite.config.ts b/vite.config.ts
index 3fb5444..bf8012f 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,4 +1,5 @@
import { resolve } from 'node:path';
+import { paperCamp } from '@dendelion/paper-camp/vite';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
@@ -13,6 +14,7 @@ export default defineConfig(({ command }) => {
if (command === 'serve') {
return {
...baseConfig,
+ plugins: [...baseConfig.plugins, paperCamp()],
server: {
host: '0.0.0.0',
port: 3040,
From 1ab527e9a5e14e9b3bb7d87896c6a67eb89b2533 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:17:56 +0000
Subject: [PATCH 03/16] feat(release): EmptyState (loading / empty / error,
centered per UX_PRINCIPLES layout-stability rules)
Refs: IDEA-3
---
package.json | 11 +----
papercamp/ideas/IDEA-3.md | 2 +-
.../empty-state/empty-state.module.scss | 48 +++++++++++++++++++
src/components/empty-state/empty-state.tsx | 47 ++++++++++++++++++
src/components/empty-state/index.ts | 2 +
src/index.ts | 3 ++
6 files changed, 103 insertions(+), 10 deletions(-)
create mode 100644 src/components/empty-state/empty-state.module.scss
create mode 100644 src/components/empty-state/empty-state.tsx
create mode 100644 src/components/empty-state/index.ts
diff --git a/package.json b/package.json
index 0b339be..7ba3d96 100644
--- a/package.json
+++ b/package.json
@@ -3,10 +3,7 @@
"version": "0.1.1",
"description": "Glossy, noisy, cosy React component library — frosted glass, film grain, and lava glow",
"type": "module",
- "sideEffects": [
- "**/*.css",
- "**/*.scss"
- ],
+ "sideEffects": ["**/*.css", "**/*.scss"],
"packageManager": "pnpm@10.12.1",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
@@ -96,10 +93,6 @@
"vite-plugin-dts": "^4.5.4"
},
"pnpm": {
- "onlyBuiltDependencies": [
- "@biomejs/biome",
- "@swc/core",
- "esbuild"
- ]
+ "onlyBuiltDependencies": ["@biomejs/biome", "@swc/core", "esbuild"]
}
}
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 5863922..1d1e16f 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -17,7 +17,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
### Phases
- [x] LinkButton (inherit/accent color, sizes — fixes the "fixed amber style" complaint)
-- [ ] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
+- [x] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
- [ ] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
- [ ] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
- [ ] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
diff --git a/src/components/empty-state/empty-state.module.scss b/src/components/empty-state/empty-state.module.scss
new file mode 100644
index 0000000..b4bcc70
--- /dev/null
+++ b/src/components/empty-state/empty-state.module.scss
@@ -0,0 +1,48 @@
+@use '../../styles/tokens' as *;
+
+.emptyState {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: $space-3;
+ min-height: 12rem;
+ padding: $space-6;
+ text-align: center;
+ font-family: $font-family-sans;
+ color: var(--fui-text);
+}
+
+.visual {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: color-mix(in srgb, var(--fui-text) 55%, transparent);
+}
+
+.title {
+ margin: 0;
+ font-size: $font-size-lg;
+ font-weight: 600;
+ line-height: 1.3;
+}
+
+.description {
+ margin: 0;
+ max-width: 40ch;
+ font-size: $font-size-sm;
+ line-height: 1.5;
+ color: color-mix(in srgb, var(--fui-text) 65%, transparent);
+}
+
+.action {
+ margin-top: $space-2;
+}
+
+.loading .visual {
+ color: var(--fui-accent);
+}
+
+.error .visual {
+ color: var(--fui-status-error-text);
+}
diff --git a/src/components/empty-state/empty-state.tsx b/src/components/empty-state/empty-state.tsx
new file mode 100644
index 0000000..5fba3f8
--- /dev/null
+++ b/src/components/empty-state/empty-state.tsx
@@ -0,0 +1,47 @@
+import type { HTMLAttributes, ReactNode } from 'react';
+import { cn } from '../../utils/style-helpers';
+import { Spinner } from '../spinner';
+import styles from './empty-state.module.scss';
+
+export type EmptyStateStatus = 'loading' | 'empty' | 'error';
+
+export interface EmptyStateProps extends Omit, 'title'> {
+ status?: EmptyStateStatus;
+ icon?: ReactNode;
+ title?: ReactNode;
+ description?: ReactNode;
+ action?: ReactNode;
+}
+
+const roles: Record['role']> = {
+ loading: 'status',
+ empty: 'status',
+ error: 'alert',
+};
+
+export function EmptyState({
+ status = 'empty',
+ icon,
+ title,
+ description,
+ action,
+ className,
+ children,
+ ...props
+}: EmptyStateProps) {
+ const visual = icon ?? (status === 'loading' ? : null);
+ return (
+
+ {visual &&
{visual}
}
+ {title &&
{title}
}
+ {description &&
{description}
}
+ {children}
+ {action &&
{action}
}
+
+ );
+}
diff --git a/src/components/empty-state/index.ts b/src/components/empty-state/index.ts
new file mode 100644
index 0000000..8ddb0ff
--- /dev/null
+++ b/src/components/empty-state/index.ts
@@ -0,0 +1,2 @@
+export { EmptyState } from './empty-state';
+export type { EmptyStateProps, EmptyStateStatus } from './empty-state';
diff --git a/src/index.ts b/src/index.ts
index 62c40fa..519d45b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -75,4 +75,7 @@ export type { ProgressProps } from './components/progress';
export { Skeleton } from './components/skeleton';
export type { SkeletonProps } from './components/skeleton';
+export { EmptyState } from './components/empty-state';
+export type { EmptyStateProps, EmptyStateStatus } from './components/empty-state';
+
export { cn } from './utils/style-helpers';
From ca7035f990af5e0046824e973f8d4fb6862876e3 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:21:52 +0000
Subject: [PATCH 04/16] feat(release): StatusDot + Chip (toggle/filter,
aria-pressed) + SegmentedControl
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 2 +-
src/components/chip/chip.module.scss | 58 +++++++++++++++
src/components/chip/chip.tsx | 36 ++++++++++
src/components/chip/index.ts | 2 +
src/components/segmented-control/index.ts | 2 +
.../segmented-control.module.scss | 71 +++++++++++++++++++
.../segmented-control/segmented-control.tsx | 52 ++++++++++++++
src/components/status-dot/index.ts | 2 +
.../status-dot/status-dot.module.scss | 58 +++++++++++++++
src/components/status-dot/status-dot.tsx | 37 ++++++++++
src/index.ts | 12 ++++
11 files changed, 331 insertions(+), 1 deletion(-)
create mode 100644 src/components/chip/chip.module.scss
create mode 100644 src/components/chip/chip.tsx
create mode 100644 src/components/chip/index.ts
create mode 100644 src/components/segmented-control/index.ts
create mode 100644 src/components/segmented-control/segmented-control.module.scss
create mode 100644 src/components/segmented-control/segmented-control.tsx
create mode 100644 src/components/status-dot/index.ts
create mode 100644 src/components/status-dot/status-dot.module.scss
create mode 100644 src/components/status-dot/status-dot.tsx
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 1d1e16f..cb75e3f 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -18,7 +18,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
### Phases
- [x] LinkButton (inherit/accent color, sizes — fixes the "fixed amber style" complaint)
- [x] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
-- [ ] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
+- [x] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
- [ ] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
- [ ] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
- [ ] CopyButton + Breadcrumb + Menu + FileButton
diff --git a/src/components/chip/chip.module.scss b/src/components/chip/chip.module.scss
new file mode 100644
index 0000000..6b6dd21
--- /dev/null
+++ b/src/components/chip/chip.module.scss
@@ -0,0 +1,58 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.375rem;
+ border: none;
+ background-color: transparent;
+ color: var(--fui-text);
+ font-family: $font-family-mono;
+ font-weight: 700;
+ text-transform: lowercase;
+ letter-spacing: 0.02em;
+ line-height: 1.4;
+ white-space: nowrap;
+ cursor: pointer;
+ box-shadow: inset 0 0 0 2px var(--fui-shadow-color);
+ transition:
+ box-shadow 120ms ease,
+ background-color 200ms ease,
+ color 200ms ease,
+ filter 200ms ease;
+
+ &:hover:not(:disabled) {
+ filter: brightness(1.05);
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+.selected {
+ background-color: var(--fui-accent);
+ color: #000;
+ box-shadow: inset 0 0 0 2px var(--fui-accent);
+}
+
+.sm {
+ padding: 0.125rem 0.5rem;
+ font-size: 0.6875rem;
+}
+
+.md {
+ padding: 0.25rem 0.625rem;
+ font-size: 0.75rem;
+}
+
+.icon {
+ display: inline-flex;
+ align-items: center;
+}
diff --git a/src/components/chip/chip.tsx b/src/components/chip/chip.tsx
new file mode 100644
index 0000000..b16c469
--- /dev/null
+++ b/src/components/chip/chip.tsx
@@ -0,0 +1,36 @@
+import { type ButtonHTMLAttributes, type ReactNode, forwardRef } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './chip.module.scss';
+
+export interface ChipProps extends ButtonHTMLAttributes {
+ selected?: boolean;
+ size?: 'sm' | 'md';
+ icon?: ReactNode;
+ onToggle?: (selected: boolean) => void;
+}
+
+export const Chip = forwardRef(function Chip(
+ { selected = false, size = 'md', icon, onToggle, onClick, className, children, ...props },
+ ref,
+) {
+ return (
+
+ );
+});
diff --git a/src/components/chip/index.ts b/src/components/chip/index.ts
new file mode 100644
index 0000000..b94adef
--- /dev/null
+++ b/src/components/chip/index.ts
@@ -0,0 +1,2 @@
+export { Chip } from './chip';
+export type { ChipProps } from './chip';
diff --git a/src/components/segmented-control/index.ts b/src/components/segmented-control/index.ts
new file mode 100644
index 0000000..96b98a9
--- /dev/null
+++ b/src/components/segmented-control/index.ts
@@ -0,0 +1,2 @@
+export { SegmentedControl } from './segmented-control';
+export type { SegmentedControlOption, SegmentedControlProps } from './segmented-control';
diff --git a/src/components/segmented-control/segmented-control.module.scss b/src/components/segmented-control/segmented-control.module.scss
new file mode 100644
index 0000000..0a2896a
--- /dev/null
+++ b/src/components/segmented-control/segmented-control.module.scss
@@ -0,0 +1,71 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.group {
+ display: inline-flex;
+ min-width: 0;
+ margin: 0;
+ padding: 0;
+ border: none;
+ background-color: var(--fui-surface);
+ box-shadow: inset 0 0 0 2px var(--fui-shadow-color);
+ backdrop-filter: var(--fui-nested-backdrop, blur(12px));
+}
+
+.segment {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.375rem;
+ border: none;
+ background-color: transparent;
+ color: var(--fui-text);
+ font-family: $font-family-mono;
+ font-weight: 700;
+ text-transform: lowercase;
+ letter-spacing: 0.02em;
+ line-height: 1.2;
+ white-space: nowrap;
+ cursor: pointer;
+ transition:
+ background-color 200ms ease,
+ color 200ms ease;
+
+ & + & {
+ box-shadow: inset 2px 0 0 0 var(--fui-shadow-color);
+ }
+
+ &:hover:not(:disabled):not(.active) {
+ background-color: color-mix(in srgb, var(--fui-text) 8%, transparent);
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ outline-offset: -2px;
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+.active {
+ background-color: var(--fui-accent);
+ color: #000;
+}
+
+.sm .segment {
+ padding: 0.125rem 0.625rem;
+ font-size: 0.6875rem;
+}
+
+.md .segment {
+ padding: 0.25rem 0.875rem;
+ font-size: 0.8125rem;
+}
+
+.icon {
+ display: inline-flex;
+ align-items: center;
+}
diff --git a/src/components/segmented-control/segmented-control.tsx b/src/components/segmented-control/segmented-control.tsx
new file mode 100644
index 0000000..2c63cf7
--- /dev/null
+++ b/src/components/segmented-control/segmented-control.tsx
@@ -0,0 +1,52 @@
+import type { HTMLAttributes, ReactNode } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './segmented-control.module.scss';
+
+export interface SegmentedControlOption {
+ value: string;
+ label: ReactNode;
+ icon?: ReactNode;
+ disabled?: boolean;
+}
+
+export interface SegmentedControlProps
+ extends Omit, 'onChange'> {
+ options: SegmentedControlOption[];
+ value: string;
+ onChange: (value: string) => void;
+ size?: 'sm' | 'md';
+}
+
+export function SegmentedControl({
+ options,
+ value,
+ onChange,
+ size = 'md',
+ className,
+ ...props
+}: SegmentedControlProps) {
+ return (
+
+ );
+}
diff --git a/src/components/status-dot/index.ts b/src/components/status-dot/index.ts
new file mode 100644
index 0000000..99cc9e3
--- /dev/null
+++ b/src/components/status-dot/index.ts
@@ -0,0 +1,2 @@
+export { StatusDot } from './status-dot';
+export type { StatusDotProps, StatusDotVariant } from './status-dot';
diff --git a/src/components/status-dot/status-dot.module.scss b/src/components/status-dot/status-dot.module.scss
new file mode 100644
index 0000000..31ad49f
--- /dev/null
+++ b/src/components/status-dot/status-dot.module.scss
@@ -0,0 +1,58 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.statusDot {
+ display: inline-block;
+ flex: none;
+ background-color: currentColor;
+ vertical-align: middle;
+}
+
+.sm {
+ width: 6px;
+ height: 6px;
+}
+
+.md {
+ width: 9px;
+ height: 9px;
+}
+
+.pulse {
+ animation: fui-status-pulse 1.6s ease-in-out infinite;
+
+ @include reduced-motion {
+ animation: none;
+ }
+}
+
+.neutral {
+ color: var(--fui-status-neutral-text);
+}
+
+.info {
+ color: var(--fui-status-info-text);
+}
+
+.success {
+ color: var(--fui-status-success-text);
+}
+
+.warning {
+ color: var(--fui-status-warning-text);
+}
+
+.error {
+ color: var(--fui-status-error-text);
+}
+
+@keyframes fui-status-pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0.35;
+ }
+}
diff --git a/src/components/status-dot/status-dot.tsx b/src/components/status-dot/status-dot.tsx
new file mode 100644
index 0000000..bac5b46
--- /dev/null
+++ b/src/components/status-dot/status-dot.tsx
@@ -0,0 +1,37 @@
+import type { HTMLAttributes } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './status-dot.module.scss';
+
+export type StatusDotVariant = 'neutral' | 'info' | 'success' | 'warning' | 'error';
+
+export interface StatusDotProps extends HTMLAttributes {
+ variant?: StatusDotVariant;
+ size?: 'sm' | 'md';
+ pulse?: boolean;
+ label?: string;
+}
+
+export function StatusDot({
+ variant = 'neutral',
+ size = 'sm',
+ pulse = false,
+ label,
+ className,
+ ...props
+}: StatusDotProps) {
+ return (
+
+ );
+}
diff --git a/src/index.ts b/src/index.ts
index 519d45b..c6557b8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -78,4 +78,16 @@ export type { SkeletonProps } from './components/skeleton';
export { EmptyState } from './components/empty-state';
export type { EmptyStateProps, EmptyStateStatus } from './components/empty-state';
+export { StatusDot } from './components/status-dot';
+export type { StatusDotProps, StatusDotVariant } from './components/status-dot';
+
+export { Chip } from './components/chip';
+export type { ChipProps } from './components/chip';
+
+export { SegmentedControl } from './components/segmented-control';
+export type {
+ SegmentedControlOption,
+ SegmentedControlProps,
+} from './components/segmented-control';
+
export { cn } from './utils/style-helpers';
From f4b4f8c6bdee3aa4f6dc16532724336d71359b72 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:24:31 +0000
Subject: [PATCH 05/16] =?UTF-8?q?feat(release):=20Drawer=20(backdrop,=20fo?=
=?UTF-8?q?cus=20trap,=20Escape,=20slide)=20=E2=80=94=20replaces=20two=20i?=
=?UTF-8?q?nconsistent=20hand-rolls?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Refs: IDEA-3
---
biome.json | 6 +-
papercamp/ideas/IDEA-3.md | 2 +-
src/components/drawer/drawer.module.scss | 218 +++++++++++++++++++++++
src/components/drawer/drawer.tsx | 133 ++++++++++++++
src/components/drawer/index.ts | 2 +
src/index.ts | 3 +
6 files changed, 362 insertions(+), 2 deletions(-)
create mode 100644 src/components/drawer/drawer.module.scss
create mode 100644 src/components/drawer/drawer.tsx
create mode 100644 src/components/drawer/index.ts
diff --git a/biome.json b/biome.json
index 4f723fc..8f2029d 100644
--- a/biome.json
+++ b/biome.json
@@ -43,7 +43,11 @@
},
"overrides": [
{
- "include": ["src/components/select/**", "src/components/modal/**"],
+ "include": [
+ "src/components/select/**",
+ "src/components/modal/**",
+ "src/components/drawer/**"
+ ],
"linter": {
"rules": {
"a11y": {
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index cb75e3f..000419a 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -19,7 +19,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] LinkButton (inherit/accent color, sizes — fixes the "fixed amber style" complaint)
- [x] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
- [x] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
-- [ ] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
+- [x] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
- [ ] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
- [ ] CopyButton + Breadcrumb + Menu + FileButton
- [ ] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
diff --git a/src/components/drawer/drawer.module.scss b/src/components/drawer/drawer.module.scss
new file mode 100644
index 0000000..9af2a07
--- /dev/null
+++ b/src/components/drawer/drawer.module.scss
@@ -0,0 +1,218 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 50;
+ display: flex;
+}
+
+.overlay.left {
+ justify-content: flex-start;
+}
+
+.overlay.right {
+ justify-content: flex-end;
+}
+
+.overlay.top {
+ align-items: flex-start;
+}
+
+.overlay.bottom {
+ align-items: flex-end;
+}
+
+.backdrop {
+ position: absolute;
+ inset: 0;
+ border: none;
+ background-color: rgba(0, 0, 0, 0.6);
+ cursor: pointer;
+ animation: fui-drawer-fade 200ms ease;
+}
+
+.panel {
+ @include glass;
+ position: relative;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ gap: $space-4;
+ padding: $space-5;
+ box-shadow:
+ inset 0 0 0 2px var(--fui-shadow-color),
+ $glass-shadow;
+ outline: none;
+}
+
+.panel.left,
+.panel.right {
+ width: 100%;
+ height: 100vh;
+ max-height: 100vh;
+}
+
+.panel.top,
+.panel.bottom {
+ width: 100vw;
+ max-width: 100vw;
+ max-height: 100vh;
+}
+
+.left.sm,
+.right.sm {
+ max-width: 20rem;
+}
+
+.left.md,
+.right.md {
+ max-width: 28rem;
+}
+
+.left.lg,
+.right.lg {
+ max-width: 40rem;
+}
+
+.top.sm,
+.bottom.sm {
+ height: 40vh;
+}
+
+.top.md,
+.bottom.md {
+ height: 60vh;
+}
+
+.top.lg,
+.bottom.lg {
+ height: 85vh;
+}
+
+.panel.left {
+ animation: fui-drawer-in-left 240ms ease;
+}
+
+.panel.right {
+ animation: fui-drawer-in-right 240ms ease;
+}
+
+.panel.top {
+ animation: fui-drawer-in-top 240ms ease;
+}
+
+.panel.bottom {
+ animation: fui-drawer-in-bottom 240ms ease;
+}
+
+@include reduced-motion {
+ .panel,
+ .backdrop {
+ animation: none;
+ }
+}
+
+.header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: $space-3;
+}
+
+.title {
+ margin: 0;
+ font-family: $font-family-title;
+ font-size: $font-size-xl;
+ font-weight: 700;
+}
+
+.close {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ width: $space-6;
+ height: $space-6;
+ border: none;
+ background: none;
+ color: var(--fui-text);
+ font-size: $font-size-xl;
+ line-height: 1;
+ cursor: pointer;
+ opacity: 0.6;
+ transition: opacity 120ms ease;
+
+ &:hover {
+ opacity: 1;
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+}
+
+.body {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: $space-4;
+ overflow-y: auto;
+}
+
+.footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: $space-2;
+}
+
+@keyframes fui-drawer-fade {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes fui-drawer-in-left {
+ from {
+ transform: translateX(-100%);
+ }
+
+ to {
+ transform: translateX(0);
+ }
+}
+
+@keyframes fui-drawer-in-right {
+ from {
+ transform: translateX(100%);
+ }
+
+ to {
+ transform: translateX(0);
+ }
+}
+
+@keyframes fui-drawer-in-top {
+ from {
+ transform: translateY(-100%);
+ }
+
+ to {
+ transform: translateY(0);
+ }
+}
+
+@keyframes fui-drawer-in-bottom {
+ from {
+ transform: translateY(100%);
+ }
+
+ to {
+ transform: translateY(0);
+ }
+}
diff --git a/src/components/drawer/drawer.tsx b/src/components/drawer/drawer.tsx
new file mode 100644
index 0000000..2bfe4f6
--- /dev/null
+++ b/src/components/drawer/drawer.tsx
@@ -0,0 +1,133 @@
+import { type ReactNode, useEffect, useId, useRef } from 'react';
+import { createPortal } from 'react-dom';
+import { cn } from '../../utils/style-helpers';
+import styles from './drawer.module.scss';
+
+const focusableSelector =
+ 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
+
+export type DrawerSide = 'left' | 'right' | 'top' | 'bottom';
+
+export interface DrawerProps {
+ open: boolean;
+ onClose: () => void;
+ side?: DrawerSide;
+ title?: string;
+ size?: 'sm' | 'md' | 'lg';
+ children: ReactNode;
+ className?: string;
+}
+
+interface DrawerSlotProps {
+ children: ReactNode;
+ className?: string;
+}
+
+function DrawerRoot({
+ open,
+ onClose,
+ side = 'right',
+ title,
+ size = 'md',
+ children,
+ className,
+}: DrawerProps) {
+ const uid = useId();
+ const titleId = `fui-drawer-title-${uid}`;
+ const panelRef = useRef(null);
+ const previouslyFocused = useRef(null);
+ const onCloseRef = useRef(onClose);
+ onCloseRef.current = onClose;
+
+ useEffect(() => {
+ if (!open) return;
+ previouslyFocused.current = document.activeElement as HTMLElement | null;
+ panelRef.current?.focus();
+
+ const onKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Escape') {
+ event.preventDefault();
+ onCloseRef.current();
+ return;
+ }
+ if (event.key !== 'Tab') return;
+ const focusables = panelRef.current?.querySelectorAll(focusableSelector);
+ if (!focusables || focusables.length === 0) {
+ event.preventDefault();
+ panelRef.current?.focus();
+ return;
+ }
+ const first = focusables[0];
+ const last = focusables[focusables.length - 1];
+ if (event.shiftKey && document.activeElement === first) {
+ event.preventDefault();
+ last.focus();
+ } else if (!event.shiftKey && document.activeElement === last) {
+ event.preventDefault();
+ first.focus();
+ }
+ };
+
+ document.addEventListener('keydown', onKeyDown);
+ const previousOverflow = document.body.style.overflow;
+ document.body.style.overflow = 'hidden';
+
+ return () => {
+ document.removeEventListener('keydown', onKeyDown);
+ document.body.style.overflow = previousOverflow;
+ previouslyFocused.current?.focus();
+ };
+ }, [open]);
+
+ if (!open || typeof document === 'undefined') return null;
+
+ return createPortal(
+
+
+
+
+ {title && (
+
+ {title}
+
+ )}
+
+
+ {children}
+
+
,
+ document.body,
+ );
+}
+
+function DrawerBody({ children, className }: DrawerSlotProps) {
+ return {children}
;
+}
+
+function DrawerFooter({ children, className }: DrawerSlotProps) {
+ return {children}
;
+}
+
+export const Drawer = Object.assign(DrawerRoot, {
+ Body: DrawerBody,
+ Footer: DrawerFooter,
+});
diff --git a/src/components/drawer/index.ts b/src/components/drawer/index.ts
new file mode 100644
index 0000000..4cacfd5
--- /dev/null
+++ b/src/components/drawer/index.ts
@@ -0,0 +1,2 @@
+export { Drawer } from './drawer';
+export type { DrawerProps, DrawerSide } from './drawer';
diff --git a/src/index.ts b/src/index.ts
index c6557b8..ddae3ab 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -57,6 +57,9 @@ export type { SwitchProps } from './components/switch';
export { Modal } from './components/modal';
export type { ModalProps } from './components/modal';
+export { Drawer } from './components/drawer';
+export type { DrawerProps, DrawerSide } from './components/drawer';
+
export { ListItem } from './components/list-item';
export type { ListItemProps } from './components/list-item';
From f0a40f83e36fe21d55e237acb408451a423e0bd6 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:27:55 +0000
Subject: [PATCH 06/16] feat(release): Kbd + InlineCode + CodeBlock (filename,
copy, per-line diff add/remove styling)
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 2 +-
.../code-block/code-block.module.scss | 97 ++++++++++++++++++
src/components/code-block/code-block.tsx | Bin 0 -> 2535 bytes
src/components/code-block/index.ts | 2 +
src/components/inline-code/index.ts | 2 +
.../inline-code/inline-code.module.scss | 12 +++
src/components/inline-code/inline-code.tsx | 13 +++
src/components/kbd/index.ts | 2 +
src/components/kbd/kbd.module.scss | 19 ++++
src/components/kbd/kbd.tsx | 13 +++
src/index.ts | 9 ++
11 files changed, 170 insertions(+), 1 deletion(-)
create mode 100644 src/components/code-block/code-block.module.scss
create mode 100644 src/components/code-block/code-block.tsx
create mode 100644 src/components/code-block/index.ts
create mode 100644 src/components/inline-code/index.ts
create mode 100644 src/components/inline-code/inline-code.module.scss
create mode 100644 src/components/inline-code/inline-code.tsx
create mode 100644 src/components/kbd/index.ts
create mode 100644 src/components/kbd/kbd.module.scss
create mode 100644 src/components/kbd/kbd.tsx
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 000419a..38b33be 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -20,7 +20,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] EmptyState (loading / empty / error, centered per UX_PRINCIPLES layout-stability rules)
- [x] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
- [x] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
-- [ ] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
+- [x] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
- [ ] CopyButton + Breadcrumb + Menu + FileButton
- [ ] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [ ] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
diff --git a/src/components/code-block/code-block.module.scss b/src/components/code-block/code-block.module.scss
new file mode 100644
index 0000000..ba06133
--- /dev/null
+++ b/src/components/code-block/code-block.module.scss
@@ -0,0 +1,97 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.codeBlock {
+ overflow: hidden;
+ background-color: rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 0 0 2px var(--fui-shadow-color);
+ font-family: ui-monospace, 'SF Mono', 'Menlo', 'Consolas', monospace;
+ font-size: $font-size-sm;
+
+ :global(.dark) & {
+ background-color: rgba(0, 0, 0, 0.4);
+ }
+}
+
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: $space-2;
+ padding: $space-2 $space-3;
+ border-bottom: 2px solid var(--fui-shadow-color);
+}
+
+.filename {
+ overflow: hidden;
+ color: var(--fui-text);
+ font-weight: 600;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.copy {
+ flex-shrink: 0;
+ margin-left: auto;
+ border: none;
+ padding: 0.1em 0.4em;
+ background: none;
+ color: var(--fui-accent);
+ font-family: inherit;
+ font-size: inherit;
+ font-weight: 600;
+ cursor: pointer;
+ opacity: 0.8;
+ transition: opacity 120ms ease;
+
+ &:hover {
+ opacity: 1;
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+}
+
+.pre {
+ margin: 0;
+ padding: $space-3 0;
+ overflow-x: auto;
+ color: var(--fui-text);
+ line-height: 1.6;
+ tab-size: 2;
+}
+
+.line {
+ display: block;
+ padding: 0 $space-3;
+}
+
+.marker {
+ display: inline-block;
+ width: 1.2ch;
+ user-select: none;
+ opacity: 0.7;
+}
+
+.content {
+ white-space: pre;
+}
+
+.add {
+ background-color: var(--fui-status-success-fill);
+
+ .marker {
+ color: var(--fui-status-success-text);
+ opacity: 1;
+ }
+}
+
+.remove {
+ background-color: var(--fui-status-error-fill);
+
+ .marker {
+ color: var(--fui-status-error-text);
+ opacity: 1;
+ }
+}
diff --git a/src/components/code-block/code-block.tsx b/src/components/code-block/code-block.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..c7eb3122e190bf2a19d38cbd6fc34ae1b97bbafd
GIT binary patch
literal 2535
zcmZ`*-*4MC5Z<%@ifb@b66(n59v#`imJZlM+Z9{hya1u4bIe5|1(8l_DEi-bM~af{
zE?OtBZHpWh*c(G|w=X$~ID0DRgtb4}%ASB;ek
z&|VrzSCcvw&+<`N-K2Rb>#Y_|ag#bDBaa*3f$IrC?jU~Wj0tsQ4-HKer*ucD-J^=#
zJDe0`k3poECGXR@P^k+2l9K&SR;Uj)_E^UNujCwlxw^U<0y`cQ{&~aOS)DfzYiQaa
zD()Fy;ESj;f2-!CcD2Q39Xo%2J)ZE0#oM|~ncND)L_Yl7IyIdVG)qy`{nQ`z0(TFd
zEnh+B`JthUPFrV1^q@)~(Z-xC;ZeNuzRo~gIKvz!K_B2_&xTimZY$TH13_Oh8cxL!
z#+dGbuP)G}I!^jHFIiT|XBe*Gs?AmG7cPxwf$j>@S~@mO7W)5V!>!qPxdeVmr#45E?ZvJ_h^iA=YjXrV-YQ$@5W`0?mAOmrTq
z)om&BCl_~?H*n1r_-B&Z7jdcS@pzUsTli+C36imJwjlk3Z8*>B2LFe2I-Mw$@qmO-
zhsj+Yzv(7JNn__W<_Vi#R|;6Q^rxE^8z<1u^?18TLr?r>IJ-|Kh#WJ}hSm9l;
+
+export function InlineCode({ className, children, ...props }: InlineCodeProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/kbd/index.ts b/src/components/kbd/index.ts
new file mode 100644
index 0000000..e7263a3
--- /dev/null
+++ b/src/components/kbd/index.ts
@@ -0,0 +1,2 @@
+export { Kbd } from './kbd';
+export type { KbdProps } from './kbd';
diff --git a/src/components/kbd/kbd.module.scss b/src/components/kbd/kbd.module.scss
new file mode 100644
index 0000000..a648480
--- /dev/null
+++ b/src/components/kbd/kbd.module.scss
@@ -0,0 +1,19 @@
+@use '../../styles/tokens' as *;
+
+.kbd {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 1.5em;
+ padding: 0.1em 0.4em;
+ background-color: var(--fui-surface);
+ color: var(--fui-text);
+ font-family: ui-monospace, 'SF Mono', 'Menlo', 'Consolas', monospace;
+ font-size: 0.8125em;
+ font-weight: 600;
+ line-height: 1.4;
+ white-space: nowrap;
+ box-shadow:
+ inset 0 0 0 1px var(--fui-shadow-color),
+ 0 1px 0 0 var(--fui-shadow-color);
+}
diff --git a/src/components/kbd/kbd.tsx b/src/components/kbd/kbd.tsx
new file mode 100644
index 0000000..9ef0df1
--- /dev/null
+++ b/src/components/kbd/kbd.tsx
@@ -0,0 +1,13 @@
+import type { HTMLAttributes } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './kbd.module.scss';
+
+export type KbdProps = HTMLAttributes;
+
+export function Kbd({ className, children, ...props }: KbdProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/index.ts b/src/index.ts
index ddae3ab..aeb9f52 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -93,4 +93,13 @@ export type {
SegmentedControlProps,
} from './components/segmented-control';
+export { Kbd } from './components/kbd';
+export type { KbdProps } from './components/kbd';
+
+export { InlineCode } from './components/inline-code';
+export type { InlineCodeProps } from './components/inline-code';
+
+export { CodeBlock } from './components/code-block';
+export type { CodeBlockProps, CodeDiff, CodeLine } from './components/code-block';
+
export { cn } from './utils/style-helpers';
From 400173ef8dbb9ee458ab6c5929c02ddb005d4250 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:32:30 +0000
Subject: [PATCH 07/16] feat(release): CopyButton + Breadcrumb + Menu +
FileButton
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 2 +-
papercamp/ideas/IDEA-9.md | 3 +-
papercamp/ideas/index.md | 2 +-
papercamp/run-order.md | 1 -
.../breadcrumb/breadcrumb.module.scss | 57 ++++++
src/components/breadcrumb/breadcrumb.tsx | 69 +++++++
src/components/breadcrumb/index.ts | 2 +
.../copy-button/copy-button.module.scss | 44 +++++
src/components/copy-button/copy-button.tsx | 78 ++++++++
src/components/copy-button/index.ts | 2 +
.../file-button/file-button.module.scss | 57 ++++++
src/components/file-button/file-button.tsx | 37 ++++
src/components/file-button/index.ts | 2 +
src/components/menu/index.ts | 2 +
src/components/menu/menu.module.scss | 84 ++++++++
src/components/menu/menu.tsx | 180 ++++++++++++++++++
src/index.ts | 12 ++
17 files changed, 630 insertions(+), 4 deletions(-)
create mode 100644 src/components/breadcrumb/breadcrumb.module.scss
create mode 100644 src/components/breadcrumb/breadcrumb.tsx
create mode 100644 src/components/breadcrumb/index.ts
create mode 100644 src/components/copy-button/copy-button.module.scss
create mode 100644 src/components/copy-button/copy-button.tsx
create mode 100644 src/components/copy-button/index.ts
create mode 100644 src/components/file-button/file-button.module.scss
create mode 100644 src/components/file-button/file-button.tsx
create mode 100644 src/components/file-button/index.ts
create mode 100644 src/components/menu/index.ts
create mode 100644 src/components/menu/menu.module.scss
create mode 100644 src/components/menu/menu.tsx
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 38b33be..626724f 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -21,7 +21,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] StatusDot + Chip (toggle/filter, aria-pressed) + SegmentedControl
- [x] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
- [x] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
-- [ ] CopyButton + Breadcrumb + Menu + FileButton
+- [x] CopyButton + Breadcrumb + Menu + FileButton
- [ ] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [ ] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
diff --git a/papercamp/ideas/IDEA-9.md b/papercamp/ideas/IDEA-9.md
index a6e0613..f7d993f 100644
--- a/papercamp/ideas/IDEA-9.md
+++ b/papercamp/ideas/IDEA-9.md
@@ -2,8 +2,9 @@
id: IDEA-9
title: Glass frost flickers on scroll — move the filter off the scroller's ancestry
type: fix
-status: review
+status: done
created: 2026-08-05
+updated: 2026-08-07
tags:
- components
- rendering
diff --git a/papercamp/ideas/index.md b/papercamp/ideas/index.md
index 0b36dbf..b799856 100644
--- a/papercamp/ideas/index.md
+++ b/papercamp/ideas/index.md
@@ -10,4 +10,4 @@
| IDEA-6 | Adopt func-ui in the radio project (replace mojo-ui) | feat | idea | migration, radio |
| IDEA-7 | Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu | feat | planned | components, release, radio |
| IDEA-8 | Adopt branch-per-idea working flow | chore | idea | workflow |
-| IDEA-9 | Glass frost flickers on scroll — move the filter off the scroller's ancestry | fix | review | components, rendering |
+| IDEA-9 | Glass frost flickers on scroll — move the filter off the scroller's ancestry | fix | done | components, rendering |
diff --git a/papercamp/run-order.md b/papercamp/run-order.md
index aa0ecf6..073faa8 100644
--- a/papercamp/run-order.md
+++ b/papercamp/run-order.md
@@ -1,4 +1,3 @@
IDEA-3 — Tier 3 — gap-fillers paper-ui never had
IDEA-4 — Showcase gallery entries for every release component
IDEA-7 — Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu
-IDEA-9 — Glass frost flickers on scroll — move the filter off the scroller's ancestry
diff --git a/src/components/breadcrumb/breadcrumb.module.scss b/src/components/breadcrumb/breadcrumb.module.scss
new file mode 100644
index 0000000..6debd2b
--- /dev/null
+++ b/src/components/breadcrumb/breadcrumb.module.scss
@@ -0,0 +1,57 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.breadcrumb {
+ font-family: $font-family-sans;
+ font-size: $font-size-sm;
+}
+
+.list {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: $space-1 $space-2;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.item {
+ display: inline-flex;
+ align-items: center;
+ gap: $space-1 $space-2;
+ min-width: 0;
+}
+
+.link {
+ border: none;
+ padding: 0;
+ background: none;
+ color: var(--fui-text);
+ font: inherit;
+ text-decoration: none;
+ cursor: pointer;
+ opacity: 0.7;
+ transition: opacity 120ms ease;
+
+ &:hover {
+ opacity: 1;
+ text-decoration: underline;
+ text-underline-offset: 3px;
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+}
+
+.current {
+ color: var(--fui-text);
+ font-weight: 700;
+}
+
+.separator {
+ color: var(--fui-text);
+ opacity: 0.4;
+ user-select: none;
+}
diff --git a/src/components/breadcrumb/breadcrumb.tsx b/src/components/breadcrumb/breadcrumb.tsx
new file mode 100644
index 0000000..09eecb3
--- /dev/null
+++ b/src/components/breadcrumb/breadcrumb.tsx
@@ -0,0 +1,69 @@
+import type { HTMLAttributes, ReactNode } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './breadcrumb.module.scss';
+
+export interface BreadcrumbItem {
+ label: ReactNode;
+ href?: string;
+ onClick?: () => void;
+ current?: boolean;
+}
+
+export interface BreadcrumbProps extends Omit, 'children'> {
+ items: BreadcrumbItem[];
+ separator?: ReactNode;
+}
+
+function BreadcrumbNode({ item, current }: { item: BreadcrumbItem; current: boolean }) {
+ if (current) {
+ return (
+
+ {item.label}
+
+ );
+ }
+ if (item.href) {
+ return (
+
+ {item.label}
+
+ );
+ }
+ if (item.onClick) {
+ return (
+
+ );
+ }
+ return {item.label};
+}
+
+export function Breadcrumb({ items, separator = '/', className, ...props }: BreadcrumbProps) {
+ const seen = new Map();
+
+ return (
+
+ );
+}
diff --git a/src/components/breadcrumb/index.ts b/src/components/breadcrumb/index.ts
new file mode 100644
index 0000000..46cb7c5
--- /dev/null
+++ b/src/components/breadcrumb/index.ts
@@ -0,0 +1,2 @@
+export { Breadcrumb } from './breadcrumb';
+export type { BreadcrumbItem, BreadcrumbProps } from './breadcrumb';
diff --git a/src/components/copy-button/copy-button.module.scss b/src/components/copy-button/copy-button.module.scss
new file mode 100644
index 0000000..62461c5
--- /dev/null
+++ b/src/components/copy-button/copy-button.module.scss
@@ -0,0 +1,44 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.copyButton {
+ display: inline-flex;
+ align-items: center;
+ gap: $space-1;
+ border: none;
+ padding: 0.15em 0.4em;
+ background: none;
+ color: var(--fui-accent);
+ font-family: $font-family-sans;
+ font-size: $font-size-sm;
+ font-weight: 600;
+ line-height: 1.2;
+ cursor: pointer;
+ opacity: 0.85;
+ transition:
+ opacity 120ms ease,
+ color 200ms ease;
+
+ &:hover:not(:disabled) {
+ opacity: 1;
+ }
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+.copied {
+ color: var(--fui-status-success-text);
+ opacity: 1;
+}
+
+.icon {
+ display: inline-flex;
+ align-items: center;
+}
diff --git a/src/components/copy-button/copy-button.tsx b/src/components/copy-button/copy-button.tsx
new file mode 100644
index 0000000..370ab3a
--- /dev/null
+++ b/src/components/copy-button/copy-button.tsx
@@ -0,0 +1,78 @@
+import {
+ type ButtonHTMLAttributes,
+ type MouseEvent,
+ type ReactNode,
+ forwardRef,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './copy-button.module.scss';
+
+export interface CopyButtonProps extends Omit, 'value'> {
+ value: string;
+ label?: string;
+ copiedLabel?: string;
+ icon?: ReactNode;
+ copiedIcon?: ReactNode;
+ timeout?: number;
+ onCopy?: () => void;
+}
+
+export const CopyButton = forwardRef(function CopyButton(
+ {
+ value,
+ label = 'copy',
+ copiedLabel = 'copied',
+ icon,
+ copiedIcon,
+ timeout = 2000,
+ onCopy,
+ onClick,
+ className,
+ ...props
+ },
+ ref,
+) {
+ const [copied, setCopied] = useState(false);
+ const timer = useRef();
+
+ useEffect(() => () => window.clearTimeout(timer.current), []);
+
+ const handleClick = (event: MouseEvent) => {
+ onClick?.(event);
+ const write = navigator.clipboard?.writeText(value);
+ if (!write) return;
+ write.then(
+ () => {
+ setCopied(true);
+ onCopy?.();
+ window.clearTimeout(timer.current);
+ timer.current = window.setTimeout(() => setCopied(false), timeout);
+ },
+ () => setCopied(false),
+ );
+ };
+
+ const currentIcon = copied ? (copiedIcon ?? icon) : icon;
+ const currentLabel = copied ? copiedLabel : label;
+
+ return (
+
+ );
+});
diff --git a/src/components/copy-button/index.ts b/src/components/copy-button/index.ts
new file mode 100644
index 0000000..067cd97
--- /dev/null
+++ b/src/components/copy-button/index.ts
@@ -0,0 +1,2 @@
+export { CopyButton } from './copy-button';
+export type { CopyButtonProps } from './copy-button';
diff --git a/src/components/file-button/file-button.module.scss b/src/components/file-button/file-button.module.scss
new file mode 100644
index 0000000..082d11a
--- /dev/null
+++ b/src/components/file-button/file-button.module.scss
@@ -0,0 +1,57 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.fileButton {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: $space-2;
+ padding: $space-2 $space-6;
+ background-color: var(--fui-surface);
+ color: var(--fui-text);
+ font-family: $font-family-sans;
+ font-weight: 700;
+ font-size: $font-size-md;
+ line-height: 1.2;
+ text-transform: uppercase;
+ cursor: pointer;
+ box-shadow: 5px 5px 0 0 var(--fui-shadow-color);
+ backdrop-filter: var(--fui-nested-backdrop, blur(12px));
+ transition:
+ filter 200ms ease,
+ background-color 200ms ease;
+
+ &:hover {
+ filter: brightness(1.05);
+ }
+
+ &:focus-within {
+ @include focus-ring;
+ }
+}
+
+.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+
+ &:hover {
+ filter: none;
+ }
+}
+
+.input {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+.icon {
+ display: inline-flex;
+ align-items: center;
+}
diff --git a/src/components/file-button/file-button.tsx b/src/components/file-button/file-button.tsx
new file mode 100644
index 0000000..fb0e2da
--- /dev/null
+++ b/src/components/file-button/file-button.tsx
@@ -0,0 +1,37 @@
+import { type InputHTMLAttributes, type ReactNode, forwardRef } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './file-button.module.scss';
+
+export interface FileButtonProps
+ extends Omit, 'type' | 'onChange' | 'children'> {
+ onFiles: (files: FileList) => void;
+ icon?: ReactNode;
+ children: ReactNode;
+}
+
+export const FileButton = forwardRef(function FileButton(
+ { onFiles, icon, children, disabled, className, ...props },
+ ref,
+) {
+ return (
+
+ );
+});
diff --git a/src/components/file-button/index.ts b/src/components/file-button/index.ts
new file mode 100644
index 0000000..9eb516e
--- /dev/null
+++ b/src/components/file-button/index.ts
@@ -0,0 +1,2 @@
+export { FileButton } from './file-button';
+export type { FileButtonProps } from './file-button';
diff --git a/src/components/menu/index.ts b/src/components/menu/index.ts
new file mode 100644
index 0000000..ee890c4
--- /dev/null
+++ b/src/components/menu/index.ts
@@ -0,0 +1,2 @@
+export { Menu } from './menu';
+export type { MenuItem, MenuProps } from './menu';
diff --git a/src/components/menu/menu.module.scss b/src/components/menu/menu.module.scss
new file mode 100644
index 0000000..eb7a934
--- /dev/null
+++ b/src/components/menu/menu.module.scss
@@ -0,0 +1,84 @@
+@use '../../styles/tokens' as *;
+@use '../../styles/mixins' as *;
+
+.menu {
+ position: relative;
+ display: inline-block;
+}
+
+.trigger {
+ display: inline-flex;
+ align-items: center;
+ gap: $space-1;
+ border: none;
+ padding: $space-1 $space-2;
+ background: none;
+ color: var(--fui-text);
+ font-family: $font-family-sans;
+ font-size: inherit;
+ line-height: 1.2;
+ cursor: pointer;
+
+ &:focus-visible {
+ @include focus-ring;
+ }
+}
+
+.list {
+ position: absolute;
+ top: calc(100% + #{$space-1});
+ z-index: 40;
+ display: flex;
+ min-width: 10rem;
+ flex-direction: column;
+ padding: $space-1 0;
+ background-color: var(--fui-surface);
+ box-shadow:
+ inset 0 0 0 2px var(--fui-shadow-color),
+ $glass-shadow;
+ backdrop-filter: var(--fui-nested-backdrop, blur(12px));
+ outline: none;
+}
+
+.start {
+ left: 0;
+}
+
+.end {
+ right: 0;
+}
+
+.item {
+ display: flex;
+ align-items: center;
+ gap: $space-2;
+ width: 100%;
+ border: none;
+ padding: $space-2 $space-3;
+ background: none;
+ color: var(--fui-text);
+ font-family: $font-family-sans;
+ font-size: $font-size-sm;
+ text-align: left;
+ white-space: nowrap;
+ cursor: pointer;
+
+ &:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+}
+
+.active:not(:disabled) {
+ background-color: var(--fui-status-neutral-fill);
+}
+
+.danger {
+ color: var(--fui-status-error-text);
+}
+
+.icon {
+ display: inline-flex;
+ flex-shrink: 0;
+ align-items: center;
+}
diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx
new file mode 100644
index 0000000..2c2fd0f
--- /dev/null
+++ b/src/components/menu/menu.tsx
@@ -0,0 +1,180 @@
+import { type KeyboardEvent, type ReactNode, useEffect, useId, useRef, useState } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './menu.module.scss';
+
+export interface MenuItem {
+ label: ReactNode;
+ onSelect?: () => void;
+ icon?: ReactNode;
+ disabled?: boolean;
+ danger?: boolean;
+}
+
+export interface MenuProps {
+ trigger: ReactNode;
+ items: MenuItem[];
+ triggerLabel?: string;
+ align?: 'start' | 'end';
+ className?: string;
+}
+
+export function Menu({ trigger, items, triggerLabel, align = 'start', className }: MenuProps) {
+ const uid = useId();
+ const triggerId = `fui-menu-trigger-${uid}`;
+ const menuId = `fui-menu-${uid}`;
+ const itemId = (index: number) => `${menuId}-item-${index}`;
+
+ const [open, setOpen] = useState(false);
+ const [activeIndex, setActiveIndex] = useState(-1);
+ const rootRef = useRef(null);
+ const triggerRef = useRef(null);
+ const listRef = useRef(null);
+
+ const firstEnabled = () => items.findIndex((item) => !item.disabled);
+ const lastEnabled = () => {
+ for (let i = items.length - 1; i >= 0; i--) if (!items[i].disabled) return i;
+ return -1;
+ };
+ const nextEnabled = (from: number) => {
+ for (let i = from + 1; i < items.length; i++) if (!items[i].disabled) return i;
+ return from;
+ };
+ const prevEnabled = (from: number) => {
+ for (let i = from - 1; i >= 0; i--) if (!items[i].disabled) return i;
+ return from;
+ };
+
+ useEffect(() => {
+ if (open) listRef.current?.focus();
+ }, [open]);
+
+ useEffect(() => {
+ if (!open) return;
+ const onPointer = (event: PointerEvent) => {
+ if (!rootRef.current?.contains(event.target as Node)) setOpen(false);
+ };
+ window.addEventListener('pointerdown', onPointer);
+ return () => window.removeEventListener('pointerdown', onPointer);
+ }, [open]);
+
+ const openMenu = (index: number) => {
+ setActiveIndex(index);
+ setOpen(true);
+ };
+
+ const close = (focusTrigger = true) => {
+ setOpen(false);
+ if (focusTrigger) triggerRef.current?.focus();
+ };
+
+ const select = (index: number) => {
+ const item = items[index];
+ if (!item || item.disabled) return;
+ item.onSelect?.();
+ close();
+ };
+
+ const onTriggerKeyDown = (event: KeyboardEvent) => {
+ switch (event.key) {
+ case 'ArrowDown':
+ case 'Enter':
+ case ' ':
+ event.preventDefault();
+ if (!open) openMenu(firstEnabled());
+ break;
+ case 'ArrowUp':
+ event.preventDefault();
+ if (!open) openMenu(lastEnabled());
+ break;
+ }
+ };
+
+ const onMenuKeyDown = (event: KeyboardEvent) => {
+ switch (event.key) {
+ case 'ArrowDown':
+ event.preventDefault();
+ setActiveIndex((i) => nextEnabled(i));
+ break;
+ case 'ArrowUp':
+ event.preventDefault();
+ setActiveIndex((i) => prevEnabled(i));
+ break;
+ case 'Home':
+ event.preventDefault();
+ setActiveIndex(firstEnabled());
+ break;
+ case 'End':
+ event.preventDefault();
+ setActiveIndex(lastEnabled());
+ break;
+ case 'Enter':
+ case ' ':
+ event.preventDefault();
+ if (activeIndex >= 0) select(activeIndex);
+ break;
+ case 'Escape':
+ event.preventDefault();
+ close();
+ break;
+ case 'Tab':
+ setOpen(false);
+ break;
+ }
+ };
+
+ return (
+
+
+ {open && (
+
+ )}
+
+ );
+}
diff --git a/src/index.ts b/src/index.ts
index aeb9f52..92b1b6b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -102,4 +102,16 @@ export type { InlineCodeProps } from './components/inline-code';
export { CodeBlock } from './components/code-block';
export type { CodeBlockProps, CodeDiff, CodeLine } from './components/code-block';
+export { CopyButton } from './components/copy-button';
+export type { CopyButtonProps } from './components/copy-button';
+
+export { Breadcrumb } from './components/breadcrumb';
+export type { BreadcrumbItem, BreadcrumbProps } from './components/breadcrumb';
+
+export { Menu } from './components/menu';
+export type { MenuItem, MenuProps } from './components/menu';
+
+export { FileButton } from './components/file-button';
+export type { FileButtonProps } from './components/file-button';
+
export { cn } from './utils/style-helpers';
From 9f3689f0bf4bd813c9bfc6255a5a1eafad0de298 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:35:58 +0000
Subject: [PATCH 08/16] feat(release): Icon set (~20: close, check, copy, plus,
folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand,
merge, push, pull, shuffle, commit, github, note)
Refs: IDEA-3
---
papercamp/config.json | 7 +-
papercamp/ideas/IDEA-3.md | 2 +-
src/components/icon/icon.module.scss | 5 +
src/components/icon/icon.tsx | 175 +++++++++++++++++++++++++++
src/components/icon/index.ts | 2 +
src/index.ts | 3 +
6 files changed, 192 insertions(+), 2 deletions(-)
create mode 100644 src/components/icon/icon.module.scss
create mode 100644 src/components/icon/icon.tsx
create mode 100644 src/components/icon/index.ts
diff --git a/papercamp/config.json b/papercamp/config.json
index 16efe15..353bcb7 100644
--- a/papercamp/config.json
+++ b/papercamp/config.json
@@ -9,7 +9,7 @@
"phase": {
"agent": "claude-code",
"model": "opus",
- "effort": "high"
+ "effort": "medium"
},
"planDraft": {
"agent": "claude-code",
@@ -25,6 +25,11 @@
"agent": "claude-code",
"model": "sonnet",
"effort": "low"
+ },
+ "feedback": {
+ "agent": "claude-code",
+ "model": "sonnet",
+ "effort": "medium"
}
},
"port": 3041
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 626724f..7b7718a 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -22,7 +22,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] Drawer (backdrop, focus trap, Escape, slide) — replaces two inconsistent hand-rolls
- [x] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
- [x] CopyButton + Breadcrumb + Menu + FileButton
-- [ ] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
+- [x] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [ ] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
### Thread
diff --git a/src/components/icon/icon.module.scss b/src/components/icon/icon.module.scss
new file mode 100644
index 0000000..2d2e4e0
--- /dev/null
+++ b/src/components/icon/icon.module.scss
@@ -0,0 +1,5 @@
+.icon {
+ display: inline-block;
+ flex-shrink: 0;
+ vertical-align: middle;
+}
diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx
new file mode 100644
index 0000000..a01b154
--- /dev/null
+++ b/src/components/icon/icon.tsx
@@ -0,0 +1,175 @@
+import type { ReactNode, SVGProps } from 'react';
+import { cn } from '../../utils/style-helpers';
+import styles from './icon.module.scss';
+
+export type IconName =
+ | 'close'
+ | 'check'
+ | 'copy'
+ | 'plus'
+ | 'folder'
+ | 'lightbulb'
+ | 'chevron-up'
+ | 'chevron-down'
+ | 'chevron-left'
+ | 'chevron-right'
+ | 'play'
+ | 'flag'
+ | 'sort-asc'
+ | 'sort-desc'
+ | 'refresh'
+ | 'more'
+ | 'wand'
+ | 'merge'
+ | 'push'
+ | 'pull'
+ | 'shuffle'
+ | 'commit'
+ | 'github'
+ | 'note';
+
+export interface IconProps extends Omit, 'name' | 'children'> {
+ name: IconName;
+ size?: number | string;
+ title?: string;
+}
+
+const paths: Record = {
+ close: ,
+ check: ,
+ copy: (
+ <>
+
+
+ >
+ ),
+ plus: ,
+ folder: ,
+ lightbulb: (
+ <>
+
+
+
+ >
+ ),
+ 'chevron-up': ,
+ 'chevron-down': ,
+ 'chevron-left': ,
+ 'chevron-right': ,
+ play: ,
+ flag: (
+ <>
+
+
+ >
+ ),
+ 'sort-asc': (
+ <>
+
+
+ >
+ ),
+ 'sort-desc': (
+ <>
+
+
+ >
+ ),
+ refresh: (
+ <>
+
+
+
+
+ >
+ ),
+ more: (
+ <>
+
+
+
+ >
+ ),
+ wand: (
+ <>
+
+
+
+ >
+ ),
+ merge: (
+ <>
+
+
+
+
+ >
+ ),
+ push: (
+ <>
+
+
+
+ >
+ ),
+ pull: (
+ <>
+
+
+
+ >
+ ),
+ shuffle: (
+ <>
+
+
+
+
+
+ >
+ ),
+ commit: (
+ <>
+
+
+
+ >
+ ),
+ github: (
+
+ ),
+ note: (
+ <>
+
+
+
+ >
+ ),
+};
+
+export function Icon({ name, size = 24, title, className, ...props }: IconProps) {
+ return (
+
+ );
+}
diff --git a/src/components/icon/index.ts b/src/components/icon/index.ts
new file mode 100644
index 0000000..4a56948
--- /dev/null
+++ b/src/components/icon/index.ts
@@ -0,0 +1,2 @@
+export { Icon } from './icon';
+export type { IconName, IconProps } from './icon';
diff --git a/src/index.ts b/src/index.ts
index 92b1b6b..8160afe 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -114,4 +114,7 @@ export type { MenuItem, MenuProps } from './components/menu';
export { FileButton } from './components/file-button';
export type { FileButtonProps } from './components/file-button';
+export { Icon } from './components/icon';
+export type { IconName, IconProps } from './components/icon';
+
export { cn } from './utils/style-helpers';
From 1762de1b95b39cfbe9eb8cdf26a78e95dcccf21e Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 17:36:38 +0000
Subject: [PATCH 09/16] feat(release): (Table/Tabs/Radio moved to [[IDEA-7]]
with the radio retarget)
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 7b7718a..e8cc6ba 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -2,7 +2,7 @@
id: IDEA-3
title: Tier 3 — gap-fillers paper-ui never had
type: feat
-status: planned
+status: review
created: 2026-08-04
updated: 2026-08-07
tags:
@@ -23,7 +23,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] Kbd + InlineCode + CodeBlock (filename, copy, per-line diff add/remove styling)
- [x] CopyButton + Breadcrumb + Menu + FileButton
- [x] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
-- [ ] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
+- [x] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
### Thread
- [x] 2026-08-07 [chat] Quick test from the embedded toolbar — just reply with a short hello.
From 21217768410894215a616a7dd687630feb6bab2d Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 19:04:40 +0000
Subject: [PATCH 10/16] feat(ideas): apply feedback edit to IDEA-3
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index e8cc6ba..f53c8e8 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -2,7 +2,7 @@
id: IDEA-3
title: Tier 3 — gap-fillers paper-ui never had
type: feat
-status: review
+status: in-progress
created: 2026-08-04
updated: 2026-08-07
tags:
@@ -25,8 +25,14 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [x] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
+### Fixes
+- [ ] Fix failing tests
+ Investigate and fix the currently failing test suite.
+
### Thread
- [x] 2026-08-07 [chat] Quick test from the embedded toolbar — just reply with a short hello.
- [x] 2026-08-07 [chat] [agent] Hello — Paper Scout here, reading you loud and clear.
- [x] 2026-08-07 [chat] just checking
- [x] 2026-08-07 [chat] [agent] Just checking, got it — nothing to change here.
+- [x] 2026-08-07 [chat] fix tests
+- [x] 2026-08-07 [chat] [agent] Added that as a fix here — a new phase to fix the tests. (reopened this idea to re-run)
From 19d9080e48ef1c601d5a77658f5d8bd3a5f1546d Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 19:17:44 +0000
Subject: [PATCH 11/16] feat(ideas): apply feedback edit to IDEA-3
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index f53c8e8..4b28587 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -24,6 +24,8 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] CopyButton + Breadcrumb + Menu + FileButton
- [x] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [x] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
+- [ ] Investigate red Tests/Docs status stamps on deliver card
+ Determine why the deliver card marks Tests and Docs as red — check what conditions those stamps key off (test script/framework presence, docs coverage) and fix or clear the false-negative.
### Fixes
- [ ] Fix failing tests
@@ -36,3 +38,6 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] 2026-08-07 [chat] [agent] Just checking, got it — nothing to change here.
- [x] 2026-08-07 [chat] fix tests
- [x] 2026-08-07 [chat] [agent] Added that as a fix here — a new phase to fix the tests. (reopened this idea to re-run)
+- [ ] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: This repo has no test suite (no test script, framework, or files — and all runnable checks are green); do you want me to (a) close this fix as "no failing tests — repo is green," or (b) scaffold a new test framework + suite from scratch (which is new work beyond "fix failing tests" and needs a framework/scope decision)?
+- [x] 2026-08-07 [chat] then check why the status stamp for Tests and Docs in the deliver card is red
+- [x] 2026-08-07 [chat] [agent] Added that as a fix here — checking why the Tests and Docs status stamps show red on the deliver card.
From 584d9939aa340e009bdfac5fda5dde8cdfffee8f Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 19:55:22 +0000
Subject: [PATCH 12/16] feat(release): Investigate red Tests/Docs status stamps
on deliver card
Refs: IDEA-3
---
papercamp/ideas/IDEA-3.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index 4b28587..adc9daf 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -2,7 +2,7 @@
id: IDEA-3
title: Tier 3 — gap-fillers paper-ui never had
type: feat
-status: in-progress
+status: review
created: 2026-08-04
updated: 2026-08-07
tags:
@@ -24,7 +24,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] CopyButton + Breadcrumb + Menu + FileButton
- [x] Icon set (~20: close, check, copy, plus, folder, lightbulb, chevrons, play, flag, sort arrows, refresh, more, wand, merge, push, pull, shuffle, commit, github, note)
- [x] (Table/Tabs/Radio moved to [[IDEA-7]] with the radio retarget)
-- [ ] Investigate red Tests/Docs status stamps on deliver card
+- [x] Investigate red Tests/Docs status stamps on deliver card
Determine why the deliver card marks Tests and Docs as red — check what conditions those stamps key off (test script/framework presence, docs coverage) and fix or clear the false-negative.
### Fixes
From e962d47a0d1b8c4eadfadfba7ce6cc602304c3da Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 21:13:40 +0000
Subject: [PATCH 13/16] docs(ideas): mark IDEA-3 fix 1 done and log
no-test-suite finding
---
papercamp/ideas/IDEA-3.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index adc9daf..b7d86ad 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -8,7 +8,6 @@ updated: 2026-08-07
tags:
- components
- release
-order: 1
---
The bespoke-UI census found ~28 hand-rolled chrome-less buttons across 10 files, ~20 loading/empty/error text states, 13 app-local icons plus text-glyph fallbacks with comments naming the missing icon, two inconsistent drawers, and duplicated diff/code/chip/dot patterns. These components make func-ui a genuine upgrade rather than a re-skin.
@@ -28,7 +27,7 @@ Skipped for the initial release (no demand from either target inventory): Accord
Determine why the deliver card marks Tests and Docs as red — check what conditions those stamps key off (test script/framework presence, docs coverage) and fix or clear the false-negative.
### Fixes
-- [ ] Fix failing tests
+- [x] Fix failing tests
Investigate and fix the currently failing test suite.
### Thread
@@ -41,3 +40,4 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [ ] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: This repo has no test suite (no test script, framework, or files — and all runnable checks are green); do you want me to (a) close this fix as "no failing tests — repo is green," or (b) scaffold a new test framework + suite from scratch (which is new work beyond "fix failing tests" and needs a framework/scope decision)?
- [x] 2026-08-07 [chat] then check why the status stamp for Tests and Docs in the deliver card is red
- [x] 2026-08-07 [chat] [agent] Added that as a fix here — checking why the Tests and Docs status stamps show red on the deliver card.
+- [ ] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: "Fix failing tests" has nothing to fix — func-ui (this plan's repo) has no test suite at all: no `test` script, no vitest/jest/testing-library dependency, no `*.test.*`/`*.spec.*` files, no test runner config, and no test step in CI (`ci.yml` runs only check-types + lint + build). `pnpm run check-types` is green and there is no failing test suite to repair. This is the same unresolved parked question from earlier: do you want me to (a) close this fix as "no failing tests — repo is green" (leave the checkbox and add nothing), or (b) scaffold a test framework + initial suite from scratch (Vitest + React Testing Library, config, and starter component tests) — which is substantial new work beyond "fix failing tests" and needs a framework/scope decision I can't make for you?
From 93bc0a28b399f039185f8e68df4cd3dce8cdb7e2 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Fri, 7 Aug 2026 21:13:55 +0000
Subject: [PATCH 14/16] docs(ideas): mark IDEA-3 as review
---
papercamp/ideas/index.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/papercamp/ideas/index.md b/papercamp/ideas/index.md
index b799856..64f6e11 100644
--- a/papercamp/ideas/index.md
+++ b/papercamp/ideas/index.md
@@ -4,7 +4,7 @@
|----|-------|------|--------|------|
| IDEA-1 | Tier 1 — the six workhorse components | feat | done | components, release |
| IDEA-2 | Tier 2 — form controls and overlays | feat | done | components, release |
-| IDEA-3 | Tier 3 — gap-fillers paper-ui never had | feat | in-progress | components, release |
+| IDEA-3 | Tier 3 — gap-fillers paper-ui never had | feat | review | components, release |
| IDEA-4 | Showcase gallery entries for every release component | docs | planned | showcase, release |
| IDEA-5 | Migrate paper-camp from paper-ui to func-ui | feat | dropped | migration |
| IDEA-6 | Adopt func-ui in the radio project (replace mojo-ui) | feat | idea | migration, radio |
From 80a502c885e5316b840e11f4399ae89a2e99eed4 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Sat, 8 Aug 2026 10:39:30 +0000
Subject: [PATCH 15/16] chore(config): Wire vitest as the test runner and tidy
idea titles
---
package.json | 17 ++-
papercamp/ideas/IDEA-3.md | 7 +-
papercamp/ideas/IDEA-4.md | 2 +-
papercamp/ideas/IDEA-6.md | 2 +-
papercamp/ideas/IDEA-7.md | 2 +-
papercamp/ideas/index.md | 8 +-
pnpm-lock.yaml | 276 ++++++++++++++++++++++++++++++++++++++
vitest.config.ts | 9 ++
8 files changed, 309 insertions(+), 14 deletions(-)
create mode 100644 vitest.config.ts
diff --git a/package.json b/package.json
index 7ba3d96..6067e18 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,10 @@
"version": "0.1.1",
"description": "Glossy, noisy, cosy React component library — frosted glass, film grain, and lava glow",
"type": "module",
- "sideEffects": ["**/*.css", "**/*.scss"],
+ "sideEffects": [
+ "**/*.css",
+ "**/*.scss"
+ ],
"packageManager": "pnpm@10.12.1",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
@@ -43,7 +46,8 @@
"lint:fix": "biome check ./src --write && stylelint \"src/**/*.scss\"",
"lint:styles": "stylelint \"src/**/*.scss\"",
"check-package": "publint",
- "ci": "pnpm run check-types && pnpm run lint && pnpm run build"
+ "ci": "pnpm run check-types && pnpm run lint && pnpm run build",
+ "test": "vitest run"
},
"repository": {
"type": "git",
@@ -90,9 +94,14 @@
"tailwindcss": "^3.4.14",
"typescript": "^5.6.3",
"vite": "^5.4.9",
- "vite-plugin-dts": "^4.5.4"
+ "vite-plugin-dts": "^4.5.4",
+ "vitest": "^2.1.9"
},
"pnpm": {
- "onlyBuiltDependencies": ["@biomejs/biome", "@swc/core", "esbuild"]
+ "onlyBuiltDependencies": [
+ "@biomejs/biome",
+ "@swc/core",
+ "esbuild"
+ ]
}
}
diff --git a/papercamp/ideas/IDEA-3.md b/papercamp/ideas/IDEA-3.md
index b7d86ad..a0dd122 100644
--- a/papercamp/ideas/IDEA-3.md
+++ b/papercamp/ideas/IDEA-3.md
@@ -1,6 +1,6 @@
---
id: IDEA-3
-title: Tier 3 — gap-fillers paper-ui never had
+title: Tier 3 gap-filler components
type: feat
status: review
created: 2026-08-04
@@ -37,7 +37,8 @@ Skipped for the initial release (no demand from either target inventory): Accord
- [x] 2026-08-07 [chat] [agent] Just checking, got it — nothing to change here.
- [x] 2026-08-07 [chat] fix tests
- [x] 2026-08-07 [chat] [agent] Added that as a fix here — a new phase to fix the tests. (reopened this idea to re-run)
-- [ ] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: This repo has no test suite (no test script, framework, or files — and all runnable checks are green); do you want me to (a) close this fix as "no failing tests — repo is green," or (b) scaffold a new test framework + suite from scratch (which is new work beyond "fix failing tests" and needs a framework/scope decision)?
+- [x] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: This repo has no test suite (no test script, framework, or files — and all runnable checks are green); do you want me to (a) close this fix as "no failing tests — repo is green," or (b) scaffold a new test framework + suite from scratch (which is new work beyond "fix failing tests" and needs a framework/scope decision)? → Resolved by owner: no suite scaffolding wanted — "there is no decision, just make it green." Wired vitest (`vitest run` + `passWithNoTests` config, `test` script) so the Tests check runs the real runner and passes; future `*.test.*` files are picked up with no further setup.
- [x] 2026-08-07 [chat] then check why the status stamp for Tests and Docs in the deliver card is red
- [x] 2026-08-07 [chat] [agent] Added that as a fix here — checking why the Tests and Docs status stamps show red on the deliver card.
-- [ ] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: "Fix failing tests" has nothing to fix — func-ui (this plan's repo) has no test suite at all: no `test` script, no vitest/jest/testing-library dependency, no `*.test.*`/`*.spec.*` files, no test runner config, and no test step in CI (`ci.yml` runs only check-types + lint + build). `pnpm run check-types` is green and there is no failing test suite to repair. This is the same unresolved parked question from earlier: do you want me to (a) close this fix as "no failing tests — repo is green" (leave the checkbox and add nothing), or (b) scaffold a test framework + initial suite from scratch (Vitest + React Testing Library, config, and starter component tests) — which is substantial new work beyond "fix failing tests" and needs a framework/scope decision I can't make for you?
+- [x] 2026-08-07 [question] [agent] Run-all parked on fix 1 ("Fix failing tests") — the agent needs a decision: "Fix failing tests" has nothing to fix — func-ui (this plan's repo) has no test suite at all: no `test` script, no vitest/jest/testing-library dependency, no `*.test.*`/`*.spec.*` files, no test runner config, and no test step in CI (`ci.yml` runs only check-types + lint + build). `pnpm run check-types` is green and there is no failing test suite to repair. This is the same unresolved parked question from earlier: do you want me to (a) close this fix as "no failing tests — repo is green" (leave the checkbox and add nothing), or (b) scaffold a test framework + initial suite from scratch (Vitest + React Testing Library, config, and starter component tests) — which is substantial new work beyond "fix failing tests" and needs a framework/scope decision I can't make for you? → Duplicate of the question above; same resolution — vitest wired with `passWithNoTests`, Tests check green.
+- [x] 2026-08-07 [log] [agent] Docs stamp was red from 4 title-style findings (the 0.16.0 title convention): retitled IDEA-3/4/6/7 to fit the 40-char no-subtitle rule (detail already lives in their bodies); consistency now reports 0 issues. Tests check re-run and passing.
diff --git a/papercamp/ideas/IDEA-4.md b/papercamp/ideas/IDEA-4.md
index 3fd1afb..5974012 100644
--- a/papercamp/ideas/IDEA-4.md
+++ b/papercamp/ideas/IDEA-4.md
@@ -1,6 +1,6 @@
---
id: IDEA-4
-title: Showcase gallery entries for every release component
+title: Showcase entries for all components
type: docs
status: planned
created: 2026-08-04
diff --git a/papercamp/ideas/IDEA-6.md b/papercamp/ideas/IDEA-6.md
index 1950b73..2425811 100644
--- a/papercamp/ideas/IDEA-6.md
+++ b/papercamp/ideas/IDEA-6.md
@@ -1,6 +1,6 @@
---
id: IDEA-6
-title: Adopt func-ui in the radio project (replace mojo-ui)
+title: Adopt func-ui in the radio project
type: feat
status: idea
created: 2026-08-04
diff --git a/papercamp/ideas/IDEA-7.md b/papercamp/ideas/IDEA-7.md
index 9bdc2f9..fbaa4bb 100644
--- a/papercamp/ideas/IDEA-7.md
+++ b/papercamp/ideas/IDEA-7.md
@@ -1,6 +1,6 @@
---
id: IDEA-7
-title: Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu
+title: Radio-parity components
type: feat
status: planned
created: 2026-08-04
diff --git a/papercamp/ideas/index.md b/papercamp/ideas/index.md
index 64f6e11..164cd80 100644
--- a/papercamp/ideas/index.md
+++ b/papercamp/ideas/index.md
@@ -4,10 +4,10 @@
|----|-------|------|--------|------|
| IDEA-1 | Tier 1 — the six workhorse components | feat | done | components, release |
| IDEA-2 | Tier 2 — form controls and overlays | feat | done | components, release |
-| IDEA-3 | Tier 3 — gap-fillers paper-ui never had | feat | review | components, release |
-| IDEA-4 | Showcase gallery entries for every release component | docs | planned | showcase, release |
+| IDEA-3 | Tier 3 gap-filler components | feat | review | components, release |
+| IDEA-4 | Showcase entries for all components | docs | planned | showcase, release |
| IDEA-5 | Migrate paper-camp from paper-ui to func-ui | feat | dropped | migration |
-| IDEA-6 | Adopt func-ui in the radio project (replace mojo-ui) | feat | idea | migration, radio |
-| IDEA-7 | Radio-parity components — Slider, CircularProgress, Radio, DataTable, Tabs, Menu | feat | planned | components, release, radio |
+| IDEA-6 | Adopt func-ui in the radio project | feat | idea | migration, radio |
+| IDEA-7 | Radio-parity components | feat | planned | components, release, radio |
| IDEA-8 | Adopt branch-per-idea working flow | chore | idea | workflow |
| IDEA-9 | Glass frost flickers on scroll — move the filter off the scroller's ancestry | fix | done | components, rendering |
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6cee49e..868a463 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -72,6 +72,9 @@ importers:
vite-plugin-dts:
specifier: ^4.5.4
version: 4.5.4(rollup@4.62.4)(typescript@5.9.3)(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0))
+ vitest:
+ specifier: ^2.1.9
+ version: 2.1.9(sass-embedded@1.100.0)(sass@1.100.0)
packages:
@@ -757,6 +760,35 @@ packages:
peerDependencies:
vite: ^4 || ^5 || ^6 || ^7
+ '@vitest/expect@2.1.9':
+ resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
+
+ '@vitest/mocker@2.1.9':
+ resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@2.1.9':
+ resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
+
+ '@vitest/runner@2.1.9':
+ resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
+
+ '@vitest/snapshot@2.1.9':
+ resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
+
+ '@vitest/spy@2.1.9':
+ resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
+
+ '@vitest/utils@2.1.9':
+ resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
+
'@volar/language-core@2.4.28':
resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==}
@@ -844,6 +876,10 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
@@ -887,6 +923,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+
cacheable@2.5.0:
resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==}
@@ -901,6 +941,14 @@ packages:
caniuse-lite@1.0.30001806:
resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==}
+ chai@5.3.3:
+ resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ engines: {node: '>=18'}
+
+ check-error@2.1.3:
+ resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
+ engines: {node: '>= 16'}
+
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -976,6 +1024,10 @@ packages:
supports-color:
optional: true
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@@ -1011,6 +1063,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -1023,6 +1078,13 @@ packages:
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+ expect-type@1.4.0:
+ resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==}
+ engines: {node: '>=12.0.0'}
+
exsolve@1.1.1:
resolution: {integrity: sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==}
@@ -1263,6 +1325,9 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
+ loupe@3.2.1:
+ resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1355,9 +1420,16 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ pathe@1.1.2:
+ resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
+
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -1635,6 +1707,9 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
@@ -1658,6 +1733,12 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ std-env@3.10.0:
+ resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+
string-argv@0.3.2:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
engines: {node: '>=0.6.19'}
@@ -1734,6 +1815,12 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
tinyexec@1.3.0:
resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==}
engines: {node: '>=18'}
@@ -1742,6 +1829,18 @@ packages:
resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
engines: {node: '>=12.0.0'}
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@1.2.0:
+ resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@3.0.2:
+ resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
+ engines: {node: '>=14.0.0'}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -1780,6 +1879,11 @@ packages:
varint@6.0.0:
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
+ vite-node@2.1.9:
+ resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
vite-plugin-dts@4.5.4:
resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==}
peerDependencies:
@@ -1820,6 +1924,31 @@ packages:
terser:
optional: true
+ vitest@2.1.9:
+ resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 2.1.9
+ '@vitest/ui': 2.1.9
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
@@ -1827,6 +1956,11 @@ packages:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
write-file-atomic@7.0.1:
resolution: {integrity: sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==}
engines: {node: ^20.17.0 || >=22.9.0}
@@ -2341,6 +2475,46 @@ snapshots:
transitivePeerDependencies:
- '@swc/helpers'
+ '@vitest/expect@2.1.9':
+ dependencies:
+ '@vitest/spy': 2.1.9
+ '@vitest/utils': 2.1.9
+ chai: 5.3.3
+ tinyrainbow: 1.2.0
+
+ '@vitest/mocker@2.1.9(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0))':
+ dependencies:
+ '@vitest/spy': 2.1.9
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ vite: 5.4.21(sass-embedded@1.100.0)(sass@1.100.0)
+
+ '@vitest/pretty-format@2.1.9':
+ dependencies:
+ tinyrainbow: 1.2.0
+
+ '@vitest/runner@2.1.9':
+ dependencies:
+ '@vitest/utils': 2.1.9
+ pathe: 1.1.2
+
+ '@vitest/snapshot@2.1.9':
+ dependencies:
+ '@vitest/pretty-format': 2.1.9
+ magic-string: 0.30.21
+ pathe: 1.1.2
+
+ '@vitest/spy@2.1.9':
+ dependencies:
+ tinyspy: 3.0.2
+
+ '@vitest/utils@2.1.9':
+ dependencies:
+ '@vitest/pretty-format': 2.1.9
+ loupe: 3.2.1
+ tinyrainbow: 1.2.0
+
'@volar/language-core@2.4.28':
dependencies:
'@volar/source-map': 2.4.28
@@ -2435,6 +2609,8 @@ snapshots:
argparse@2.0.1: {}
+ assertion-error@2.0.1: {}
+
astral-regex@2.0.0: {}
autoprefixer@10.5.4(postcss@8.5.25):
@@ -2474,6 +2650,8 @@ snapshots:
node-releases: 2.0.51
update-browserslist-db: 1.2.3(browserslist@4.28.7)
+ cac@6.7.14: {}
+
cacheable@2.5.0:
dependencies:
'@cacheable/memory': 2.2.0
@@ -2488,6 +2666,16 @@ snapshots:
caniuse-lite@1.0.30001806: {}
+ chai@5.3.3:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.3
+ deep-eql: 5.0.2
+ loupe: 3.2.1
+ pathval: 2.0.1
+
+ check-error@2.1.3: {}
+
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -2551,6 +2739,8 @@ snapshots:
dependencies:
ms: 2.1.3
+ deep-eql@5.0.2: {}
+
detect-libc@2.1.2:
optional: true
@@ -2574,6 +2764,8 @@ snapshots:
es-errors@1.3.0: {}
+ es-module-lexer@1.7.0: {}
+
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -2604,6 +2796,12 @@ snapshots:
estree-walker@2.0.2: {}
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.9
+
+ expect-type@1.4.0: {}
+
exsolve@1.1.1: {}
fast-deep-equal@3.1.3: {}
@@ -2804,6 +3002,8 @@ snapshots:
dependencies:
js-tokens: 4.0.0
+ loupe@3.2.1: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -2884,8 +3084,12 @@ snapshots:
path-parse@1.0.7: {}
+ pathe@1.1.2: {}
+
pathe@2.0.3: {}
+ pathval@2.0.1: {}
+
picocolors@1.1.1: {}
picomatch@2.3.2: {}
@@ -3154,6 +3358,8 @@ snapshots:
semver@7.7.4: {}
+ siginfo@2.0.0: {}
+
signal-exit@4.1.0: {}
slash@5.1.0: {}
@@ -3170,6 +3376,10 @@ snapshots:
sprintf-js@1.0.3: {}
+ stackback@0.0.2: {}
+
+ std-env@3.10.0: {}
+
string-argv@0.3.2: {}
string-width@4.2.3:
@@ -3309,6 +3519,10 @@ snapshots:
dependencies:
any-promise: 1.3.0
+ tinybench@2.9.0: {}
+
+ tinyexec@0.3.2: {}
+
tinyexec@1.3.0: {}
tinyglobby@0.2.17:
@@ -3316,6 +3530,12 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.5)
picomatch: 4.0.5
+ tinypool@1.1.1: {}
+
+ tinyrainbow@1.2.0: {}
+
+ tinyspy@3.0.2: {}
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -3342,6 +3562,24 @@ snapshots:
varint@6.0.0: {}
+ vite-node@2.1.9(sass-embedded@1.100.0)(sass@1.100.0):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.4.3
+ es-module-lexer: 1.7.0
+ pathe: 1.1.2
+ vite: 5.4.21(sass-embedded@1.100.0)(sass@1.100.0)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
vite-plugin-dts@4.5.4(rollup@4.62.4)(typescript@5.9.3)(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0)):
dependencies:
'@microsoft/api-extractor': 7.58.12
@@ -3371,12 +3609,50 @@ snapshots:
sass: 1.100.0
sass-embedded: 1.100.0
+ vitest@2.1.9(sass-embedded@1.100.0)(sass@1.100.0):
+ dependencies:
+ '@vitest/expect': 2.1.9
+ '@vitest/mocker': 2.1.9(vite@5.4.21(sass-embedded@1.100.0)(sass@1.100.0))
+ '@vitest/pretty-format': 2.1.9
+ '@vitest/runner': 2.1.9
+ '@vitest/snapshot': 2.1.9
+ '@vitest/spy': 2.1.9
+ '@vitest/utils': 2.1.9
+ chai: 5.3.3
+ debug: 4.4.3
+ expect-type: 1.4.0
+ magic-string: 0.30.21
+ pathe: 1.1.2
+ std-env: 3.10.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinypool: 1.1.1
+ tinyrainbow: 1.2.0
+ vite: 5.4.21(sass-embedded@1.100.0)(sass@1.100.0)
+ vite-node: 2.1.9(sass-embedded@1.100.0)(sass@1.100.0)
+ why-is-node-running: 2.3.0
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
vscode-uri@3.1.0: {}
which@1.3.1:
dependencies:
isexe: 2.0.0
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
write-file-atomic@7.0.1:
dependencies:
signal-exit: 4.1.0
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 0000000..5caf52d
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ // No test suite yet — the runner is wired so checks and CI stay green,
+ // and future *.test.* files are picked up with zero further setup.
+ passWithNoTests: true,
+ },
+});
From 4ea42c2fd647399d39d5bbdaea869159b97cbe75 Mon Sep 17 00:00:00 2001
From: Croco Dendy
Date: Sat, 8 Aug 2026 10:43:37 +0000
Subject: [PATCH 16/16] fix(ci): load the paper-camp toolbar plugin lazily,
serve-only
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The build imported @dendelion/paper-camp/vite at config load, but the
package is a dev-machine link: spec that CI can't resolve — the Quality
job's build step died with ERR_MODULE_NOT_FOUND. The plugin is dev-only
(apply: 'serve'), so the config now imports it dynamically in the serve
branch and degrades to no toolbar when the package is absent.
Co-Authored-By: Claude Fable 5
---
vite.config.ts | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/vite.config.ts b/vite.config.ts
index bf8012f..487e49e 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,20 +1,31 @@
import { resolve } from 'node:path';
-import { paperCamp } from '@dendelion/paper-camp/vite';
import react from '@vitejs/plugin-react-swc';
-import { defineConfig } from 'vite';
+import { defineConfig, type PluginOption } from 'vite';
import dts from 'vite-plugin-dts';
import { sharedCssConfig } from './vite.shared';
-export default defineConfig(({ command }) => {
+// Dev-only tooling: the paper-camp toolbar package may be absent (e.g. on CI,
+// where the local link: spec doesn't resolve), so the dev server degrades to
+// no toolbar instead of the whole config failing to load. Builds never import it.
+async function paperCampPlugin(): Promise {
+ try {
+ const { paperCamp } = await import('@dendelion/paper-camp/vite');
+ return [paperCamp()];
+ } catch {
+ return [];
+ }
+}
+
+export default defineConfig(async ({ command }) => {
const baseConfig = {
- plugins: [react()],
+ plugins: [react()] as PluginOption[],
css: sharedCssConfig,
};
if (command === 'serve') {
return {
...baseConfig,
- plugins: [...baseConfig.plugins, paperCamp()],
+ plugins: [...baseConfig.plugins, ...(await paperCampPlugin())],
server: {
host: '0.0.0.0',
port: 3040,