{"_id":"@stapel/search-react","_rev":"74-e3900755409d2904c5a40a87171367a6","name":"@stapel/search-react","dist-tags":{"latest":"0.52.1"},"versions":{"0.1.0":{"name":"@stapel/search-react","version":"0.1.0","license":"MIT","_id":"@stapel/search-react@0.1.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"homepage":"https://github.com/usestapel/stapel-react#readme","bugs":{"url":"https://github.com/usestapel/stapel-react/issues"},"dist":{"shasum":"49d09efe5959d1ff7a14a7933660c3d28ee679c6","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.1.0.tgz","fileCount":195,"integrity":"sha512-h4cym0aK6oieuTX/CWDt/em+VVEu5d2m7Hm7OXy9K0NvSz9GqHLrDNvtDkDaziZ5TOK2s6jRnHFilCpZBb+AqQ==","signatures":[{"sig":"MEQCIDwrgwMPueSieBB9fxYAShL1dz0Ge02XJcynvfmEkX8PAiA54kpRMG7M6YADE6mxM5ifFoDvoPi15ZpLR1TwZZ3CWg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":570924},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"gitHead":"bb9379f5de356cfd3e3a588561e9b8e632bf5640","scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"},"repository":{"url":"git+https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (results, facet panel, degradation notice, ranking disclosure) must stay out of the main bundle","path":"dist/default/index.js","limit":"13 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"_npmVersion":"10.9.2","description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.13.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"workspace:^","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/tokens":"workspace:^","@stapel/showcase":"workspace:^","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"workspace:^","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"workspace:^","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.15.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/tokens-antd":">=0.5.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.1.0_1787404064173_0.7778586391918816","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@stapel/search-react","version":"0.2.0","license":"MIT","_id":"@stapel/search-react@0.2.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"301430116c45bd0de7c7b3b3017bbe8f0a188c4c","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.2.0.tgz","fileCount":196,"integrity":"sha512-YI1kX7j3c5BexRVdPMjkV+XE91UZxf9b7TWlJ6ZONEBhggNfVZqg/uzt9kgzmNYK8kK+S68qLLtpBfRLynUA/A==","signatures":[{"sig":"MEQCIF2rARIkGP9a3aPCvRAzQDW8mgop+JLhvmrPlHBfKwx9AiA2+9F5tKNpfjaEAw7yNQqyryoL7L9MJpS89A7Zufz2LQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":574815},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (results, facet panel, degradation notice, ranking disclosure) must stay out of the main bundle","path":"dist/default/index.js","limit":"13 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.15.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/tokens":"^0.5.0","@stapel/showcase":"^0.2.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.5.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.2.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.15.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/tokens-antd":">=0.5.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.2.0_1787441274746_0.8190290802047016","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@stapel/search-react","version":"0.3.0","license":"MIT","_id":"@stapel/search-react@0.3.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"2ecb15cfe88a0901d12c5c0aff3da1a4cdfd6d22","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.3.0.tgz","fileCount":201,"integrity":"sha512-R5uHjHYeEfRv1dpudclIIHjPKKx5DwMBfPjjdAQN2XCMt4FTg19fK/hpw1sLkw8UYpOx/Z2XGkCsCb8iLI92SA==","signatures":[{"sig":"MEUCIQDzWRPMyAua9x7YXWUnoj9cIs0pQGtWmxFWWZr6ZggWJwIgQZKDH8PtrzyFjCs/SBCEdRLXws2D2AVRxXSNLUos6Js=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":592152},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (results, facet panel, degradation notice, ranking disclosure) must stay out of the main bundle","path":"dist/default/index.js","limit":"13 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.17.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/tokens":"^0.5.0","@stapel/showcase":"^0.2.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.5.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.2.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.15.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/tokens-antd":">=0.5.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.3.0_1787506499392_0.15573581569559103","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@stapel/search-react","version":"0.3.1","license":"MIT","_id":"@stapel/search-react@0.3.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"d2ba7d2ba17df5c242655dd08b6e01983726eb94","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.3.1.tgz","fileCount":201,"integrity":"sha512-trNakbiSbexHPLkyKVW1JdD0NDMvFyEoPltCMXbwc73dbsYTG1h/+Zkcl4vYpPJH1MNrAxYtQVKXasQGnYMqAw==","signatures":[{"sig":"MEYCIQD6rv0qe2y0HUKUChqDqjHDzGvEnHODF1S5Z1wnMuIzbwIhALSgRl+pL1Q0Uk+cgFT02dXW/Rn1mBqPV4y+IVowf/Vo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":592746},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (results, facet panel, degradation notice, ranking disclosure) must stay out of the main bundle","path":"dist/default/index.js","limit":"13 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.17.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/tokens":"^0.5.0","@stapel/showcase":"^0.2.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.5.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.2.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.17.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/tokens-antd":">=0.5.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.3.1_1787522283777_0.44145008218473136","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@stapel/search-react","version":"0.4.0","license":"MIT","_id":"@stapel/search-react@0.4.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"1ad8dbc801a3f6af9a50fef92763c09766451cb4","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.4.0.tgz","fileCount":201,"integrity":"sha512-a05BiuUmVzMlqj8DtLjj74W3+q2UqhZogD4aHMIkiyBZ2cKnQzp08i04FkSebTCTpBGVbxatdBCcxjPPi89S0A==","signatures":[{"sig":"MEUCIQCiAEqSitTTliZWw7vV3zf2IcI7EIpRShbmXaKzMHB2VAIgOet+4S6XGgoC0FWRbLNvFXpgraseTKTITMPCXj8BYAc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":620261},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (results, facet panel, degradation notice, ranking disclosure) must stay out of the main bundle","path":"dist/default/index.js","limit":"13 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.17.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/tokens":"^0.5.0","@stapel/showcase":"^0.2.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.5.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.2.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.17.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/tokens-antd":">=0.5.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.4.0_1787527362790_0.0015188000834760462","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@stapel/search-react","version":"0.7.0","license":"MIT","_id":"@stapel/search-react@0.7.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"f9cfc17fbede4648929b4637d4db79b1c3029dfb","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.7.0.tgz","fileCount":241,"integrity":"sha512-VI5MOBDQ7JXZuvYZldh/v9UidMtfBhT0fqFuu8VrN/oNglZDDgPEUTTgYBSK5+aX25cono6/k8kKFGQFGxqucQ==","signatures":[{"sig":"MEUCIQDWBcVyRDggCI9Wr47qDD5DqbvyAikfKhHiitZZUhSOAAIgcNTb74LTlkxLAdMDqfOzTvKH/T2ywUcrcgPlYtNBZ/k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":865241},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots, results, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"16 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.18.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.1","@stapel/tokens":"^0.5.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.7.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.3.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.7.0_1787777948703_0.24930062305484824","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@stapel/search-react","version":"0.8.0","license":"MIT","_id":"@stapel/search-react@0.8.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"8214ee81cdc61bc8d883e1d3af16b07de14c0ec7","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.8.0.tgz","fileCount":256,"integrity":"sha512-YQPC70/0n+B/3RjUO8CkWfUjVuID7RWKcvdsLFzoCzSgqswoxL8FVSe2RJ4Ty/O8qDeDUScndNrDNP2iaWMC2w==","signatures":[{"sig":"MEUCIQCQHmdfRQO1xI6r/MtfR4Pl5uqz3IcXOi0lmuff2xeCWQIgBDA8euSkA6TbtdF0a3y+bRSfv5TD9Od4NY9F1G8KlB8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":972362},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots + the phone chip row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"18 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.19.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.5.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.7.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.3.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.8.0_1787889148349_0.8365975952520854","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@stapel/search-react","version":"0.9.0","license":"MIT","_id":"@stapel/search-react@0.9.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"3199ef0912f9fd510214d783850812b5b1de135d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.9.0.tgz","fileCount":256,"integrity":"sha512-JhLTtoWvyIchk6OPnF48xpShlEDvvzH+jgTypYaV915nXIkbeOxaNEkSZjlEgMgoH5d7KG+cIN8Mc12AlglH7Q==","signatures":[{"sig":"MEQCIFeISfwc2Yu7zDa83hKtpT+qNQlo1HOEB4ED+RXPvZViAiBxouyWrtfGJ8AT7GxfgpRcPoAb3HwqmjUsivAUCwBIhw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":998751},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots + the phone chip row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"18 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.20.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.8.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.3.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.9.0_1788044768305_0.6042719713551188","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"@stapel/search-react","version":"0.9.1","license":"MIT","_id":"@stapel/search-react@0.9.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"e4c63b54183ca78d25e2f466d044d7706f3730f1","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.9.1.tgz","fileCount":256,"integrity":"sha512-hWxuY/43JwkbDkJg6S+bYQaUTb57W024fwekh4FkLEmzPR2CDcPbBLKBzy8oVZg3x2Bz0ng9JQdUR6qF7U5slQ==","signatures":[{"sig":"MEUCIDfSioqTKK/+tbrSw/odlM0C+IsR1Jd5uybsqd0VsvW3AiEAiE/VV1oI1251oztrYE4Zl6BoXA9S1hS4tRL2vEn07S4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.9.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":999754},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots + the phone chip row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"18 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.20.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.8.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.4.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.9.1_1788124089688_0.38720533458117057","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@stapel/search-react","version":"0.10.0","license":"MIT","_id":"@stapel/search-react@0.10.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"807a40d8992b5c4ddf9fa3be78edf5bfcc4c86c3","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.10.0.tgz","fileCount":271,"integrity":"sha512-xnesQgbu2GaFLcxPH4Be+QwRBvBn2ecgJrgAI3JVP+0gonUcNKaXvMrkCvzuNRrT8UqK0R/8epXpBtVa8tetsw==","signatures":[{"sig":"MEUCIFwi9mX2yVbY8Vq5EqIO0p5eJm+t5LAJ54Q9mEIWcEefAiEA8IyNPt6/2xlYKNu2SOrj45Z1o1WNMC3wf9YX7H647pY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1066542},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots + the phone chip row and the location summary row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"18 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.20.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.9.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.5.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.10.0_1788139068360_0.1871612392485229","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@stapel/search-react","version":"0.11.0","license":"MIT","_id":"@stapel/search-react@0.11.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"6b7c1bf7f9b9cae74ac204b48983191b0744c633","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.11.0.tgz","fileCount":271,"integrity":"sha512-q2awgk7UKXbb8IxxoG2e7uJVUnewvm/YvJPAmSQ93gjuefEehzfq7fqTy2MNlIXpksTMpLP88MX5vPaAiVxvcQ==","signatures":[{"sig":"MEYCIQDllhOMawfXU6AU8s9Hd7fyNYlHmiDBlSjAssl0OtXqEwIhAJTGVT9M0v6DvVrERx+IdUHV3aCwKdvLbXdGWrKRCApV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.11.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1110852},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router","path":"dist/index.js","limit":"10 KB"},{"name":"default — the antd skin (query box + typeahead, filters incl. ranges/geo/category slots + the phone chip row and the location summary row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"18 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.21.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.10.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.5.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.7.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.1.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.11.0_1788159031336_0.41939407203979506","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"@stapel/search-react","version":"0.12.0","license":"MIT","_id":"@stapel/search-react@0.12.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"c52f4f5bfa762ec7a04d7d2bcd2bccff32c5da92","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.12.0.tgz","fileCount":276,"integrity":"sha512-5k9kMUD+357DpHN7K3YqJhtjANXr5TlGLVnnuSmZlQs1qHvfwKvBNIkWSSOwSxFTw4eIS0y0qJ17IabbI1jkjQ==","signatures":[{"sig":"MEYCIQCreOB44c7abTtDZr5R42EK5Sxf5klYb7swf8bauSfo9wIhANT/H8jTF18AealR5Fd21btv1KpFC2NweQ+LgU/rl0GV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.12.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1271622},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"10.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"19.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.6.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.12.0_1788169982558_0.15955051863101843","host":"s3://npm-registry-packages-npm-production"}},"0.13.0":{"name":"@stapel/search-react","version":"0.13.0","license":"MIT","_id":"@stapel/search-react@0.13.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"495bd630489cb4b0221299f5a91f89842125424d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.13.0.tgz","fileCount":281,"integrity":"sha512-UZHxe/Y+h44boFq8zHKRufBd6mvw4hAGMWObd4HbhTDjtfQYJYed+sXr/RqXD1Gbv9e8xFT5ILYcZ4ACrDEr/g==","signatures":[{"sig":"MEUCIQCzVSmzYViaRtF+4GOB6mBhJJXEMhLYQCa+uNkl4kdw0gIgUgDq8L5b8XG8rj7qGjxKioKfae80d/5oChn/C01RoMw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.13.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1311682},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"10.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"20 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.6.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.13.0_1788176282360_0.3940708060848426","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"name":"@stapel/search-react","version":"0.14.0","license":"MIT","_id":"@stapel/search-react@0.14.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"fd2202f2335cd056fa32b7fe871d3dfe3901870c","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.14.0.tgz","fileCount":281,"integrity":"sha512-HV4paqnQbvggW+1em/8mE+edh5VAz7PBXLUyE15OLpGhe8snvg8rZEC9gBLwP2eXFsZq0MGUOIHTCWj7BqkfQw==","signatures":[{"sig":"MEQCIEoOltP0qt9Sch/KM+iQ1IvgSGQv+YTnhnd4eBuiFkahAiBZxDiltJZ/6J94ggkeZaArWsNXSbFEppmAoJdQmUZMYQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.14.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1329080},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"10.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"20 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.6.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.14.0_1788178487791_0.7644650260368788","host":"s3://npm-registry-packages-npm-production"}},"0.14.1":{"name":"@stapel/search-react","version":"0.14.1","license":"MIT","_id":"@stapel/search-react@0.14.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"c8515aafea7cd88e06fbd34a859afcc2462111a8","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.14.1.tgz","fileCount":281,"integrity":"sha512-fjCmnavsi9iEujSsB3JYAcHE9oOjaQRQx6ynx3Gru6ACT9izPgd372cXTau2gMIs2au0CFYpS+dn3Ut14ik1Og==","signatures":[{"sig":"MEUCIDCRfRqxq2AY6z17JKyj25k6tXj1yrk88jKMKlpLhUkdAiEA6xVHC0HUWJMMZCkmVTgbJgi3y9/y/ItLkSF7uJXb2PE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.14.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1337981},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"10.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"20 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.8.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.14.1_1788186092492_0.497033386999592","host":"s3://npm-registry-packages-npm-production"}},"0.14.2":{"name":"@stapel/search-react","version":"0.14.2","license":"MIT","_id":"@stapel/search-react@0.14.2","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"4b33e742dd628ded1e9158714e5ea853dcf73065","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.14.2.tgz","fileCount":281,"integrity":"sha512-ondHAKqymjQfx3LwhNB6xSy4w021PISmhxxTgKDg/nt9HpzskX4A+TdqUzxHOrWf5qcUYwmLL/PlVYSPi35MlA==","signatures":[{"sig":"MEQCIBLE9JumucQJyGKWOCwk6JaKApMGY45w4Qm1ScxII7iTAiBs50D8HrZ3OrhIRbDZSWlHWTbyg0eVVHi6R0Y0wOTejA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.14.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1339067},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"10.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"20 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.8.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.14.2_1788288770158_0.08505997906270757","host":"s3://npm-registry-packages-npm-production"}},"0.15.0":{"name":"@stapel/search-react","version":"0.15.0","license":"MIT","_id":"@stapel/search-react@0.15.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"79270e963ad25e43bf2fef176a1e5dfdb141f070","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.15.0.tgz","fileCount":286,"integrity":"sha512-m2p3SjQ/5z3RlKjPGCxXp5Cjf/6oQI909CbpNCc5lLWzLiAk707qJh3K/qkwAElUHnyC8acnjSQNVehObqAvSg==","signatures":[{"sig":"MEUCIQCaIHpK2O9C5V3g6hYgIio7BLZD6L5uLid5Chuar1h9ygIgMDh+nKKUmvquQIEdjKu85luJ6MAuLINnZukxpCsdQ8o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.15.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1382626},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"21 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.22.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.11.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.8.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.15.0_1788298361238_0.007342377778328801","host":"s3://npm-registry-packages-npm-production"}},"0.16.0":{"name":"@stapel/search-react","version":"0.16.0","license":"MIT","_id":"@stapel/search-react@0.16.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"8f16997b24a96f3d9bfe1baef43ec633be0911bc","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.16.0.tgz","fileCount":286,"integrity":"sha512-ww1evg4K8pvIMCRn+DCGG/cBftyCL3ssb05Na24L+fBGwEkfL40XFqjvp1+V5nUouVviRDOvxF6tgqWxDByujA==","signatures":[{"sig":"MEUCIQDoe8MZ+aKTovqsWg5DE7G1rprFEkha+GzXyQF2OMcp/gIgds/Eki1E3a17/d9ITFA7i8FvO1TA/r9/kA96W7cJw+A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.16.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1394838},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"21 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.23.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.6.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.12.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.10.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.16.0_1788328738638_0.635319406039659","host":"s3://npm-registry-packages-npm-production"}},"0.18.0":{"name":"@stapel/search-react","version":"0.18.0","license":"MIT","_id":"@stapel/search-react@0.18.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"9ce6859ae129f95d029a3c4cc81ee86081cc3391","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.18.0.tgz","fileCount":286,"integrity":"sha512-CDIJUwWlKM551T+cw3BRRnXnmbc1qmTA5SCfp3E9ZWAlkeic1TKgoke7zaRuv7LDjahnQMoBoiGVlJRVuBUxPg==","signatures":[{"sig":"MEUCIQC9NCkPpg9H4QpWUebLM4EDrbCdynAmAT6ek9hFuKLszgIgXjeMVk44GDlulDShEibqmGcPwErLT3+J3/rQOyo2hkk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.18.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1462387},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"22 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.23.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.14.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.11.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.18.0_1788364617076_0.9283871966024464","host":"s3://npm-registry-packages-npm-production"}},"0.18.1":{"name":"@stapel/search-react","version":"0.18.1","license":"MIT","_id":"@stapel/search-react@0.18.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"3f4832817a81a6d2f625581ea4cf17039d0b6cc6","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.18.1.tgz","fileCount":286,"integrity":"sha512-/gcEux1CqpDxwICsLMjdWSV4Ry79bnEjApwl7ulSYpdWlJ8t86DdX+SqBK+E051mwzxdz5PZI7tKxTzuQs04gw==","signatures":[{"sig":"MEUCIBl/9Xggs9f2I3VuupkiBTEPG1lItWn4gyqJYojpvQ9YAiEAmM8gddxj8A//YmVXGZro6cV/tpH2fDpDKjP6U4eyeCw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.18.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1467500},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"22 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.23.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.13.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.18.1_1788396815626_0.10726503731546555","host":"s3://npm-registry-packages-npm-production"}},"0.19.0":{"name":"@stapel/search-react","version":"0.19.0","license":"MIT","_id":"@stapel/search-react@0.19.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"d7d9d9b9f7746da220df3d7fb061fc00b1ce4217","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.19.0.tgz","fileCount":286,"integrity":"sha512-93GT8omW2d0qZ58NXEORPER+R/Kpu0jHZaiGJYD7Gr51cOrcJeaHV8tzTgncWIrzhPqlpOTaMo5DRyClveXNIw==","signatures":[{"sig":"MEYCIQDSNkhDph8Np74nATOUydqrDqBD/z0XCuQ0bhPeA2kW0wIhAJOcjDg2aLM/vXFTV7xsYH7b6EmTElUkuaifwGyRZYQ7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.19.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1485437},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"22 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.23.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.14.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.19.0_1788407688211_0.049012899195898685","host":"s3://npm-registry-packages-npm-production"}},"0.20.0":{"name":"@stapel/search-react","version":"0.20.0","license":"MIT","_id":"@stapel/search-react@0.20.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"305c8e1b1f869d212f77caf1cdb415ed16348f2a","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.20.0.tgz","fileCount":286,"integrity":"sha512-UtZ5giMSAOGK/6nAB+toeiiqA/0KSRI33UGm4/rtVAxinGohbPean0Dyih/L62a6GCNjsUcH/EG2nq/rgzUR/g==","signatures":[{"sig":"MEUCIQDfEb8OTRP0BECquzwzAd3xAtqZHoQ4gy5U17SSwf1VyAIgB7xnjXVw29+GgabfEzgrgJHGaMIcQ48Goqi0h6yBRfQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.20.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1486954},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"22 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.24.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.14.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.20.0_1788423725630_0.27265475646487447","host":"s3://npm-registry-packages-npm-production"}},"0.21.0":{"name":"@stapel/search-react","version":"0.21.0","license":"MIT","_id":"@stapel/search-react@0.21.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"01add1febf8fac4af92243a1076234db0721e89c","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.21.0.tgz","fileCount":286,"integrity":"sha512-qe2iorWtbiRJ2laoaz2sO4C480Hfd6XF2cKpF6bm+GqwMpJkP0zBw4t48Whh30nhbcjNjyE/G7mJ4F75Fq23HQ==","signatures":[{"sig":"MEQCIC3GYnSvBjUnl9PFfEu1QryyFSpEIAwC1g10X5iXj/WwAiBW2lqawvwOvV5NStfobqV2AoxoW8mrRKd8jz3ozo3mPg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.21.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1566727},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule and the host label seam): no antd, no react-router","path":"dist/index.js","limit":"11.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking) must stay out of the main bundle","path":"dist/default/index.js","limit":"22.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.24.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.14.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.21.0_1788439330286_0.4012504069268683","host":"s3://npm-registry-packages-npm-production"}},"0.22.0":{"name":"@stapel/search-react","version":"0.22.0","license":"MIT","_id":"@stapel/search-react@0.22.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"6f129a16402cab612fe574910fce66621ceaf9ac","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.22.0.tgz","fileCount":301,"integrity":"sha512-ZoZ3AH7hEVj5tfzmRalq8laTi6DsLib/wvGSsf+WXJAGb7U15gPXSjY7LplKk12ggVQ7jPPbMSC/+dnTmlMC+A==","signatures":[{"sig":"MEUCIQCQeqKSczzy8vwsgaO5IIxyrqkL4wxwQXkOCIQ3OGL2ygIgA4YR/nx02vKh29AoRAt9DYHXuJyB0GvsIbB44T5pHsQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.22.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1666373},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order and the across-alphabets prefix matcher): no antd, no react-router","path":"dist/index.js","limit":"12 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block and the partition chip row) must stay out of the main bundle","path":"dist/default/index.js","limit":"24.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.24.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.14.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.22.0_1788503692627_0.6950562091228605","host":"s3://npm-registry-packages-npm-production"}},"0.23.0":{"name":"@stapel/search-react","version":"0.23.0","license":"MIT","_id":"@stapel/search-react@0.23.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"bc9bc6a2d0d7a843818d16428c7ff044b16e7113","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.23.0.tgz","fileCount":301,"integrity":"sha512-ABW2+rT8o2hfteUKPTxPJXspvgv8AvB5Pq1ivmaon1It888xwUG0oP5MGfxh+oulSCLp+R6r4RxECGNdXrslcA==","signatures":[{"sig":"MEUCIQCXpYkcPhFxcew0cspv+U7QHeCV/wc5Wz/t75rSfKYtCAIgWz6LJUhnrbwsoFevnmaPEMrEQljzpNljzkGuOo9SKio=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.23.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1759980},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds","path":"dist/index.js","limit":"12.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls","path":"dist/default/index.js","limit":"25.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.15.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.23.0_1788507332152_0.5142885075777375","host":"s3://npm-registry-packages-npm-production"}},"0.24.0":{"name":"@stapel/search-react","version":"0.24.0","license":"MIT","_id":"@stapel/search-react@0.24.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"00add4419f86b6c1cb587035efeba1e279f2881d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.24.0.tgz","fileCount":301,"integrity":"sha512-XeQ2O2m9OV2sjEtooozBzfgbz2KObhy/qfm903KSP4eQOzcCGsRjH37yz0PqsKJbHbzbUe56OyYiniC0quvYmw==","signatures":[{"sig":"MEYCIQD6SB4P6IEqlZd4vyAfhfZYD23lYt+OkwblpiM+J5dFPQIhAKU3JjCIgw1XaggHbSJuln8GORBvGexsCFK9Xk4N+x8V","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.24.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1808314},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds","path":"dist/index.js","limit":"12.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it)","path":"dist/default/index.js","limit":"26.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry","path":"dist/i18n/es.js","limit":"3.5 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.15.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.24.0_1788512463417_0.6149280156809838","host":"s3://npm-registry-packages-npm-production"}},"0.25.0":{"name":"@stapel/search-react","version":"0.25.0","license":"MIT","_id":"@stapel/search-react@0.25.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"965c5d4747ea26376e401539d50bf477557c1512","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.25.0.tgz","fileCount":311,"integrity":"sha512-sauTt2/YOVV/D97bcga8pw8qI2C/CqYiZ4h6JoaWuoyV5n6ZOot7qWwRZeRM3UQUf/2R8L7pxsOq8QKxKwZsJw==","signatures":[{"sig":"MEQCIBpD3COgTH2Hwh+GgIo8HbeCoxjoLT3CO//n0D+B8Xj+AiB3vCf+vRSUCBFJKA83PRjiNCIj8PdEUb6y57zq7MZucQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.25.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1873582},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request","path":"dist/index.js","limit":"13 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them","path":"dist/default/index.js","limit":"27 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.16.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.15.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.25.0_1788516746797_0.18670417508173243","host":"s3://npm-registry-packages-npm-production"}},"0.26.0":{"name":"@stapel/search-react","version":"0.26.0","license":"MIT","_id":"@stapel/search-react@0.26.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"9724700fa4023f4f967e9260e057d451669546af","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.26.0.tgz","fileCount":311,"integrity":"sha512-C7vXmLAXqP1z4kkb3zkB1QoZ+YILVAScVyKijlgkb+uLSh347tFhYpiE9q+q4VLS/VkbgFRzissrAKtNIHrmnQ==","signatures":[{"sig":"MEYCIQCd350numGypIovGanWw1k0E/IGVkTmnHwFFsZLw/4WegIhANq0uqbzXXuuKkq5KSDHPFIbnU2TLPO2k13Kr2su0D5J","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.26.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1945974},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share","path":"dist/index.js","limit":"13.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere","path":"dist/default/index.js","limit":"27.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.26.0_1788523272441_0.9152482123875514","host":"s3://npm-registry-packages-npm-production"}},"0.27.0":{"name":"@stapel/search-react","version":"0.27.0","license":"MIT","_id":"@stapel/search-react@0.27.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"46a61b7646f04db1f20981198907c531c397365d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.27.0.tgz","fileCount":311,"integrity":"sha512-K7TWDaSjD13rcg61fYkmU9Nr98Ac71zs6CIAorSIwAaENmMFh9ryVMBITqNpHo/a0HcendWyZYebeSFrz4lSoQ==","signatures":[{"sig":"MEYCIQD6Oat23fi+DRGMlTli8ZXrGueweB5K/gZecKErMlPRSQIhAOJAGf/KlfdkaRwzmWLsLTGniw24/pw6e9rS/3IMYrPJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.27.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1953339},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share","path":"dist/index.js","limit":"13.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere","path":"dist/default/index.js","limit":"27.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.27.0_1788530848870_0.5304878818610699","host":"s3://npm-registry-packages-npm-production"}},"0.28.0":{"name":"@stapel/search-react","version":"0.28.0","license":"MIT","_id":"@stapel/search-react@0.28.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"c8d8efb30f78e2a2d954dd4d8486ada0ac3389a6","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.28.0.tgz","fileCount":311,"integrity":"sha512-G9v/noQVSXtxo5jqB6EnkSyuiwNudzDtfR4Z+Fio5c2vQhl4hMtBeddh57sTxYkPH4w4PwGMmvpOC6RXej0xjA==","signatures":[{"sig":"MEUCIGexwvzc41FIFH0N0JhLa06zdUtToMf/m0XZ+mJSXaDlAiEA8qtPZ+STXnCYXpweRy/pSrf42JOQiWJhKHU5SoAA6zw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.28.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1979917},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared","path":"dist/index.js","limit":"13.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab","path":"dist/default/index.js","limit":"28.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry","path":"dist/i18n/ru.js","limit":"4.75 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.11.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.28.0_1788540213871_0.06819478707011006","host":"s3://npm-registry-packages-npm-production"}},"0.29.0":{"name":"@stapel/search-react","version":"0.29.0","license":"MIT","_id":"@stapel/search-react@0.29.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"ae98907b5c4544739bba43f4ea61047faf993ae3","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.29.0.tgz","fileCount":311,"integrity":"sha512-HNTTzSWc4J9io6DIigkl1A29zaHJP+MdMx3Fj595GSyWKNkNAFjfn2eRB4MbuOGFiQWY7p03LNL/u/DkLynE3Q==","signatures":[{"sig":"MEUCIDKqUuU1Gh74wctbBqWKc4FZMadSEPm6LsZyQLEsmGnzAiEA+HweRBzwIBNFiQtEK0BALdpNQtMiaZBc1e0Q0xy8pMM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.29.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2016597},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared","path":"dist/index.js","limit":"13.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes","path":"dist/default/index.js","limit":"29.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.29.0_1788543463847_0.43518443196145506","host":"s3://npm-registry-packages-npm-production"}},"0.29.1":{"name":"@stapel/search-react","version":"0.29.1","license":"MIT","_id":"@stapel/search-react@0.29.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"a025f6e05783a571527c016d3e791d8f8b81a5a4","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.29.1.tgz","fileCount":311,"integrity":"sha512-oTCSxEjziyrMQB31dS3CCAFlQld0eDAiwepGeIy4Wk3TtGt29XSrR0CSgxuWsS0dbTlr8M3Rv2J+deCsFRAaSQ==","signatures":[{"sig":"MEUCIQCKPg3T9m+HoUiuRpGKcmxBjIo4R8LRZvZpMDsb4kWN/wIgde/9yRsNBzBTC249JY+iuvRnP2MuomSULDA7WSpY2mU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.29.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2026276},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared","path":"dist/index.js","limit":"13.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes","path":"dist/default/index.js","limit":"29.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.29.1_1788547189364_0.3916632130772242","host":"s3://npm-registry-packages-npm-production"}},"0.30.1":{"name":"@stapel/search-react","version":"0.30.1","license":"MIT","_id":"@stapel/search-react@0.30.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"1d3a50943c67caac9b06372cfca2859ded8910bd","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.30.1.tgz","fileCount":311,"integrity":"sha512-Voh1pJfhaCoJi3oZudiLQsMY7lCG4jGW9Ah1m45/9Sz8M7pGKQ1MpUr2w2d8bv5N/f66g/ss2iTbULm8JQV8xw==","signatures":[{"sig":"MEUCIDdzN5jRZZk3pRynJ/I3N9sKm0KwSmdnpe3UgxGHw7EfAiEAkhQYHyfgWSWTV8bT/mrm9p8d7ezBIvkw8TIpA02TXeE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.30.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2081511},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from","path":"dist/index.js","limit":"14 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes","path":"dist/default/index.js","limit":"29.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.30.1_1788561995984_0.5192277648562347","host":"s3://npm-registry-packages-npm-production"}},"0.31.0":{"name":"@stapel/search-react","version":"0.31.0","license":"MIT","_id":"@stapel/search-react@0.31.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"db7371b55e6e2a6b19c4bfed7fd3b96770ce3f71","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.31.0.tgz","fileCount":311,"integrity":"sha512-accqzSM8RaC2vg/Lw+BAE3KJM7Kd3fwNn0EWSU/vWN16GsM/YMU1InUGOSFixfZlvacUbquqixhKNqtCcFkHLw==","signatures":[{"sig":"MEYCIQCJ2FUXZP04RcJbrqkIhHyfPUCbjUlEHDYLK7CUSfWAawIhAMXPIFu0LyMUpJnwUxFRP1DxFLGpZgL4/GW9tl2p2M/a","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.31.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2083102},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from","path":"dist/index.js","limit":"14 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes","path":"dist/default/index.js","limit":"29.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.7.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.31.0_1788596647307_0.5560091696492047","host":"s3://npm-registry-packages-npm-production"}},"0.32.0":{"name":"@stapel/search-react","version":"0.32.0","license":"MIT","_id":"@stapel/search-react@0.32.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"10905ef25bdc9c9a46498cc5487cc2f7e932c012","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.0.tgz","fileCount":316,"integrity":"sha512-VIAp66Bp3hf8/SlU7GYra9DThEtyOIa6X1/5jm9QM4oe8mUJdwr73w1TUpi+eQqkJcrjTlx926bjqKaeXL7kQg==","signatures":[{"sig":"MEQCICek4tTdj/csOBpsnNRUxgjtvnd2XzI9Fza/zJYzbDaLAiBkDaS9uraounrvtMmtSJ5nbKcxDSkAJUgpXhEXI0COnw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2203513},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with","path":"dist/default/index.js","limit":"30.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.2","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.0_1788618057029_0.18800209549054347","host":"s3://npm-registry-packages-npm-production"}},"0.32.1":{"name":"@stapel/search-react","version":"0.32.1","license":"MIT","_id":"@stapel/search-react@0.32.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"936294bcf5734f27b9179a778845e24133c744d0","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.1.tgz","fileCount":316,"integrity":"sha512-qs9kWDj/VLROOK4KAtkBkqdvmFRnupTQdOvDdWSMYGFOYBjAP3pnOlBucXKwzQJABzVVCIKk/VDHCuXEKlg84g==","signatures":[{"sig":"MEUCIAosyiwU55AjqNAns+6zqHL1Up0kAdVc3D+0vPLF/PHVAiEA4eXIIjFpJGD9SrEb62g/MP4sm5+bjpYRnsb4aiEQYBs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2214563},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with","path":"dist/default/index.js","limit":"30.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.2","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.1_1788626511959_0.9985158934549059","host":"s3://npm-registry-packages-npm-production"}},"0.32.2":{"name":"@stapel/search-react","version":"0.32.2","license":"MIT","_id":"@stapel/search-react@0.32.2","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"7bd3dc43c37f92d86fd297607c141ce4b20bcbb1","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.2.tgz","fileCount":316,"integrity":"sha512-UFXHmxZXbuwCg4uk2K3K1ZGmYNZhjuCeCWKKQlBktbgZPSVLWBhLJlXhminqEaTaK6lF/Ffx1mdHPVrRBs/V1w==","signatures":[{"sig":"MEYCIQCyqAEz02BpTVwjjtS3uxyRKycGdfBNu0r5mQlXQLX6igIhAMitF3vKJDCxokC8ckaIbNo80AMttacQm/ISC43RvzHC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2215989},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with","path":"dist/default/index.js","limit":"30.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.2","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.2_1788628600669_0.92065121140363","host":"s3://npm-registry-packages-npm-production"}},"0.32.3":{"name":"@stapel/search-react","version":"0.32.3","license":"MIT","_id":"@stapel/search-react@0.32.3","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"16022ee603beeabcc41e88e8f9e864a1c976d66c","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.3.tgz","fileCount":316,"integrity":"sha512-d7qM8xKwcV8Lig4o1Y5TxFWg7nopGrMnEFV/xwP5kG+l3qwfpAoOPz56SMdIJF39fudS1BfHkZHRu5k7kMd02A==","signatures":[{"sig":"MEYCIQDCUP3EBU6ZoGxr0XB/adjeylRyimb0MpW2z9xXA27jWAIhAPXT5+OPknpcw0JqfR9WF8aHr8bXkqtBZD3DuBLO8PIs","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2225212},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with","path":"dist/default/index.js","limit":"30.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.2","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.1","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.3_1788631808819_0.7262046427356688","host":"s3://npm-registry-packages-npm-production"}},"0.32.4":{"name":"@stapel/search-react","version":"0.32.4","license":"MIT","_id":"@stapel/search-react@0.32.4","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"556daf3e03264347d45321840e15b028c6fd21f5","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.4.tgz","fileCount":316,"integrity":"sha512-eld1zyphrPz5zAxoW+3M67ij25v900PwMTP0l2nRZ+ni0gCiSEUso9bg/jueEn0qBRsdvC7OKrU0WJXQ+unUvw==","signatures":[{"sig":"MEUCIG6ikFz2ZgxiWiBvO7fRgqSyepsjcqukJikA9qNtBNxcAiEA0DjUvGy8g8OpzEKbZVghqzpNPZukZE6JNWJGd7tBWX4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2240856},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with","path":"dist/default/index.js","limit":"30.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.2","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.4_1788646204016_0.9112876361035467","host":"s3://npm-registry-packages-npm-production"}},"0.32.5":{"name":"@stapel/search-react","version":"0.32.5","license":"MIT","_id":"@stapel/search-react@0.32.5","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"fbe0d36131e8e516da0b8e8258d5cbf377ce7529","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.5.tgz","fileCount":316,"integrity":"sha512-Ip3LBGqm+dbGIzxgRsBlPnbwMps/DVqb1YURucCek2hcZ0JfYwCprhvdtQofBFmoaGGo0ppZx1Ni2MRgaxTpAw==","signatures":[{"sig":"MEUCIEk1YU5Fm+CSOax+ttAFAnQLqIw6RcstKtAHgoUooW/bAiEAgcPFHEzAe+4LCAetWrR2sx6AwmLmAQr/LFhpF30Idx0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2257506},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back","path":"dist/default/index.js","limit":"31 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.2","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.5_1788650644140_0.561279864622565","host":"s3://npm-registry-packages-npm-production"}},"0.32.6":{"name":"@stapel/search-react","version":"0.32.6","license":"MIT","_id":"@stapel/search-react@0.32.6","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"d6763d4db87492c5833a38ba613c7d7977fbd5ee","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.6.tgz","fileCount":316,"integrity":"sha512-M1bzQTGUlqlT0O20eIEWGbiqIqcLPffr8Tm4sQo4xvgwJ/f046mwBG/k+VIraHsJRBm4O8P0O4vClrwleyOz9w==","signatures":[{"sig":"MEYCIQCOm8OceolHRJXr/87n+LlsjPWiRoshSayyL7jOYX3SmgIhAOdg7Qr9K9ifNgwd3gWiehWlDUSFiQSCBiCTbOZvIvJN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2262906},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back","path":"dist/default/index.js","limit":"31 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.3","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.6_1788653790738_0.4928997437262488","host":"s3://npm-registry-packages-npm-production"}},"0.32.7":{"name":"@stapel/search-react","version":"0.32.7","license":"MIT","_id":"@stapel/search-react@0.32.7","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"76bc0d5419ebba5a179dd3dc1f975b7a34ce6729","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.7.tgz","fileCount":316,"integrity":"sha512-z7bTuHZwVfS6xAdm+tSpo7QnNxkLciu+1PIbn+Bbn1RvqhA+kQrtZc19jNcgVL7D/P+3q6nHBfW16yY9QKW2yQ==","signatures":[{"sig":"MEUCIBW22eIbYpgGifuLk4sTFnXmjsCuW0QAithAwdM49ip+AiEAl7QHazlpRscU9C4UU+12R8xR9Sfv4iEHILsrCIARCPc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2282889},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back","path":"dist/default/index.js","limit":"31 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.4","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.7_1788668887766_0.19926743981951178","host":"s3://npm-registry-packages-npm-production"}},"0.32.8":{"name":"@stapel/search-react","version":"0.32.8","license":"MIT","_id":"@stapel/search-react@0.32.8","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"53746c7dcd955e9601d406d3497d87e8c6ab190b","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.32.8.tgz","fileCount":316,"integrity":"sha512-lvHLWlZ2Nby8XPTuHMPuQFU1FIZc6Ota/2/J2NgyIMFnKcROqJnpXn9qtK17iRudAj6SgapzB3Ng8tqX1cCUGg==","signatures":[{"sig":"MEYCIQCNeKBqPIIqC2eZbz5WKAk8pOhjhIqpoG1994QPHJ2aywIhAIIJ2losr1YftC5YQZ0SyveFnkX5O3FZki99wr7neNQG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.32.8","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2289806},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted","path":"dist/default/index.js","limit":"31.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.5","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.32.8_1788683219114_0.6868071578485653","host":"s3://npm-registry-packages-npm-production"}},"0.33.0":{"name":"@stapel/search-react","version":"0.33.0","license":"MIT","_id":"@stapel/search-react@0.33.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"b28906400f642e1fe4ac7310ca258ca089a45388","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.33.0.tgz","fileCount":316,"integrity":"sha512-tjCmw8pOniV7uIMazLxSJROiVY5EOHwvP7WQbIRtS8Rnglltzlzm2kVxvfsQ+abzuZ4q48ENf8ltAVI+BpQj2g==","signatures":[{"sig":"MEQCIHRz+4I4KeAwo0XBzBCb9f78qe5v2CAz4y5rzHwXdUohAiA3tgVAbaGEg74e9GyFc72TSjgJkQKS/H7PBqzojDz4eQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.33.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2320760},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query","path":"dist/default/index.js","limit":"31.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.5","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.33.0_1788686999779_0.4123291865160188","host":"s3://npm-registry-packages-npm-production"}},"0.33.1":{"name":"@stapel/search-react","version":"0.33.1","license":"MIT","_id":"@stapel/search-react@0.33.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"32b84cd9986da0f43260a3a952a4b1a155e3f1b5","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.33.1.tgz","fileCount":316,"integrity":"sha512-xY00ZGnh2kF66BeRD4yhxY4HnjwXuUhJyFxNiEHynvNQha27VHdxQmzSVqb9cBRUDUj13kDS7/IWqm7btrSBIg==","signatures":[{"sig":"MEUCIQCcTkRncbxpz8Rbo0cO/1XpRCeQZV3HvLMUArlXQgyvawIgH63e9l+jb3VVlEvNqkG+E+lffuwdqLrKV3K4pIqbhWs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.33.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2338971},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query","path":"dist/default/index.js","limit":"31.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.25.4","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.17.3","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.5","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.18.1 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.33.1_1788696202354_0.3297371060632903","host":"s3://npm-registry-packages-npm-production"}},"0.34.0":{"name":"@stapel/search-react","version":"0.34.0","license":"MIT","_id":"@stapel/search-react@0.34.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"68e2876c3a9f7e405ac2b3f7b8fd2497b2a20673","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.34.0.tgz","fileCount":316,"integrity":"sha512-7FuFR0HDx0wisB6b6ZTEOAHF5sX4HNTl/+lOiwRSAwI4oSi+G+8a5JhHgulZVBKuokkIrcVhFGxOECb/ajLdmw==","signatures":[{"sig":"MEUCIFFewOZJshYzQ0noqj/i5C1uugWVAzfiTLvi7j3H0/7YAiEA7n33PJRQfFCv+HrkEE/0JgKcZb22XDe+I6Ciqgxeb8c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.34.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2352739},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE","path":"dist/default/index.js","limit":"31.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.5","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.34.0_1788709654692_0.1263297780873267","host":"s3://npm-registry-packages-npm-production"}},"0.35.0":{"name":"@stapel/search-react","version":"0.35.0","license":"MIT","_id":"@stapel/search-react@0.35.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"2e5315a302a959395c2655436ebb0c5984a0b938","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.35.0.tgz","fileCount":316,"integrity":"sha512-FLk414ngoQSJwwvW/ZQhkPFVXMbO1YfXW7InjdwXtHzzB1AoSU7gd4dZuDTsN6sBwPsjCH26mkS9rFRaw4euIA==","signatures":[{"sig":"MEUCIQCdBuLvqqivjL58i70a5rwulfAUe1aNBgNclGgAK5gBDAIgIT4kwHfjRGqV0zQB6pzFl9qaCehpwpeGyTGmZbx6iw8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.35.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2384664},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B","path":"dist/default/index.js","limit":"32 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.5","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.35.0_1788719326995_0.9867761097752279","host":"s3://npm-registry-packages-npm-production"}},"0.36.0":{"name":"@stapel/search-react","version":"0.36.0","license":"MIT","_id":"@stapel/search-react@0.36.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"cbd1ca07cca52d691b15435e91da7519044b20b8","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.36.0.tgz","fileCount":316,"integrity":"sha512-E7enL2GaQTsNXtPj2CDWEVn1J6sGUXe970MfNPz8JM8yBLx+wkzk4/Wf0srjq0bsnWtIxwcBNKRhJ4u6TVSlNQ==","signatures":[{"sig":"MEQCID7XPZNNqRpa4BBFEwHds/SST0+xmbk5TnIKvTVx6s5UAiBuxNrFR7vEFUnj7mB708aKOhD0Bgt8/JWNOtagBqQhYQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.36.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2399224},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B","path":"dist/default/index.js","limit":"32.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.6","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.36.0_1788745737025_0.2948240616097513","host":"s3://npm-registry-packages-npm-production"}},"0.36.1":{"name":"@stapel/search-react","version":"0.36.1","license":"MIT","_id":"@stapel/search-react@0.36.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"8e8512830a177e48651d817e31b68912ad89eb61","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.36.1.tgz","fileCount":316,"integrity":"sha512-JhJ5S8bVHtyXTl0kOld2L1Ove0LIu2pRHz8whXdqsDxy1Qzip823V5OuOWVnt1Vjd9mFn3PIhi9dwbQMKEX4CQ==","signatures":[{"sig":"MEYCIQCiJgQlwEY98nW5LgHdcIQVwnYyVengeRmvKfCC6jAoIgIhAOzg21sSLkrCAg8nA5iMMl6pYuHgU3kldLX8Yafc7HPu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.36.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2413128},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar","path":"dist/default/index.js","limit":"32.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.6","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.36.1_1788780141878_0.40641875867221233","host":"s3://npm-registry-packages-npm-production"}},"0.37.0":{"name":"@stapel/search-react","version":"0.37.0","license":"MIT","_id":"@stapel/search-react@0.37.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"6d46ad25ebe1bdab9a3ccaa192632358dd0143a4","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.37.0.tgz","fileCount":316,"integrity":"sha512-KMkKiElEOqNMdclplbTDAa27gG4m4/SnaVhgigy0ZYtUm+HJmbIWA25XAI0uElt4mWsMoxl0+H0bKbq1ZExhSg==","signatures":[{"sig":"MEUCIASSmRdskxPrVSY/pRu5Nd/bry6IkShPzisYUugU/X8xAiEA6kfKrCFhYFQ3xyEqu87JxR008T60yHex7D2D28XvHVE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.37.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2431628},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete","path":"dist/default/index.js","limit":"32.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.0","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.16.6","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.37.0_1788814080625_0.3409564430431884","host":"s3://npm-registry-packages-npm-production"}},"0.38.0":{"name":"@stapel/search-react","version":"0.38.0","license":"MIT","_id":"@stapel/search-react@0.38.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"859ca5e4812806550dfb5c78d8ce699207a6d99d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.38.0.tgz","fileCount":316,"integrity":"sha512-oAb8wQTth5cCfxbA6tWpDee+HQ4CpDG+PuVtq95abaLqwrU29bl97nVL5e/BZyJv9yJFAX+zE/jiGYfeIj9D3Q==","signatures":[{"sig":"MEQCIHkCTGw0FKLQQxSBpH8fZd+3C69SNPPRoclfatiMh+oSAiAvE7qqeB80/ZpItJP6axJRYPHndahMbVhzHZWgkk5zSg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.38.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2457313},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has","path":"dist/default/index.js","limit":"32.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.38.0_1789036403347_0.6138727078504205","host":"s3://npm-registry-packages-npm-production"}},"0.39.0":{"name":"@stapel/search-react","version":"0.39.0","license":"MIT","_id":"@stapel/search-react@0.39.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"c7fe4c551830180f3bfb96b32954c1bef6c36584","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.39.0.tgz","fileCount":316,"integrity":"sha512-aNlrdKvm55rm3z4d9pY1fckQ95tBvpy5FWp7k3QE89fQx4tlQrj4rKiDNsYuH9v+pbg2Zcg1jN2oPr0Y7ItpxA==","signatures":[{"sig":"MEYCIQD32fx1bLqT53MNVrlLCUyHTdhTvIPj3Q9Q3VDoHvn6lAIhALX56v9vwqa4XWVtzpczx8lLtWbotFq7ukClaF4nq7GG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.39.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2475471},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B","path":"dist/default/index.js","limit":"33.25 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.39.0_1789042950872_0.6749475058604166","host":"s3://npm-registry-packages-npm-production"}},"0.40.0":{"name":"@stapel/search-react","version":"0.40.0","license":"MIT","_id":"@stapel/search-react@0.40.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"ab027ef81a4fb7414f6f87b5e655e2e96df85fc4","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.40.0.tgz","fileCount":321,"integrity":"sha512-RLGXrS/OpzUeF75XnoUiPtrHRjNM1ocQP3+lTGm0JpoYaeNdabk3AGHCsELKlTlCffEGMcipL5Adi7rBrNt5QA==","signatures":[{"sig":"MEUCIHa4xBZ0yk0CyvfUAjbd104wr/WL1S6O/DxXUpRm220lAiEAmAuINEM1Hd4o8u/vp4SszEgCtcvpgnQ1eiZwEbOk22c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIF6TLLUo3KG/YwMM3jc7YVcX6HVnrXc+XMOA/XBe28OyAiAE8brEtnzZqUQ1MmhEgaBVNRKeIQ6ahZT7+kuTW4FMIA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.40.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2547262},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has","path":"dist/default/index.js","limit":"34 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.40.0_1789090863575_0.4184573610765361","host":"s3://npm-registry-packages-npm-production"}},"0.41.0":{"name":"@stapel/search-react","version":"0.41.0","license":"MIT","_id":"@stapel/search-react@0.41.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"3223c4344db5776adb3f1070990d3b7024250355","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.41.0.tgz","fileCount":321,"integrity":"sha512-Hws3Db4kGbhz+ghNF3HpX4qc36x+hFA7rcpRriDy9E2kwvHzqQGMcpLzaTHqtG703VdS+kv05FxAmEp/nwFclQ==","signatures":[{"sig":"MEUCIQDn/r0YIyWUr/5+1dKzSme+Qdwh0fEKmtUrXct+T/YvYwIgDOyyt4SkVGD9le2sGhorxfxn5/Xzf48TKmulgVLogwo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIER0XZOl4O12IV+65gVosrTQtOh3XO1qYPyXHPw5feFLAiB9Fuj3JPOLv2hv+uz7tYmNwRACOGzuWgX1argXUFXxYA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.41.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2565722},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has","path":"dist/default/index.js","limit":"34 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.41.0_1789097421679_0.6609053100368967","host":"s3://npm-registry-packages-npm-production"}},"0.41.1":{"name":"@stapel/search-react","version":"0.41.1","license":"MIT","_id":"@stapel/search-react@0.41.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"ca167de44cbbb9ea8258c4f31a68ef39f23ba346","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.41.1.tgz","fileCount":321,"integrity":"sha512-3hd0ilzHZLUpVJLhDLel9aPj9LVA7qRU3YdfDY6Vu1HhlnBvGAQ+wZ0D+uZcysBj5d9xcS6obpeZFyjmVpUC6Q==","signatures":[{"sig":"MEYCIQD9fd4PwaMS43bmqiQHLH4Dd0mFGd7oXiAmcz+8fbhgTgIhAImaNwp60m/SCDjj2Q+AUSMkR38tse92f3gfhjzkJ3zS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDAWcPnq+50x2p0vR0PvOLuOj7zm0uZRZhPLhu9yIPgfgIhAI9jkyEHc+FmFsQsvTKlaXbqxOW5Ixj6a6KZ1Po5RR9I","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.41.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2571553},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has","path":"dist/default/index.js","limit":"34 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.41.1_1789174581838_0.08111093959242721","host":"s3://npm-registry-packages-npm-production"}},"0.41.2":{"name":"@stapel/search-react","version":"0.41.2","license":"MIT","_id":"@stapel/search-react@0.41.2","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"b13b31fa628c53bbae0baa2e56fbdeef80ce0022","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.41.2.tgz","fileCount":321,"integrity":"sha512-zYlrDwUS7+yL1nh+863+2GdUs3c5+LNwLVrnWqG6iuTO+beQXsD+3i0nEzndyYZuGDyBT4GjCF0vcdosO5dWnw==","signatures":[{"sig":"MEYCIQCbXYsEtrXOCvhi4SxarArRRoz8EH3SYKqJnOjRyXkF0gIhAPmTtogpVOnTuyS4LMJuYHKMiE+Zh74m4m5KbvoVMo5x","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIGxCELGgUDkJEBXcoWwY2z6E+LxCIQxSWCvii7XhbOFdAiA/EFoXpTpjN37wcsESQCZnS9BkPGWEugRaATRggb61zg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.41.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2581212},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has","path":"dist/default/index.js","limit":"34 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.41.2_1789181292782_0.3245822521876198","host":"s3://npm-registry-packages-npm-production"}},"0.42.0":{"name":"@stapel/search-react","version":"0.42.0","license":"MIT","_id":"@stapel/search-react@0.42.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"efcde262a0cb02b3fbf7ee400c8f2308d5823e7d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.42.0.tgz","fileCount":326,"integrity":"sha512-6YC2ZIilhUnDBcFvQb+z6rxpDEU1X1prEiFzmLrqEKDax6Vus22A05jNWXkytnt3IbDSTX/KzkHLNmBhtdacBQ==","signatures":[{"sig":"MEUCIElmwN5AXC0uxOJ3KvQS927ZL2JHeu2EY/Sw/n58iO5tAiEA8jTWkyZQEJy3GV6fwyfzqkziwAwDZBH/vi3fUl3nCX4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCICRbLD1iV6w15ElyywfN9R0/tZh/qbCtcEFaUZTaD2WkAiA88qrSkUXcOf/A+yR7Xn+L/LdXvwSLITAKWlHaewBIMg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.42.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2607956},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B","path":"dist/default/index.js","limit":"34.5 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.42.0_1789241508768_0.187169872047102","host":"s3://npm-registry-packages-npm-production"}},"0.42.1":{"name":"@stapel/search-react","version":"0.42.1","license":"MIT","_id":"@stapel/search-react@0.42.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"6a5056ee9f6c276378d23762cf3ec373de7eb5ff","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.42.1.tgz","fileCount":336,"integrity":"sha512-OMt6bZo52A6RjSb/U5J0jeK4QOkbbAwooZcCFdiWHsXMRB7PPMFWg9TGkLBgq8RLi9+rY29qc/AU/xiiEibUbQ==","signatures":[{"sig":"MEUCIQDqC3caofJmMuzHt+1mI2iQvY+OKezV6BBQC0QXkuUUQAIgUBJgchQRxV0blXncUJ56b+Vai/6y6BL33lIUKVh10XI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDq18pcgkOhotp2PJYCXmdaG+7sm2EGZ88CI24U3Jys0QIgfuusKHgOrkL3dkniT/YRjFHRBU9hqu4B3xV3f9kMYgo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.42.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2643549},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.18.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.42.1_1789248225170_0.43428742771105133","host":"s3://npm-registry-packages-npm-production"}},"0.42.2":{"name":"@stapel/search-react","version":"0.42.2","license":"MIT","_id":"@stapel/search-react@0.42.2","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"acf3133dbf6996e3040a3d7c03f9840de9ca98f4","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.42.2.tgz","fileCount":336,"integrity":"sha512-Nc0p55b7ta74gDClg/cJ2p4a1VYJGrFNmWdV5+dh7V+mHmm6OPWf3hJqP340Uqoao2ls7w3tjO3J8pF7RXPqzg==","signatures":[{"sig":"MEUCIQDYc3qioFA/LVuqQEAhSdoU0+JHmUBAREawG/0xSlKSjgIgNNUGyQ+gd72e1M1oGLCYzZsCXoHSFL3ZipdWMkGqKcI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHCVio1jLGsD2XH1U7KIBY0822MoljYR4EKII6KwflMoAiBKcLZ2ajHmcU+sHrkh41wH1xRcyVrjpuovjIy2ziEZNQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.42.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2650797},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.42.2_1789307032795_0.7949532169884026","host":"s3://npm-registry-packages-npm-production"}},"0.43.0":{"name":"@stapel/search-react","version":"0.43.0","license":"MIT","_id":"@stapel/search-react@0.43.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"d5de2b30334dec25b47ce81ada285d49cd54d5f7","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.43.0.tgz","fileCount":336,"integrity":"sha512-46QFaSIsT7qCZIvo5YqkAtZzg4jsnoptnT46BOCGtejaRmlV9IKY0T6TT4xlBXwXSlWXa5pzKBIM89xdQ0jBqg==","signatures":[{"sig":"MEYCIQDTVTsks2OdI1hE6NGdgrV2tnZ05yQ+sgm8XbAPD5tzJgIhAOYVOPmVwsfgK96wGkmrRPIhs90HjhKNW9IhYJkZ4Orx","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFyuRZ5zqdt6WCSrw5ofZfmhSzZgfWSf3AUo8HXzMokEAiEAgOiwo6+4jUHNQ5JRIYLtvvbLir9vtJjpMamE7Ct2hFE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.43.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2665109},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.43.0_1789309706627_0.04513851056932339","host":"s3://npm-registry-packages-npm-production"}},"0.44.0":{"name":"@stapel/search-react","version":"0.44.0","license":"MIT","_id":"@stapel/search-react@0.44.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"2fec57175a1ecad55fdb138c24f338546fb962b5","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.44.0.tgz","fileCount":336,"integrity":"sha512-Ndj4HgYOiEoRrg79bvssBli4BGV2EHdlkyYXXYQs/tjhjDDO+w1tpSlEIpCEaBbayq7D5jtQHsSYEmZ8kY5Gdw==","signatures":[{"sig":"MEYCIQCpilyhx1g8GjBtm/FZpC6PMBWeKQlVMG7C3R7k6IckZQIhAP4xgp9ggNhS+ZCL+nUnajLHpkRLgyU6rP7stkcchqbd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQD9pYY2P2kDqqa35AyEpVBTzqgVKLJwheXXY70pvXq+9gIgAMqPxi+XF6dSsUKl3x+bQX2Gtr56DXdc4jrO4MZmlG8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.44.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2679034},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.44.0_1789311022561_0.6083818611214473","host":"s3://npm-registry-packages-npm-production"}},"0.45.0":{"name":"@stapel/search-react","version":"0.45.0","license":"MIT","_id":"@stapel/search-react@0.45.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"2334b0ae0a66c00fea95752909836416a28eb0c9","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.45.0.tgz","fileCount":336,"integrity":"sha512-CSrb+vtym8mjY0IYoFaIr4OtYDr36j+x2vDEmDNumEQdk35OoHhPZgfO/x6gbiMl62gXjCohBvxGHBSFdHiE8g==","signatures":[{"sig":"MEUCIAGYIMO8MF59QGpd67rosv4/cExQ3/0i21gLGQ1pMuxsAiEA5S15oSeCEVIYhGOJ7Mb/AyOdco/hJ/kmcLCgubPQozI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDzfa0c7PyWy2CrMu6XVZhdMKK/aHZZ/YEeJyAVgpD4DAIhAOkHasgsQ2aRwiIF8mhN+IxLDytcmK30bjzNv7pamfZh","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.45.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2681795},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.45.0_1789313872598_0.16459352110633696","host":"s3://npm-registry-packages-npm-production"}},"0.46.0":{"name":"@stapel/search-react","version":"0.46.0","license":"MIT","_id":"@stapel/search-react@0.46.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"13195a934e53727e67f9e73023326ef469eab7ce","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.46.0.tgz","fileCount":336,"integrity":"sha512-iDj2f3JY5/4+v0sFae+Qn21s3b5ucgyQJQP9gbG6ROIxTN0qeqkb9DwI9HP8GsXu87VFIGdudjPLsdhPYJYzEA==","signatures":[{"sig":"MEYCIQCciyE5c+oLWOHjnHXz/fPZEZvvdV4dUO1055S0Itha3wIhAPqSvdZSA0zWPltR02IF1xWu+onqHtzIabWlBuZaLqQt","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCLUy2z8Q8H8EIEXM2qeiUxJAvUNtMq0yRThFfQrKM2cwIgKnoyLZK8bE07UM+dmByEEU1/Ak09E2nNhF0NsmBNc6s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.46.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2694799},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that","path":"dist/index.js","limit":"14.5 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make","path":"dist/default/index.js","limit":"34.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.46.0_1789319775208_0.4565493134634009","host":"s3://npm-registry-packages-npm-production"}},"0.47.0":{"name":"@stapel/search-react","version":"0.47.0","license":"MIT","_id":"@stapel/search-react@0.47.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"8316f10e7f24011121dea9b1f0d1bc427babfa20","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.47.0.tgz","fileCount":336,"integrity":"sha512-TGOml11HJbqyDOV6nxKniGrUTVvw8KGwVlKSKlw9/rLdLns7RR1/mqRO8H6PVY+tqyniAZlXUbcBfZCGF649IQ==","signatures":[{"sig":"MEUCIQCKBybvZiFPtNDjeaX1j7dOmN4PTf1+ut3bKBdHNYzkagIgcFmX2HSmZUOxa3SGVbTIi5sHNTYpTDgUuTIiG3uAIUg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAo2e1V1/Q+7le+xzIHhJbCEGCZGW66UN69E4zPmEl9lAiEA73jLQlbjlOeNXxgm4EgcE4cTzKtXalvYl82+s4e0n7A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.47.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2726997},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it.","path":"dist/default/index.js","limit":"35 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.47.0_1789324243875_0.5895367213886078","host":"s3://npm-registry-packages-npm-production"}},"0.47.1":{"name":"@stapel/search-react","version":"0.47.1","license":"MIT","_id":"@stapel/search-react@0.47.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"9a15238e21eddc161e6a91f007207a27eed62ea0","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.47.1.tgz","fileCount":336,"integrity":"sha512-nGNAJ0u+XPQPPPXGCPAoNFe78HdYYSqcblNiv35hPQ6W7TMy0sg/V3PAd2XnzeCOOadY5lrzLY33OBuc+MEQhQ==","signatures":[{"sig":"MEYCIQC5FurpGDw2IQFmEM530YvJ5L2r8ozHw/PS0v1tThi0HgIhAJc9vEcE+P0dJpMxJ5FWX3z1gVfGVsm9cyyrajZoC2fv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIFpaIrMeJfWoRTCOQM0ynK1qRoE0SeFK+A1yEufmh1KmAiBMHjjoNHmqKcCFAuIMnYxkdXxpv7ZTmmpr/rLlBaZzvw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.47.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2733134},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it.","path":"dist/default/index.js","limit":"35 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.47.1_1789325811341_0.1968944758081712","host":"s3://npm-registry-packages-npm-production"}},"0.48.0":{"name":"@stapel/search-react","version":"0.48.0","license":"MIT","_id":"@stapel/search-react@0.48.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"082f6b6834935033f4b53f3e6527735a73f20f11","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.48.0.tgz","fileCount":336,"integrity":"sha512-/0GudduAI5ve6x1LnyKT7ePq21u51i2GHSKt5h7VoPDwi6FZLheX4lLZzmeG2GTE3Z0V7ugKFWu7jdE2dgTqxg==","signatures":[{"sig":"MEYCIQCjgw19nZHgEpxhBFrgn+HmDTI+z5Wa1lawBBNOX8z10AIhAKDPPk6oB6PM9DSRjxuC569QbvLz6kQ5jn2cpNdz9zez","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCT9qUudmsESHhs0LtK3LdmjhzcwwlfZsltThsCEYL+WQIhAP5LoF+6mQauPHTKJX+nJ2S0jUxm6AvtqYUV2RGpQSl6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.48.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2760862},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.19.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.48.0_1789332465646_0.342437631407543","host":"s3://npm-registry-packages-npm-production"}},"0.48.1":{"name":"@stapel/search-react","version":"0.48.1","license":"MIT","_id":"@stapel/search-react@0.48.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"a148e8a6f5614b38e8c39792c72ed5f0a2fbdaf3","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.48.1.tgz","fileCount":336,"integrity":"sha512-ewl5btyLbd2kImXP5YCYja4FRT/4KBPm7Gn7U4ZgpaK9pQ0lETFaDaDTbw6+La79EoAW4TeM7I1C1tCgbdlybw==","signatures":[{"sig":"MEUCIH6mRMamgRGtvqNE7juTH2gwtDMm2jayccb5LWecLyh/AiEAwAaUB3r/VKYxZBYVY30Y5hMLK10xVl008sjzyEsuxgk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDEY4Si3/Xjfx5TTwHeh4H+P69dyE+bNEEl8HCSl0OV8AIgBww+2KvVHXp2d0okRwdRGD4ymUpj8j8UTXw9FzxvesM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.48.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2764473},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.48.1_1789380769807_0.7665306740911766","host":"s3://npm-registry-packages-npm-production"}},"0.49.0":{"name":"@stapel/search-react","version":"0.49.0","license":"MIT","_id":"@stapel/search-react@0.49.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"7df34681d1b40842f5ccff2826a49041192120f9","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.49.0.tgz","fileCount":336,"integrity":"sha512-FIs03XOEKzJbJf8givBzWMqbzPGhzmjjiJtEX4s9fvb5Jje8Rhtl9mJTRvMeMILwky9bQqwHYgrMjnsdkd9KOQ==","signatures":[{"sig":"MEYCIQColDH+gZyejRJgcq+z6T64zEDHaVQhnIpfSby3egLjNAIhAL1Zs0tyLlAtV/6fznH3b1Lj1YpPFEVktOD70NpcpKWF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIDbrPh4vXrxvm03AActdTzihyt1r5cHrbEfm6LkvOwYwAiEAuy2aI4cREsqHNSdkoctgcTzAy2siMhRuPxS4Z+9J1l0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.49.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2770967},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.49.0_1789405039438_0.4232763207956236","host":"s3://npm-registry-packages-npm-production"}},"0.49.1":{"name":"@stapel/search-react","version":"0.49.1","license":"MIT","_id":"@stapel/search-react@0.49.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"bf0bacb924c39e29e63188f9d53aaabe5ee6397a","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.49.1.tgz","fileCount":336,"integrity":"sha512-iPqylvi2MlNCfXa+Ro1J5vn+O2jd+vVG/9ERAP8CzL8Kt6A0oQsyvltkHKWQ9+KhHUhSDaC3DZa6AwFrlMRuuQ==","signatures":[{"sig":"MEUCIQC9AeIvkthJfz/yen/xwCM6RMPx3FvLHcmGdQwj7nthYAIgZByw0vdEB9aHnVh3FwUPjrrNjdfqZzYReza4n+gs9Mk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIDPm5b0flCNbPSz7N9NFit65tx9V/QBoxWJCcYos2cLrAiBAb+zQllb7Dt8pU0/c/fs5zEtQ7Yj/YAWVs6dbTNG6Sw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.49.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2774239},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.49.1_1789407105472_0.14554999188281958","host":"s3://npm-registry-packages-npm-production"}},"0.49.2":{"name":"@stapel/search-react","version":"0.49.2","license":"MIT","_id":"@stapel/search-react@0.49.2","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"aedc8d52835b1bab8e7d8bdd0f69247097c6c0b7","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.49.2.tgz","fileCount":336,"integrity":"sha512-t6lz2t/d0krkM3JR9ukRkYr1yCD4hx7Tt/3ZaQcXDnhjJWP9yqCmRrsMoMYkm6JUdR6tcuIvCQ62nzqcCv/Egw==","signatures":[{"sig":"MEQCIQD/fqPQMD4pNj3xzssSLd8hAewrX0kq7epzTxPbLgfPEgIfI356VGIrYpx+Svb16fyq9qXBko6KjdM1bsLFADnwVQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDoMPbXO/W9+RXUTeiz82P/NopSJqWh7RuqC8BMUIpVZwIgDtLatm8b9fnugndVLOZFAC/PtNajaKYKPqywSsN+Pc8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.49.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2779619},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.0","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.0","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.49.2_1789412310736_0.5842630394251989","host":"s3://npm-registry-packages-npm-production"}},"0.50.0":{"name":"@stapel/search-react","version":"0.50.0","license":"MIT","_id":"@stapel/search-react@0.50.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"836f83a18da3c228f09e5c1398de800e8f919aa5","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.50.0.tgz","fileCount":336,"integrity":"sha512-qu6zTWbL5OQXyZZV0s4PGvJtn5gcybYEIogGIMdlqq67E2meuGMwCL5TG39xKwZtbCMYD8Ul2VhcBN294fYanw==","signatures":[{"sig":"MEYCIQCldj2lgeUkOuvkLuk9rwH5dYUSCZ13XPPM4mVGR4/vVwIhANpaQrGdSjX6Z7PVpUYnM66YZie+3B1uhXthNyUbO6I7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDo/17hfWkRIvAYqOaL2LiY4nihrn4q94Dp6FgEfM6gewIhAIgeLrya6iCbEkYLqb3ak63v2xAV4GNXnFXFbBRvJYbu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.50.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2786012},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.50.0_1789415139749_0.9484690431600891","host":"s3://npm-registry-packages-npm-production"}},"0.50.1":{"name":"@stapel/search-react","version":"0.50.1","license":"MIT","_id":"@stapel/search-react@0.50.1","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"9e1181e72efd6247c6148195ddda2e3117df286d","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.50.1.tgz","fileCount":336,"integrity":"sha512-PFOhhTz4nYcjjoFkEin/ejyVUi8K5X1wqrcMS3yGtLr7nMsXQxVckOFwKDq84F2ghC99jTKGx6IpK81fpt6OAQ==","signatures":[{"sig":"MEYCIQCGETE3UhsBAjk8XeAg7EsfgfuPF/wj2qkakHiMX9bcVQIhAJZJLRARipn/f3qkqKUI7n3KUdagjkr50/eTXZ6cJwAv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBUXowIwjdJ6hxng+fiHCuOsr19xKars7hsibHwkm/03AiA2mDs92ScfRkLq/EiWIW0gvKufgOrRoRsmgbG9rQvoyg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.50.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2787943},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever.","path":"dist/index.js","limit":"14.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B.","path":"dist/default/index.js","limit":"35.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.50.1_1789517690335_0.6606975035709863","host":"s3://npm-registry-packages-npm-production"}},"0.52.0":{"name":"@stapel/search-react","version":"0.52.0","license":"MIT","_id":"@stapel/search-react@0.52.0","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"dist":{"shasum":"856ed72a0a91f662bdec62d1609306cb298c1ff2","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.52.0.tgz","fileCount":341,"integrity":"sha512-RqayuFMVJLPPgHFnND+J90QY5/xeKwr31//04QSOV9Ak8HKHPjd+YDkrFrR0BCxofq5y18RyiPAkMJFO5BNLHg==","signatures":[{"sig":"MEYCIQDCVymSk7En6Z6TgQ8QZspMP8KoUWzVz9pD/7/b+twIOgIhALUPyygXJYAQTct+0tOuogp+PSpFr97KZSW+fjT7sjam","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDRIU8fRRSD44wLDxbJWO5PsN38L/hmcev3gcleseKQ7AIhAKQXbPXFl+vtSClz0AjZPbo+9JATNxEGmvLoLBmRneQD","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.52.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2869378},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever. 14.75 -> 15.75 KB for STAGED DEPENDENT FACETS, which is the same rule said by the side that can always say it. Measured with dependencies held constant, this package's src before this change and then at it: 14704 -> 15391 B — 687 B, and the old line had 46 B of room left; the new line leaves 359. The wire fields (`depends_on`/`gated`/`parent_missing`, `facet_meta.dependent_facets`) are carried onto the group, `applyDependentFacets` decides WHICH rule holds — the answer's, the schema's, or none — and `useDependentFacets` publishes one fact per group plus the reducer rule a parent change owes its children. Most of the weight is that reducer: `dependentFacetSlugs` walks the chain transitively (make -> model -> generation; clearing the make while a generation stands is the same wrong answer one rung down) and `clearDependentFilters` drops both spellings of each key, because the address may carry the answer's short `url_key` while the groups are keyed by slug. It lives in the MODEL for the reason the schema-derived rule does: four surfaces draw these axes and a rule applied in one control is a rule the other three disagree with.","path":"dist/index.js","limit":"15.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B. 35.75 -> 36.75 KB for the GATED group and the deep link. Measured with dependencies held constant, this package's src before this change and then at it: 35541 -> 36329 B — 788 B, and the old line had 209 B of room left; the new line leaves 421. A group the answer is holding shut renders collapsed and inert — disabled header, no focus stop, no options, no count — with the hint naming its parent drawn whether the group is open or not, which is the half the schema-derived rule never needed because it never closed anything. Its opener chip is disabled rather than opening a sheet with nothing in it, and the group REMOUNTS when it un-gates so the axis the reader has just unlocked comes back open instead of as a header they must press. The other half is the deep link: a group that arrived filtered without its parent keeps its selection and forces the PARENT group open beside it, so the reader can see what their selection is a child of.","path":"dist/default/index.js","limit":"36.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/search-react_0.52.0_1789697458314_0.16483001726936974","host":"s3://npm-registry-packages-npm-production"}},"0.52.1":{"_id":"@stapel/search-react@0.52.1","dist":{"shasum":"b07a3e3ad79b4828d366d655f0cf852c05e6a8d3","tarball":"https://registry.npmjs.org/@stapel/search-react/-/search-react-0.52.1.tgz","fileCount":341,"integrity":"sha512-0TAHBNJu93CCPxm1O1ual2qMVt6yogas2MVIrsH+AkdehJhuJ045ZxIy1uqcnu33/LQaB7iGNGBdwul/zsYfUQ==","signatures":[{"sig":"MEQCIEFKRsTnsGBKuaoYoTGLTCPT3/90wtP9iigWDv3HVbl4AiARm2d7mS6FiepSQyM8/aDkQiKvfpgUlIXGqf9h7svnJA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCyCJxmnI/l28jWus4v/m+wNBOZIMtGScBt9OvN794mxQIgBpM/IRt+x/t1bcSGastCoEJhdy32uDJFPqPyAhEo08k="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@stapel%2fsearch-react@0.52.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2870665},"main":"./dist/index.js","name":"@stapel/search-react","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./router":{"types":"./dist/router/index.d.ts","default":"./dist/router/index.js"},"./default":{"types":"./dist/default/index.d.ts","default":"./dist/default/index.js"},"./i18n/es":{"types":"./dist/i18n/es.d.ts","default":"./dist/i18n/es.js"},"./i18n/ru":{"types":"./dist/i18n/ru.d.ts","default":"./dist/i18n/ru.js"},"./llms.txt":"./llms.txt","./manifest":"./manifest.json","./package.json":"./package.json","./manifest.json":"./manifest.json","./nav-manifest.json":"./nav-manifest.json"},"license":"MIT","scripts":{"lint":"eslint .","size":"size-limit","test":"tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts","build":"tsc -p tsconfig.json","test:pack":"vitest run test/prodBundlePurity.test.ts"},"version":"0.52.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:bfa27d74-9d0e-495e-81c9-7cc6cc16a81e"}},"repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"size-limit":[{"name":"index — the headless pair (client + hooks + URL codec + facet model incl. the facetability rule, the label-source order, the across-alphabets prefix matcher, the SCHEMA-order comparator that puts a category's required axes first and the bounded-integer picker list): no antd, no react-router. Raised 12 → 12.5 KB for the rail-order comparator, the shared drawability predicate (one rule for the rail and the chip row) and the picker bounds. Raised 12.5 → 13 KB for `useOtherCategories`, which reads the sections an answer is made of out of `facet_meta.categories` — the read that replaced a storefront's second request, then 13 → 13.5 KB for the SHORT FEATURE KEYS: the two-direction `url_key` map (built with the server's own collision rules, so an ambiguous short form keeps the slug on both sides), its publication seam from the answer up to the state provider, and the vocabulary-backed predicate the drawability rule and the dictionary shape now share, then 13.5 → 13.75 KB for the documented history policy (`DEFAULT_HISTORY_MODE`, one push/replace table every mutator follows instead of an ad hoc boolean per call) and the codec omitting `type`/`sort`/`limit` from the address when they equal the default a host declared, then 13.75 → 14 KB for the MEASURED range axes: `facet_meta.ranges` on the envelope, the bounds/picker rule that prefers what an answer measured over what a catalogue declares (and draws a row for a vocabulary-backed numeric axis the schema types as a choice), and the per-category axis memory the rail reserves its box from, then 14 → 14.5 KB for ONE PANEL and the named axis: a RangeAxis carrying its own label/unit/order instead of two bare numbers, the withheld rows that say which axis was dropped and why, `orderPanelItems` merging groups and ranges into a single sequence, and `setRanges` committing a whole panel in one state change. Measured with dependencies held constant, this package's src at the commit before that work and then at it: 13.95 -> 14.28 KB. 330 B is what it costs to stop drawing `kilometrage` as a heading over a picker — an axis nobody named is now dropped rather than captioned from its slug, and the model has to carry the name to know that 14.5 -> 14.75 KB for THE CHAIN, which is a rule and not a control: `facetParentSlug` / `resolveFacetParents` read the catalogue's own `optionsRef.parentFeature` off each group's feature and stamp `FacetGroup.awaitingParent` (the parent's slug and its heading) on any axis whose parent carries no value. It lives in the MODEL and not in the rail because three surfaces draw these axes — the desktop rail, the phone filter sheet and the popular-values band — and a fourth one will; a rule applied in the control is a rule the other two disagree with, which is how a model could be picked with no make and the press led to an empty feed (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 14481 -> 14599 B — 118 B, 99 of them over the old line, and a ceiling that fails on 99 B of a shipped defect fix is a gate proving nothing. The asymmetry it inherits from the composer's own predicate is part of the weight: a pointer naming an axis this page does not have gates NOTHING, because a control switched off by a slug nobody can answer is switched off forever. 14.75 -> 15.75 KB for STAGED DEPENDENT FACETS, which is the same rule said by the side that can always say it. Measured with dependencies held constant, this package's src before this change and then at it: 14704 -> 15391 B — 687 B, and the old line had 46 B of room left; the new line leaves 359. The wire fields (`depends_on`/`gated`/`parent_missing`, `facet_meta.dependent_facets`) are carried onto the group, `applyDependentFacets` decides WHICH rule holds — the answer's, the schema's, or none — and `useDependentFacets` publishes one fact per group plus the reducer rule a parent change owes its children. Most of the weight is that reducer: `dependentFacetSlugs` walks the chain transitively (make -> model -> generation; clearing the make while a generation stands is the same wrong answer one rung down) and `clearDependentFilters` drops both spellings of each key, because the address may carry the answer's short `url_key` while the groups are keyed by slug. It lives in the MODEL for the reason the schema-derived rule does: four surfaces draw these axes and a rule applied in one control is a rule the other three disagree with.","path":"dist/index.js","limit":"15.75 KB"},{"name":"default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted, then 31.25 -> 31.5 KB for the two PINNING seams: `<SearchPage railTop>` (the rail's sticky offset and its height cap moved together, so a rail under a 64px header still ends at the foot of the window) and `<SearchResultsPane stickyToolbar>` with the toolbar's own element in both header shapes. Measured with dependencies held constant, this package's src before and after: 31.05 -> 31.2 KB — 150 B, and what it replaces in one deployment is an `!important` over the pair's own inline geometry, a `:has()`, a `display: contents` and this pair's rail breakpoint restated in the host's media query, then 31.5 -> 31.75 KB for the rail saying when its answer is IN FLIGHT: `FacetPanelBag.refreshing` off `loadStateFromQuery(…, { keepPrevious })`, `data-facets-refreshing` on the rail, and each facet group standing on its own last measured height (a `min-block-size` floor held in a ref) until the new answer lands. Measured with dependencies held constant, this package's src before and after: 31.43 -> 31.51 KB — 80 B, against 0.0586 CLS on a partition press (p43), where the groups survive and RESIZE, then 31.75 -> 32 KB for the FIRST MOUNT, which had none of that: `refreshing` is never true on a cold load, so nothing above reached the one pass a plain load is made of. Three parts. `<SearchPage categoryFeaturesPending>` / `<FacetPanelPane categoryFeaturesPending>` is the third state `categoryFeatures` never had — undefined means both \"no schema\" and \"not yet\", and on a category leaf the schema is a SECOND read, so the panel drew the rail from the answer alone and then drew it again when the schema landed: on the live cars leaf make and model went from three-row checkbox lists to one-row dictionary fields, condition and colour from checkboxes to pills, and `orderFacetGroupsBySchema` reordered all of them (p41, 0.0586 CLS on a plain load of `/c/transport-avtomobili`, make -152px and model -76px). Told the schema is coming, the panel keeps the box it already reserves and draws the rail ONCE. Second, every group now stands on a DECLARED box from the frame it mounts in (`facetGroupReservedHeight` — heading, rows and fold per shape), with its measured height preferred only while an answer is in flight. Third, `<SearchPage filtersHeaderReserve>` puts the host's own band above the rail in flow from the first frame, for the partition row that is two chained catalogue reads behind the answer. Measured with dependencies held constant, this package's src before and after: 30.77 -> 31.14 KB — 366 B, then 32 -> 32.25 KB for the filter sheet's open state becoming the HOST's: `<SearchPage filtersOpen>` / `onFiltersOpenChange(open, reason)` as React's usual controlled pair, and `filtersHeader` accepting a function handed `{ closeFilters, open }`. What it costs is the four call sites naming WHY the sheet moved (`open`, `apply`, `dismiss`, `consumer`) and the slot's function arm; what it buys is a header whose own control NAVIGATES being able to take the sheet down on the same press — the page published only `defaultFiltersOpen`, so a partition chip inside the sheet left the drawer standing over the page it had just opened. Measured with dependencies held constant, this package's src before and after: 31.14 -> 31.26 KB — 120 B, then 32.25 -> 32.5 KB for the two levers a storefront could not reach: `<SearchPage footerBar>` (the rail's footer bar writes its own `display` inline, so a consumer stylesheet could only suppress it with an `!important` its own gate forbids, and this page hard-coded the column's value) and `PartitionChild.count`, which the chip draws itself in the muted weight the facet rows use instead of a host welding the number onto the name. Measured with dependencies held constant, this package's src before and after: 32.01 -> 32.10 KB — 90 B, against a string-joining hack and an unreachable bar, then 32.5 -> 32.75 KB for THE THREE BOXES A STOREFRONT WAS HOLDING FOR THIS PAIR. The phone chip row's reserve is `chipRowMinHeight(token.controlHeight)` instead of a `44 + …` constant: the touch floor raises the chips to 44 only BELOW the tablet breakpoint, so from 768px up the reserve stood 12px taller than the 40px row and the results pane ROSE when the row landed (0.0725 CLS on a category leaf at 768, against 0.00016 at 390). `<SortSelect compact>` reserves the width of the longest label it can display, measured by the browser through an `aria-hidden` sizer stacked with the select in one grid cell, instead of `minWidth: 0` inline and a control that GREW 115px when the answer named the sort. And `<SearchResultsPane>` names its own root (`data-testid=\"search-results-pane\"`) and takes `reserve` — `<SearchPage resultsReserve>` — for the box the feed arrives into, which a host was holding with `#search-page > :last-child`. Measured with dependencies held constant, this package's src before and after: 32.10 -> 32.25 KB — 150 B, against a hand-guessed height, a sibling-count selector and two stylesheet rules a consumer can now delete. 32.75 KB HOLDS for the rail's own scrollbar and the block rhythm (owner's walk of the storefront, dark theme): measured 32539 B against the 32.75 KB line, 290 B over the 32249 B this note last recorded, and 211 B of room left. The rail stays its own scroll container — filters that stay put while the results move under them is the whole point of it — and `railScrollbar` names whose BAR draws in the gutter: `\"styled\"` (the new default) is a hoisted rule set in both vendor forms, a 6px track with no arrows and no track fill and a thumb that is transparent at rest and arrives from the tokens on hover or focus-within, standing always under `(pointer: coarse)` where neither fires; `\"system\"` hands the port back to the platform and mounts no sheet at all. The system bar was never a decision, which is why the default is the new arm. The rest is `blockRhythm`: one gap for every block on this page from `var(--stapel-block-gap)` / `var(--stapel-block-gap-compact)` with each block's outer margin reset, in place of the flat `spacing[4]` the root `<Flex>` wrote inline. A budget is not raised for a change that fits under the line it already has. 32.75 -> 33.25 KB for THE POINTER THAT WAS A PARTITION CHIP (owner's read of the stand at 0.38.0). Measured with dependencies held constant, this package's src before this change and then at it: 32539 -> 32779 B — 240 B, 29 of them over the old line, and a ceiling that fails on 29 B of a shipped defect fix is a gate proving nothing. `PartitionChild.linked`/`href` and `<PartitionChips linkedChildren>` split the row's items ONCE, above everything that reads them: the cells, the roving stop, the value lookup and the arrow keys see only the SECTIONS, so a pointer cannot be a radio, cannot carry a count and cannot be the chosen partition — the live row read `All | New 0 | Used 3 | Car rental 0`, where the last zero counted a category that is not a section of this template at all. The rest is the pointer's own chip: an outlined pill that is a real `<a href>` to the target, its inline arrow glyph (drawn here, like every other glyph in this skin — this package ships no icon set), and the row that carries them OUTSIDE the radiogroup, because a `role=\"radiogroup\"` containing a link announces a choice with an option nobody can choose. 33.25 KB leaves 471 B, then 33.25 -> 34 KB for THE TWO THINGS THE CLOSING-WAVE CENSUS FOUND ON THE FEED AND THE RAIL. Measured with dependencies held constant, this package's src before this change and then at it: 32779 -> 33584 B — 805 B, 334 of them over the old line. First, `<SearchPage toolbarSticky>` (default `true`): the results toolbar pins itself at `railTop` — the same edge the filter rail already clears, so there is no second number to keep in step — through a hoisted `@media (pointer: fine)` rule set, because the pin has to be gated on a pointer and a media query cannot be written in a `style` attribute. `stickyToolbar` shipped a release ago and no deployment turned it on, which is a feature nobody has; the reference pins its sort bar once a reader has scrolled into the results (REPORT §24, Surface 2) and this page now does too, on a desktop only — a pinned bar over a 390px viewport spends the fold on chrome. The row also states its own box from the first frame (`toolbarRowMinHeight(token.controlHeight)`, the discipline `chipRowMinHeight` is written under), so its height cannot change around the moment the rule engages. Second, the colour SWATCH: a facet whose axis is a colour (`isColorAxis` — the slug's head, the address key beside it, and `axis_role` the day the canon grows a colour one) draws a filled dot beside every value whose code it can resolve to an actual colour (`swatchColor` — a design-system colour role first, then CSS's own keyword vocabulary, then a hex code a catalogue spelled out itself), and NOTHING beside the rest. Most of the weight is that keyword list, and it is the whole point of the feature: it is the vocabulary in which \"this code names a colour\" is a fact rather than a guess, and without it the only alternatives are a hue table invented for one catalogue's transliterations or a grey placeholder saying every value is the same colour. 34 KB leaves 416 B. 34 KB HOLDS for the owner's tidiness probe on the stand (dark theme): measured 33661 B against the 34 KB line, 77 B over the 33584 B this note last recorded, and 339 B of room left. Three fills, all of them this pair drawing something the page had already decided. `<SearchPage railSurface>` / `<FacetPanelPane railSurface>` (default `\"flat\"`, `\"panel\"` restores the old arm): the filter panel's body painted the raised container ground and read as a 270 x 1539 filled slab with no radius and no border, standing on the page ground for the whole height of the feed — flat draws the controls and only the text colour a bare surface drops (`var(--stapel-text)`), the same answer `categories-react` gave for its grid, strip and breadcrumbs. The rail's footer bar stopped choosing a colour: it painted antd's `colorBgContainer` in both arms, and now paints the panel's OWN token and only in the pinned arm, which is the one with a scroll port under it — the static arm paints nothing and keeps its hairline. And `resultsHeader`'s wrapper is `display: contents`: it was mounted on the PROP rather than on what the prop rendered, so a host whose header said nothing still put a 1392 x 0 element in the block-rhythm column, which is charged a gap on BOTH sides — 64px between two real blocks where 32 is declared, on every feed page, plus a `:empty` stand-in rule in the consumer's stylesheet that can now be deleted. A budget is not raised for a change that fits under the line it already has, then 34 -> 34.5 KB for THE RAIL THAT SCROLLS WITH THE PAGE (`railScroll`, a founder's ruling on a client storefront). Measured with dependencies held constant, this package's src before this change and then at it: 33661 -> 34193 B — 532 B, 193 of them over the old line. The rail has been its own scroll container since it became sticky and stays one by default; `railScroll=\"page\"` is the other answer, for a surface whose owner reads a second scrollbar standing beside the results as a second page: no `overflow-y`, no height cap, no gutter, no `overscroll-behavior`, and no bar to dress a port that is not there. The weight is the half that is NOT a deletion, because `\"page\"` is not \"sticky off\": a rail SHORTER than the room under the host's chrome still pins at `railTop`, and only a rail taller than the window goes static — a stuck box that tall is cut off at the foot of the screen, and the page scroll, now the only scroll on the surface, cannot reach its last controls. Which of the two a leaf gets is MEASURED and not guessed from a breakpoint (`useRailFits`: the rail's own height against `window.innerHeight` minus the offset it carries as `scroll-margin-top`, an observer for the element and a listener for the window, and zero refused as a measurement), because the same catalogue draws four facet groups on one section and twenty on the next. 34.5 KB leaves 307 B, then 34.5 -> 34.75 KB for THE THREE THINGS THE OWNER READ AS BROKEN ON A CLIENT STOREFRONT'S CARS LEAF. Measured with dependencies held constant, this package's src before this change and then at it: 34193 -> 34490 B — 297 B, and the old line had 10 B of room left, which is a ceiling that would fail CI on rounding rather than on weight. First, the dictionary's VALUES BOX is a scroll port and was drawing the platform's bar over the row's last column — the count sat under a grey strip. The rail's own scrollbar rule set moves to `./scrollbar.ts` and both ports mount the one hoisted sheet: `scrollbar-gutter: stable` plus a 6px token hairline, the row's count carrying the same measure as padding for the engines that ignore the gutter, and the list opening one step of the scale below the box that filters it. Second, `./focusRing.ts`: the facet controls stamp `data-pointer-focus` on a pointer press and clear it on the first key or on blur, and one rule turns the ring off while that stamp is on. `:focus-visible` was already the only thing drawing it — it is a heuristic, and it fires for a click on a control whose own list has just changed under it, which is every disclosure toggle in the rail. Third, `<PopularValues>` sizes its columns to their words (`inline-size: fit-content`, a scale gap, four columns at most) instead of dividing the whole results pane into three, which printed a make, 300px of nothing, and the next make 34.75 -> 35 KB for THE THREE THINGS THE FOUNDER READ ON THE LIVE SITE (2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34490 -> 34832 B — 342 B, 82 of them over the old line. First, the rail's dictionary axis is the BOX and its values, not a select-shaped field reading «Any» that has to be pressed first: `<SearchPage>`'s per-layout default is `\"inline\"` on a desktop now, the reference puts no press there, and the objection the field was introduced for — a 418-value vocabulary held open in a 280px column — is answered by the fold the inline body already has. The `\"field\"` arm stays for a host that asks for it by name, which is why this is not a deletion. Second, the switched-off rung: a group whose parent is unanswered draws its heading, a disabled box and a sentence NAMING the axis to use first, and its option rows are drawn `disabled` rather than removed — a rail is a map of what a category can be narrowed by, and an axis that vanishes and reappears as you choose is a rail that moves under the reader. `<PopularValues>` refuses the same axis for the same reason and says so. Third, `<PopularValues>`' «all of it» link moved into the caption's own row: it was under the columns, which on a four-column block of twelve makes is three rows below the only words that say what the block is, and two reviewers missed it. 35 -> 35.75 KB for THE BAND'S HEADING BECOMING A PAIR OF TABS (founder's read of the live site, 2026-09-13). Measured with dependencies held constant, this package's src before this change and then at it: 34814 -> 35334 B — 520 B, 334 of them over the old line. What was there: a caption naming the axis with an «all of it» link beside it, where pressing the link swapped the block for the host's full list AND took the caption and the link with it — so there was no way back to the busiest dozen at all, and the reference draws the same control as two tabs that both stay on screen. `<PopularValuesTabs>` is that control and it is exported on its own, because the swap is the HOST's (the expanded list is the host's block) and the tabs have to stand over both halves or the way back is gone again on the other one. The weight is the half that is not colour: a real `tablist` — one tab stop, a roving `tabIndex`, `aria-selected` as the state, the four keys a tablist answers with selection following focus, and the values box named as the panel the selected tab controls. Two buttons that recolour each other are, to a screen reader, two unrelated buttons: nothing says they are alternatives and nothing says which is in force, which is the whole reason the roles are not decoration. The first tab's LABEL is a prop and not a build: the catalogue declares a category `name` and no plural, case or gender, and on this fleet's own tree those names include bare imperatives and bare adjectives with no noun at all. 35.75 KB leaves 416 B. 35.75 -> 36.75 KB for the GATED group and the deep link. Measured with dependencies held constant, this package's src before this change and then at it: 35541 -> 36329 B — 788 B, and the old line had 209 B of room left; the new line leaves 421. A group the answer is holding shut renders collapsed and inert — disabled header, no focus stop, no options, no count — with the hint naming its parent drawn whether the group is open or not, which is the half the schema-derived rule never needed because it never closed anything. Its opener chip is disabled rather than opening a sheet with nothing in it, and the group REMOUNTS when it un-gates so the axis the reader has just unlocked comes back open instead of as a header they must press. The other half is the deep link: a group that arrived filtered without its parent keeps its selection and forces the PARENT group open beside it, so the reader can see what their selection is a child of.","path":"dist/default/index.js","limit":"36.75 KB"},{"name":"router — the react-router binding is opt-in; the main entry must never pull a router","path":"dist/router/index.js","limit":"1 KB"},{"name":"i18n/ru — the Russian bundle is opt-in, not carried by the main entry. Raised 4.75 → 5 KB for the dictionary sheet's three headings","path":"dist/i18n/ru.js","limit":"5 KB"},{"name":"i18n/es — the Spanish bundle is opt-in, not carried by the main entry. Raised 3.5 → 3.75 KB for the three strings of the other-categories line","path":"dist/i18n/es.js","limit":"3.75 KB"}],"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","directories":{},"maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"antd":"^6.5.0","jsdom":"^26.1.0","react":"^19.1.0","vitest":"^3.2.4","react-dom":"^19.1.0","size-limit":"^11.2.0","typescript":"^5.8.3","@stapel/core":"^0.26.1","@types/react":"^19.1.0","react-router":"^7.18.1","@stapel/image":"^0.4.2","@stapel/tokens":"^0.8.1","@stapel/showcase":"^0.3.0","@types/react-dom":"^19.1.0","@stapel/tokens-antd":"^0.22.1","@tanstack/react-query":"^5.81.0","@testing-library/react":"^16.3.0","@stapel/attributes-react":"^0.17.0","@size-limit/preset-small-lib":"^11.2.0"},"peerDependencies":{"antd":">=5.20.0 <7","react":">=19","@stapel/core":">=0.26.0 <1.0.0","react-router":">=7.0.0 <8","@stapel/image":">=0.3.0","@stapel/tokens-antd":">=0.12.0","@tanstack/react-query":"^5.0.0","@stapel/attributes-react":">=0.4.0"},"peerDependenciesMeta":{"antd":{"optional":true},"react-router":{"optional":true},"@stapel/image":{"optional":true},"@stapel/tokens-antd":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/search-react_0.52.1_1789725911102_0.5949437566917612"}}},"time":{"created":"2026-08-22T13:07:43.838Z","modified":"2026-09-18T10:05:11.550Z","0.1.0":"2026-08-22T13:07:44.301Z","0.2.0":"2026-08-22T23:27:54.911Z","0.3.0":"2026-08-23T17:34:59.567Z","0.3.1":"2026-08-23T21:58:03.930Z","0.4.0":"2026-08-23T23:22:42.956Z","0.7.0":"2026-08-26T20:59:08.987Z","0.8.0":"2026-08-28T03:52:28.529Z","0.9.0":"2026-08-29T23:06:08.444Z","0.9.1":"2026-08-30T21:08:09.842Z","0.10.0":"2026-08-31T01:17:48.502Z","0.11.0":"2026-08-31T06:50:31.498Z","0.12.0":"2026-08-31T09:53:02.707Z","0.13.0":"2026-08-31T11:38:02.520Z","0.14.0":"2026-08-31T12:14:47.933Z","0.14.1":"2026-08-31T14:21:32.665Z","0.14.2":"2026-09-01T18:52:50.336Z","0.15.0":"2026-09-01T21:32:41.431Z","0.16.0":"2026-09-02T05:58:58.773Z","0.18.0":"2026-09-02T15:56:57.213Z","0.18.1":"2026-09-03T00:53:35.785Z","0.19.0":"2026-09-03T03:54:48.399Z","0.20.0":"2026-09-03T08:22:05.823Z","0.21.0":"2026-09-03T12:42:10.447Z","0.22.0":"2026-09-04T06:34:52.948Z","0.23.0":"2026-09-04T07:35:32.295Z","0.24.0":"2026-09-04T09:01:03.572Z","0.25.0":"2026-09-04T10:12:26.960Z","0.26.0":"2026-09-04T12:01:12.591Z","0.27.0":"2026-09-04T14:07:29.050Z","0.28.0":"2026-09-04T16:43:34.045Z","0.29.0":"2026-09-04T17:37:44.048Z","0.29.1":"2026-09-04T18:39:49.523Z","0.30.1":"2026-09-04T22:46:36.223Z","0.31.0":"2026-09-05T08:24:07.497Z","0.32.0":"2026-09-05T14:20:57.227Z","0.32.1":"2026-09-05T16:41:52.142Z","0.32.2":"2026-09-05T17:16:40.843Z","0.32.3":"2026-09-05T18:10:09.189Z","0.32.4":"2026-09-05T22:10:04.267Z","0.32.5":"2026-09-05T23:24:04.311Z","0.32.6":"2026-09-06T00:16:30.940Z","0.32.7":"2026-09-06T04:28:07.944Z","0.32.8":"2026-09-06T08:26:59.339Z","0.33.0":"2026-09-06T09:29:59.932Z","0.33.1":"2026-09-06T12:03:22.524Z","0.34.0":"2026-09-06T15:47:34.868Z","0.35.0":"2026-09-06T18:28:47.203Z","0.36.0":"2026-09-07T01:48:57.216Z","0.36.1":"2026-09-07T11:22:22.067Z","0.37.0":"2026-09-07T20:48:00.766Z","0.38.0":"2026-09-10T10:33:23.516Z","0.39.0":"2026-09-10T12:22:31.042Z","0.40.0":"2026-09-11T01:41:03.703Z","0.41.0":"2026-09-11T03:30:21.815Z","0.41.1":"2026-09-12T00:56:21.953Z","0.41.2":"2026-09-12T02:48:12.940Z","0.42.0":"2026-09-12T19:31:48.910Z","0.42.1":"2026-09-12T21:23:45.295Z","0.42.2":"2026-09-13T13:43:52.910Z","0.43.0":"2026-09-13T14:28:26.744Z","0.44.0":"2026-09-13T14:50:22.673Z","0.45.0":"2026-09-13T15:37:52.707Z","0.46.0":"2026-09-13T17:16:15.317Z","0.47.0":"2026-09-13T18:30:43.989Z","0.47.1":"2026-09-13T18:56:51.458Z","0.48.0":"2026-09-13T20:47:45.735Z","0.48.1":"2026-09-14T10:12:49.998Z","0.49.0":"2026-09-14T16:57:19.580Z","0.49.1":"2026-09-14T17:31:45.607Z","0.49.2":"2026-09-14T18:58:30.909Z","0.50.0":"2026-09-14T19:45:39.894Z","0.50.1":"2026-09-16T00:14:50.439Z","0.52.0":"2026-09-18T02:10:58.419Z","0.52.1":"2026-09-18T10:05:11.205Z"},"license":"MIT","repository":{"url":"https://github.com/usestapel/stapel-react.git","type":"git","directory":"packages/search-react"},"description":"Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets","maintainers":[{"name":"ucsoftworks","email":"ucsoftworks@gmail.com"}],"readme":"","readmeFilename":""}