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 ( +
+ {options.map((option) => { + const active = option.value === value; + 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( +
+ +
+ {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 ( + + {title && {title}} + {paths[name]} + + ); +} 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,