diff --git a/docs/framework-remediation-plan.md b/docs/framework-remediation-plan.md index cc85ba8f..9ac7a4e9 100644 --- a/docs/framework-remediation-plan.md +++ b/docs/framework-remediation-plan.md @@ -1,14 +1,15 @@ # Framework remediation plan -**Status: remediation behavior completed; CSS ownership cleanup remains.** The +**Status: completed.** The repository has 102 maintained UI components, zero undeclared non-native output emitters, zero components matching the scaffold definition, and local styles on every component. The core reactive runtime is 48,124 minified bytes; component controllers ship separately at 24,027 bytes. -Section 4.1 remains open: the global `ui.css` still contains legacy component -rules duplicated by local component styles. Those rules must be removed before -the §0.1 ownership convention can be called complete. +The §4.1 ownership migration is complete: `ui.css` contains global and +cross-cutting primitives only. Shared component foundations are carried by +three internal style-only components and render on demand; the former global +component families and standalone `wire-next` generation class are absent. Final validation passed the production, package, example, service, editor, showcase-generation, typecheck, lint, formatting, public-API, visual-contract, @@ -16,7 +17,7 @@ security, and runtime-size gates. The only skipped test is the explicitly environment-dependent live PostgreSQL/MySQL test. Written 2026-08-09, after the 0.8.6 release. Every number here was measured -against the tree at commit `7a2b5865`, not estimated. Where a cause is not yet +against the completed tree, not estimated. Where a cause is not yet proven the item says so and makes proving it step one — nothing in this document should be implemented on the strength of a guess. @@ -440,11 +441,10 @@ AdvancedRangeSlider, Chart, Confetti, CopyMarkup, FileUpload, Toast, ToastNotifications, TreeView. Do §3.1 first and this list drops to 19 without any extra work. Do not plan the two items separately. -Separately, 58 components carried the `wire-next` scaffold class in the -original audit; **45 retain it now**. This is a cosmetic naming artefact and was -not part of the scaffold completion criterion. That class is a -generation artefact rather than a design, and it is what ties them to `ui.css` -instead of their own styles (§4.1). +Separately, 58 components carried the standalone `wire-next` scaffold class in +the original audit; **zero retain it now**. Component-specific BEM identifiers +such as `wire-next--alert` remain locally owned implementation details, but no +component is bound to a global stylesheet through the generation artefact. **Change.** Rebuild them under §0.1, or remove them. Note that several are primitives where a scaffold is nearly the right answer — `skeleton`, `spinner`, @@ -500,18 +500,20 @@ whichever behaviour was chosen. ## 4. Delivery and the dev loop -### 4.1 Global `ui.css` migration — PARTIAL +### 4.1 Global `ui.css` migration — FIXED **Original issue.** `ui.css` was **175,848 bytes, 26,350 gzipped**, served on every page. Only **42 of 108** components had a local `style {}` block. -**Result so far.** The maintained library now has **102 of 102** components -with local styles. Built `ui.css` is **54,016 bytes / 9,338 gzipped** after -removing the unused `.wire-switch`, `.wire-alert`, and `.wire-card` families and -localizing the live `.wire-btn`, `.wire-dropdown`, ButtonGroup, alert-variant, -card-overlay, and related rules. The remaining `.wire-next` field and component -rules still form a parallel legacy layer. Local-style coverage alone does not -complete this item; global component selectors must reach zero. +**Result.** The maintained library now has **102 of 102** components with local +styles. Built `ui.css` is **15,927 bytes / 3,762 gzipped**. The `.wire-next`, +`.wire-btn`, `.wire-dropdown`, `.wire-alert`, `.wire-card`, `.wire-footer`, +`.wire-metric-card`, and `.wire-segmented-group` global families are gone. +Reusable field, select, color, and size foundations live in three internal +style-only components; the renderer emits and deduplicates them only when a +component that needs them renders. An example-app SSR guard verifies that +on-demand path, while the UI suite prevents the global families or standalone +`wire-next` class from returning. **Change.** Done in groups with the visual contract regenerated after each migration. @@ -520,8 +522,9 @@ migration. ```bash ls packages/ui/components/*.wrn | wc -l # 102 -grep -lE '^\s*style\s*\{' packages/ui/components/*.wrn | wc -l # 102 -bun run build && gzip -c examples/basic-app/dist/ui.css | wc -c # 9338 +grep -lE '^\s*style\s*\{' packages/ui/components/*.wrn | wc -l # 102 +bun run build +bun -e "const b=await Bun.file('examples/basic-app/dist/ui.css').arrayBuffer(); console.log(Bun.gzipSync(new Uint8Array(b)).length)" # 3762 ``` Add a ratchet test asserting the gzipped size only ever decreases, so this @@ -849,7 +852,7 @@ history. Every row is complete. | 3 | §2.6 server-rendered i18n | Contained work; the core SSR claim currently fails on text. | | 4 | §4.2 + §4.3 dev loop | Cheap, and it compounds across every task below. | | 5 | §4.6 de-duplicate generated client modules | 490 kB decoded parsed per page, 90% of it duplicated. Codegen-only, no API impact. | -| 6 | §4.1 finish the CSS migration | 66 components, mechanical, takes ~26 kB off every page. | +| 6 | §4.1 finish the CSS migration | Localized component ownership and reduced the always-served sheet by ~160 kB. | | 7 | §4.6 split controllers out of the core runtime | 6.6 kB gzipped a typical page never executes. | | 8 | §3.1 Group A: supersede the 5 duplicate scaffolds | 15 of the 22 dead outputs, and 5 fewer components to maintain. Needs a migration entry, not new code. | | 9 | §3.2 scaffolds that need only their styles | Larger and cheaper than it looks; folds into item 6. | diff --git a/docs/ui-visual-contract-0.8.json b/docs/ui-visual-contract-0.8.json index cd9f10d7..8e099d82 100644 --- a/docs/ui-visual-contract-0.8.json +++ b/docs/ui-visual-contract-0.8.json @@ -2,56 +2,56 @@ "schemaVersion": 1, "releaseLine": "0.8", "artifacts": { - "packages/ui/components/Accordion.wrn": "98e6897d7dee2045fbc66e23d8a0b5051114d43f1c75234a2a6c5165132eb706", - "packages/ui/components/AdvancedSelect.wrn": "f8c7ff1c1727ce0e3e132536cdaefe71779936e9303694f763e78699f3ec827a", + "packages/ui/components/Accordion.wrn": "285df0aa50733618afb1b82aa125a67030d3af4bd8b9de52bc2e6366cea871de", + "packages/ui/components/AdvancedSelect.wrn": "e8666638204f9eb044ee6f163d6af432b119bf7f39d9df20243cfae471d20bcd", "packages/ui/components/AnnouncementBar.wrn": "903bfd9421a7350c923ace3315cedc5763fe3e6b7b54b660a0f26281d46a8754", - "packages/ui/components/AuthForm.wrn": "a0f34c233c5d52e2dd11429dacab98e7cd77bec8ae60652aff48f7dab8506893", - "packages/ui/components/AuthSplitLayout.wrn": "42736850c94f2df0bdc5c733530731fb5df0abd1aedfc6962f8f5774c18f3428", - "packages/ui/components/AvatarGroup.wrn": "d73df8249787c7296c2d19f06186a43fcfaf8b7983107b792c42acf18a388494", + "packages/ui/components/AuthForm.wrn": "ec8796a67320afa2fb2070edba194382d1ab0a00cbd574f936a502da819d00fa", + "packages/ui/components/AuthSplitLayout.wrn": "675c6ac9b07e0e9c5d6572f30028dda2391f9c6599b45945eb626df056a5b987", + "packages/ui/components/AvatarGroup.wrn": "85dd6c64f8064d0980bf4157963bf366410c2ba391fd65df86a54b1a336f43a4", "packages/ui/components/BackToTop.wrn": "b12c56ec8b7aabad68cbdc47f4b3237e2c21a61398f0aa51f9add6229b7357cd", - "packages/ui/components/Blockquote.wrn": "3e0845286c631151847d19980631c2636d37bc4bd2e95c6b045a9f51fe01fdc5", + "packages/ui/components/Blockquote.wrn": "6f91cee9538c11858aaeb98ef1a098a814a6e319e3777e59cecd2de078b3beaf", "packages/ui/components/Breadcrumb.wrn": "5ab85d273ce72e4d5b87907975bb33f0249a34f2f87f01dc0812e827f775eed9", - "packages/ui/components/ButtonGroup.wrn": "fd1db987cedcf956e0d279a620eedbf2dcc88b7b7eb25f029d556fd5e363b273", + "packages/ui/components/ButtonGroup.wrn": "0bb23d927e03926cc303498bc4ac1ab098343782082ac1fceeb2402702945842", "packages/ui/components/CTASection.wrn": "2d2241d4f1018cfd2f8ea1ddd5fa8c8fcb8d1bbb2d4e4498cb9f39ff47a3801c", - "packages/ui/components/Card.wrn": "c7e48fba8a0062a46b54dd4ce0ea4fbae8b3a05c416db30992db46d82819882a", - "packages/ui/components/Carousel.wrn": "549fc881e453cc8f74de69cd4716042a4306ead33de99fd19c3e7abe5d79e1f9", + "packages/ui/components/Card.wrn": "ba1b577ae4ffa9bd93c1e6a650ce90745df3f78cd6ff9ee85530e32dab56860a", + "packages/ui/components/Carousel.wrn": "0d39e17a623fb623022f48e79ea1ab9f268e2eb359c491609c137f711a1a3ffc", "packages/ui/components/Chart.wrn": "d2cedd0e02818d0908708c2d07a495c629fad13fa021a2e035d5023dc5c367de", - "packages/ui/components/ChatBubble.wrn": "7b323b35005aaba91b39e6cfaf819f49932428173223c4809374f14cf8e1d3fc", + "packages/ui/components/ChatBubble.wrn": "c46b9aef38f54e6243663046fe1b18ba6f9223cbe9b479d9335f96f217d401cc", "packages/ui/components/Clipboard.wrn": "03fcfb9786008fd7fb0a7719c3279711253afc5bbb9b0262b805dd553c44da8a", - "packages/ui/components/Collapse.wrn": "9a4e6c9cec95342479eeef4df842dc283f8a3fd93eb6ad871b5992fb98f11656", - "packages/ui/components/ColorPicker.wrn": "af0f962555b581df75a6dffb3056d394708c29d93ad18afa86e31707b505a807", + "packages/ui/components/Collapse.wrn": "8869ff4a39541b7e0d538e2b63b9a3dcdcfcd4055fa362519c7e73f164f1be9d", + "packages/ui/components/ColorPicker.wrn": "02f5744c3eb984de4b24de26fbfd3f69021633d4b0b33aceeba84df32f6a7284", "packages/ui/components/Columns.wrn": "e01496aa53025444cc51671efcce40d6d24d86775b2cbb1ee0def1862bb6315d", - "packages/ui/components/Combobox.wrn": "b6ae8cf667ed98f3fc4dc141bde797daf7e3daacf7df6c9a7c25a3a143432f62", + "packages/ui/components/Combobox.wrn": "140b038735a5902eb901386281a5a01e16fd1c345560a48ff2b143ebaebe1f3d", "packages/ui/components/Confetti.wrn": "b9aece64735c721c24356122e52ca84602d9f646c7d8be1e0b80d9de3163a501", "packages/ui/components/Container.wrn": "4a0acbb896f4c11714e3925d912b10ef9aeedfa904b4ad8561aa2cbd9a0fdca0", "packages/ui/components/ContextMenu.wrn": "33fb0f60268b12411d66e3031dc0557cb231149e7a8d83340b4b453a6e37cb09", "packages/ui/components/CustomScrollbar.wrn": "fedb2ab06cc2cf9499c130590945ca6971a3edfb60407b6658ef7756e4be9823", - "packages/ui/components/DataMap.wrn": "7d0384d89126d947a6c2d640c93ab047aecca7931569d11b54d82dbb6639ff0e", - "packages/ui/components/DataTable.wrn": "dc4453df72181311658b1227fabc4f147e0097ecbfe122ff695142642819534e", - "packages/ui/components/DatePicker.wrn": "a9edc2faf30a0e998e964e9290ee6bd9512787aa5dc19f360bcce029796d7e1c", - "packages/ui/components/DeviceFrame.wrn": "805aeed1abd321649c31dcf5c9e4e3465e16303a837645924437c75985befc26", + "packages/ui/components/DataMap.wrn": "6058f92be7fb95e9eedcc714cad1ad43fa70e40c9dd50fd8bba5aae9935953a7", + "packages/ui/components/DataTable.wrn": "edb935b091750ee3d1aff354007eabd4998fc7e5584d50a6c726c6657765d800", + "packages/ui/components/DatePicker.wrn": "2c46f92612528cf60aa0b7e8aaae9826094acb5518d3982c2db65aca6d01e103", + "packages/ui/components/DeviceFrame.wrn": "d918d213e6e0b74d690911ab3b3f440e9b62fa019fd9e8140c5a56c5c0a0843d", "packages/ui/components/Divider.wrn": "f5cc449611022b3d3eedf982ae48f6b1a289db7855cc9b6ea0248dcda807ffb3", - "packages/ui/components/DragAndDrop.wrn": "d97a7598dd659ecf72b8649af0b23902dc14d80c19df53dc63ecc5c7b69b8952", + "packages/ui/components/DragAndDrop.wrn": "31ffe9d41fc655a38257c841a520c947d3ce2338e174b5e89e32fe9ccf23b9b3", "packages/ui/components/Drawer.wrn": "e6e2778e515361a3475439ab91b6efec3895efab2a4dfdcfb535713f656cc7ed", "packages/ui/components/Dropdown.wrn": "627319de0f555f0f07f80e19a59f9fd52e7f74af7cf2cf9ff09e114678ad9eb8", "packages/ui/components/FeatureCard.wrn": "2a1bfb01cec8a9892d3ff066e48c276fa7c548cb59c15bcd9b4bbf85450a07a2", - "packages/ui/components/FeatureGrid.wrn": "9e3c0440d08c6982861d3e732eeb20f1023413a58243844dfb9d7033bac13d2b", + "packages/ui/components/FeatureGrid.wrn": "9bd3e9becb5d7359841ed21d607131c58da20f2e8e87e25a9fb48f6b1a2b17e5", "packages/ui/components/FeatureIconCard.wrn": "620f66a36ca5c8ad8f2ea09e94dc4471e4146189c42149e9d31db58501281639", - "packages/ui/components/FileInput.wrn": "c235385a70eb7cb985083597570474c0cb70463c03cab651e452199b2c9abf25", - "packages/ui/components/FileUploadProgress.wrn": "1abdb7a1a181abc6b9b62a0bd45066236f7e1d8fa5139e7fb478b08997f000d9", - "packages/ui/components/Footer.wrn": "956a504682760c4e5f4d26091830c4fc0f8d0c12f7cdf7e69c94539685c67763", + "packages/ui/components/FileInput.wrn": "cc4b8f95f11d91ead9a5796e202b2264eeea24aa1c3b1718327a6ea1dd28d785", + "packages/ui/components/FileUploadProgress.wrn": "c4b4174025a1de75c35a3497e0afd0b8acc645ad5f85c3ed7296ea295bb05749", + "packages/ui/components/Footer.wrn": "71790c99e4b15a62fdaf4b7a65d7016ca427408b62a2b1c7695ef1b39ba29440", "packages/ui/components/Grid.wrn": "d089d8657298b4d33993ba4bf7b581f816c65db513d8e48cf1fdd18da19e05a8", "packages/ui/components/Hero.wrn": "e4e39dcd59c273192c7e4136f6583279e20b0956bcba4cfbc3f6e01a1fade152", "packages/ui/components/HeroActions.wrn": "77f69085db73b946c00aa684d50fb5ae474684e440e81edbccfd8ef5dc357e33", "packages/ui/components/Image.wrn": "8113441bf90ab0d1d8618d477125ad339021f39e853db89d656c72c492e7a20b", - "packages/ui/components/InputGroup.wrn": "7347865ff9b90dde690cf0753adc753a91d2ae599e92405f47e5b35806f58e06", + "packages/ui/components/InputGroup.wrn": "95333e7cb883c52958e3d6112899f337b00825e7678a2323baed1724983a7238", "packages/ui/components/InputNumber.wrn": "0ec020084f3e556d438f8264d61f836cfab4951c52d4df60e4944fb734fb38a9", "packages/ui/components/Kbd.wrn": "5afaabbb15902bd8fb82cb4155cf6cbfff55600927b54d564d27e2dd8b752386", "packages/ui/components/LayoutSplitter.wrn": "6bd6812e364420ed5d3439862116c58d0b011b298679005795bdccdbb7455066", - "packages/ui/components/LegendIndicator.wrn": "f5a59fce000206dd9285c063b6b8eea414d044f161524e6e1c77e8c817ede261", + "packages/ui/components/LegendIndicator.wrn": "11f13413242e106daf347638ee2b2313fd20b05fc7001f03c0f4c00a558dfec0", "packages/ui/components/Link.wrn": "b986abcc66bc0b1c6296f3ff4e560812e35d89cc680d5251d7a3883e68c1d053", "packages/ui/components/List.wrn": "9bfa9613f388e5b126fc27d505e8165d7aa4a058e72132b755585464e116490e", - "packages/ui/components/ListGroup.wrn": "4fcf9302f409b3d6c5d4a3519abac87f71647a9315d89b1f9d8abfa3b9b8f632", + "packages/ui/components/ListGroup.wrn": "885020eea4dbdfc90b5a659e48a339cba7a205ddb539e30d7f1aa57244d728a5", "packages/ui/components/Map.wrn": "9023a7a188480b24222a3910d26f6926918470369a1ab610f841c31a6120b9aa", "packages/ui/components/MarketingSectionHeader.wrn": "6f89a3b298ea299db686ddf903f92c4fe5d321719213943b16be82ba36c23302", "packages/ui/components/Marquee.wrn": "2a88c8bd8378469add26b0d937adccac4aa9f2c2005393010298e8e4fa89693e", @@ -60,16 +60,16 @@ "packages/ui/components/MetricGrid.wrn": "6018a98c10628ed240ed236ed916c0ff60994d192c3aadafd10bc876be0f9364", "packages/ui/components/Modal.wrn": "59d4ae9d6dd2700692d9edecfe53ee868e9f864363a4885961d1813cb2bee51f", "packages/ui/components/Nav.wrn": "7dc456b879e9248bde267b986cdcb138b8f3127d98b51e27bc9708129953f5e2", - "packages/ui/components/Navbar.wrn": "7989d25819312014c0a0855370b80b925d53ff735d682fdb61e9677a9dacb7f3", + "packages/ui/components/Navbar.wrn": "70640f9ff6e615c70ea9a5e996058bad45ebf0e97b02c9d827228a8f475f72e2", "packages/ui/components/PageHeader.wrn": "59264dfb26a132fd3eb265c4374f9fcae781f30dd94a087c57e6e8256717cf14", "packages/ui/components/Pagination.wrn": "9ceb74745b159150b015bbbb1974c68e14a7d4b92bd03491cb23b8855aa07983", - "packages/ui/components/PinInput.wrn": "6909e196bb1060aeec4877594a180da3ff1dad694671756fcdb0f58f548a63d3", + "packages/ui/components/PinInput.wrn": "2b656cf832c02fa9c28e2fe78bf1147ff05b17a9d8e744c33e1a63bad7c7ebb3", "packages/ui/components/Popover.wrn": "f2996f00fad3e35fba2d48e70af17f592854eb73b9e8c6a83526aa78c4e41293", - "packages/ui/components/PortalDashboard.wrn": "0ca5228b0793572270d9cbac1eb5e5e5a77a3886a3a4a7ce7126d5e7b467fd4e", - "packages/ui/components/PreferenceSwitcher.wrn": "61d01f507b3f6b4bab55d2642beb9fee5edf0662997b44443142b43c828ea239", + "packages/ui/components/PortalDashboard.wrn": "79b54868f150a551cede0731cc5390a45ce22375f1929f2d537ce67a987bde50", + "packages/ui/components/PreferenceSwitcher.wrn": "241060fb24a16e795c53981506d273fe9110cbb250c73c85928c788c75d05ded", "packages/ui/components/PublicPageShell.wrn": "369b74f65e27227311a2ed73e9ca56c8b60908100d6840a798e8ba5f2c8b1040", - "packages/ui/components/RangeSlider.wrn": "90ef35ceb94899dfd6e07ef3f3a88f2fb49c8dfe4596def67fe39fd9911d73c7", - "packages/ui/components/Rating.wrn": "1dc480b9bea35af8e3703f858f4d169ed3a16e7689827e4451ec5d8f2e6029ca", + "packages/ui/components/RangeSlider.wrn": "eff9db1616d424f9c803185b4efe011942866acad3328179438a200210d97710", + "packages/ui/components/Rating.wrn": "41bbce2eb7fb6ad08a3aacde97d03af6e346824962148e7655743028c59185d3", "packages/ui/components/Scrollspy.wrn": "76d1c17580c8d460f1222ce97585bdcac9779141f2f30d5460c84ff9f75413d8", "packages/ui/components/SearchBox.wrn": "717f7647fabd762f8ed60a7c3306eac3ddb83c0da292a53c76d91886c2b8f94f", "packages/ui/components/Section.wrn": "33eb8a82a2102229c2b1f64cec497e9e8e70b67adab8dbe396be860fccbb699c", @@ -78,32 +78,35 @@ "packages/ui/components/SplitHero.wrn": "70e843565ff869bcf413b11b6d9830b2e2bd229863a00904596f71e2dff0e76d", "packages/ui/components/StatsBar.wrn": "c7d1df3895f25b6d3a2e1012a18b97592c7f33e65418b880d486f20c2d490686", "packages/ui/components/Stepper.wrn": "df9093e4222ef3250963a8c6fbfec74477242735d23eabe896c29731c54fc14d", - "packages/ui/components/StrongPassword.wrn": "9559756cacd10d613aea7a4ab9845a011f7f2f4613f82f83c87ab5fd2bad2ea9", - "packages/ui/components/StyledIcon.wrn": "e4f79f188dab1d6a3f515c13f15b7e35e2f1c1bd9130e4affc7f2fc09d456c5a", + "packages/ui/components/StrongPassword.wrn": "0df060bf01ace77ad0158df489588df75fd5d426dc04f000abacc2b3ddd93fc5", + "packages/ui/components/StyledIcon.wrn": "bf9b41e9c402c4886feddda504c3f12348bbbe49b9003de69d807db4bf52d1b1", "packages/ui/components/Tabs.wrn": "e38336d28876caa4e97da32a569749e3803b030284a85ce9f35fa788e51cc5b0", "packages/ui/components/TextLink.wrn": "6e18906337cd3d30c2a0122593d249bde8f7cedc697b90ae388e2bd0e8eff3e1", - "packages/ui/components/TimePicker.wrn": "b3f24767448cb04ddd56e06540b52e5cc32ea21ed4acd2a5eb4f7e46f8617aba", + "packages/ui/components/TimePicker.wrn": "d2fb7cd156bb2abb997a9e85d27c36b80f4ba81515b523a125e793363568475c", "packages/ui/components/Timeline.wrn": "686a37ebc62732842846d004491336970db94945bca942f226097d863e159d1c", "packages/ui/components/Toaster.wrn": "288b2b370f65bf823e8d2a6f8c8cf66972332b8174303d33ebe8546d5e1d52c4", - "packages/ui/components/ToggleCount.wrn": "c4365eb10cc9993d8b6b212268341904dda27718360113826a925a617e279479", - "packages/ui/components/TogglePassword.wrn": "c644436c3435b8a9b39c6b7a9f75671b76ca74f273952ce5c032ca169b0470e5", + "packages/ui/components/ToggleCount.wrn": "285abf0ed5c7156c5a6f404af0c2519f181b591975515e845cbc3c21349c5cfd", + "packages/ui/components/TogglePassword.wrn": "94cd3579bb48e53283c82400bff58ea0f2ca92646b87385502e3b474ba787a96", "packages/ui/components/TreeView.wrn": "c354fce9c5e81fed6eec4089dfd2a7f6bb84eb189c94efc88e00251efdc12c0b", "packages/ui/components/Typography.wrn": "1b4d1b91dee0ff522d27c566becc3bc49bd9ec979ae6334e6a15fca5d88eccac", - "packages/ui/components/WysiwygEditor.wrn": "e4d341f7f49b53301d790bcebe7f3788fea4ea4b72ba8bf0a422e006ceeb54eb", - "packages/ui/components/alert.wrn": "74ef969d629f68a83a9cb8a42bb4924411f048bfa9e7b451b9243bd451ac8323", - "packages/ui/components/avatar.wrn": "3e2fc145949f6141246ad0b274403b9149ccc28b6a8e80285b396345097c818a", - "packages/ui/components/badge.wrn": "61fbc7a9cab484287025b214e181dab7662280a766e64c1af80248ab7dbea121", - "packages/ui/components/button.wrn": "a42df46d19c8375ceed059f593b555f77414042bbaf777afcf16d276e133db15", - "packages/ui/components/checkbox.wrn": "e59a56e6acfe3756da8c2b827fee938fa4158250ae587a62936b3df0b988f28c", - "packages/ui/components/input.wrn": "b75df32f470f16e4ee858368264a60bac582b3525eca1c0910250ee3a0a56b76", + "packages/ui/components/WysiwygEditor.wrn": "231da25f4064b065adb2783252d430aa336585e008547a010a41174a41284524", + "packages/ui/components/alert.wrn": "6dde2cee818a66e1d80df6b93e9f971d5389f95387961593350b0c297e3ed367", + "packages/ui/components/avatar.wrn": "ac2239cc746ec35b81a34ec6e27f4ee74ca04dc6058bad5853aa66640f2a9426", + "packages/ui/components/badge.wrn": "9e1e884e9e2e9d881348c5121f53f4c85b91355cbfa49eeb2bff43f5ab38fab5", + "packages/ui/components/button.wrn": "da1660c671daf2feffe1024203ac1a8bc947beb07691bef595c1552c664b9cde", + "packages/ui/components/checkbox.wrn": "a5fb8410558696b3c8e63d5cd8dd49b44d51ed35b809cb2b189501e2e7b323e2", + "packages/ui/components/input.wrn": "184066a837982ef3fe44e518730d0cccb7dd6772d5af58116c0774b71cb894e2", "packages/ui/components/progress.wrn": "61b01ba575d35691e3dfebfcb03ccd1c6b79f1df1c0d41857ec3b01944081a5d", - "packages/ui/components/radio.wrn": "d0f45da28075e5dc6283f62296687f96ed06eeadcc59db892ee516d0f420ce2b", - "packages/ui/components/select.wrn": "826035c3049eca85f0a86e2a974ce23f5b6d2f855bce660f2219b9855332c974", + "packages/ui/components/radio.wrn": "cc65395aad6c0bac690c18cb7c36b1d2784e4c3284be3d3cb277b745f2f29bbc", + "packages/ui/components/select.wrn": "d58b454958edccce99f96c642eb67d5a0e64e2b97e58e742d445fe45164a7660", "packages/ui/components/skeleton.wrn": "dda95a2c59c6060ab2b9f916eb046fbe74a68b398a051afc0bde41808e059c3a", "packages/ui/components/spinner.wrn": "ffbd28ec6fc017fc94c67778f8966eab2eefa3b47f3f27f064c77dbeb65d84c1", - "packages/ui/components/switch.wrn": "205591decf50f1f7d190d8da6a3d969e0fd17ec5300c968fb005608da6a6e596", - "packages/ui/components/textarea.wrn": "00b48d4dbbd5aedfe51e8e932d124b3e222383360c738ac3b15fbbf478481ff7", + "packages/ui/components/switch.wrn": "917219d77b2089584bc444fe94f2cb0670f800d73f69ae70f0368bfece16be0c", + "packages/ui/components/textarea.wrn": "602ef2c8a081476f790408119b96ec2b51fb18abe76a43ee2b955dcb60debd17", "packages/ui/components/tooltip.wrn": "40028dfbb17f6725c76c2e091af9c30ea4db6aa4dea919d38f53874ea70315d1", - "packages/ui/ui.css": "b37e9434e74478cc4d7f3ccb7bee8e2f629827edc09dadbe29e6c299d6913a36" + "packages/ui/styles/ComponentBaseStyles.wrn": "566724a7bcc8f7caa067d5415177bf982ebae7b579a34052ce6f2092cbade4d7", + "packages/ui/styles/FieldStyles.wrn": "460fc8cbb0228151927fd6a61caceae0a148fdbc3009c13ba511ab0a4010b42d", + "packages/ui/styles/SelectStyles.wrn": "2c45e9c04678aaff76632e908b3c061410be0d6999a54a9203a39a3817d698f2", + "packages/ui/ui.css": "b7e2ae796ffbb738451364f63fce13022a81d81207f7e49c7f6220d24c36acd9" } } diff --git a/examples/basic-app/app/example.test.ts b/examples/basic-app/app/example.test.ts index 72bbcbc7..1d1102eb 100644 --- a/examples/basic-app/app/example.test.ts +++ b/examples/basic-app/app/example.test.ts @@ -98,6 +98,17 @@ describe("full app", () => { expect(html).not.toContain("Card title"); }); + test("shared UI foundations render on demand instead of shipping in ui.css", async () => { + const fieldResponse = await app.fetch("/modal"); + expect(fieldResponse.status).toBe(200); + const fieldHtml = await fieldResponse.text(); + expect(fieldHtml).toContain('data-wrnexus-style-owner="FieldStyles"'); + expect(fieldHtml).toContain('data-wrnexus-style-owner="ComponentBaseStyles"'); + const selectResponse = await app.fetch("/test"); + expect(selectResponse.status).toBe(200); + expect(await selectResponse.text()).toContain('data-wrnexus-style-owner="SelectStyles"'); + }); + test("platform showcase uses the public layout and styled reactive primitives", async () => { const res = await app.fetch("/platform-showcase"); expect(res.status).toBe(200); diff --git a/examples/basic-app/app/pages/modal.wrn b/examples/basic-app/app/pages/modal.wrn index 1230dc08..6219e1d9 100644 --- a/examples/basic-app/app/pages/modal.wrn +++ b/examples/basic-app/app/pages/modal.wrn @@ -1,3 +1,7 @@ +import Input from "@wrnexus/ui/components/input.wrn" +import Modal from "@wrnexus/ui/components/Modal.wrn" +import Toaster from "@wrnexus/ui/components/Toaster.wrn" + // Modal demo page. Route: /modal // // Five real-world use cases for the shared @wrnexus/ui Modal component — each @@ -9,13 +13,6 @@ // this page. Any client expression can raise one with the runtime global — // toast("..."), toast.success(...), toast.error(...) — so pages never // hand-roll a status banner and never reach for a blocking alert(). -// -// No import here on purpose: component tags resolve by directory scan, and -// @wrnexus/ui's index.ts intentionally has no runtime exports (registry.ts -// holds the server-only filesystem helpers instead) — an explicit -// `import { Modal } from "@wrnexus/ui"` fails to bundle since there's no -// matching export. The WRN-IMPORT-IMPLICIT warning this triggers is safe to -// ignore for component tags. page ModalPage { state noteText = "Remember to ship the release notes" diff --git a/examples/basic-app/app/pages/test.wrn b/examples/basic-app/app/pages/test.wrn index eeb783b4..d710d6f5 100644 --- a/examples/basic-app/app/pages/test.wrn +++ b/examples/basic-app/app/pages/test.wrn @@ -1,3 +1,6 @@ +import AdvancedSelect from "@wrnexus/ui/components/AdvancedSelect.wrn" +import ComboBox from "@wrnexus/ui/components/Combobox.wrn" + // Component event test page. Route: /test // // Events bubble from the exact ComboBox or AdvancedSelect that emitted them. diff --git a/packages/cli/src/build.ts b/packages/cli/src/build.ts index c293958b..533f86e0 100644 --- a/packages/cli/src/build.ts +++ b/packages/cli/src/build.ts @@ -148,7 +148,12 @@ export async function runBuild(appRoot: string): Promise { const pluginContributions = await pluginRunner.contributions(); const { generateApplicationTypes } = await import("./types.ts"); generateApplicationTypes(root, pluginContributions); - const componentDirs = [uiComponentsDir(), ...pluginContributions.componentDirs]; + const bundledUiDir = uiComponentsDir(); + const componentDirs = [ + bundledUiDir, + join(bundledUiDir, "..", "styles"), + ...pluginContributions.componentDirs, + ]; await pluginRunner.hook("buildStart"); const virtualModules = new Map(); for (const [index, module] of pluginContributions.virtualModules.entries()) { diff --git a/packages/cli/src/inspect.ts b/packages/cli/src/inspect.ts index 0d3fafe4..38181706 100644 --- a/packages/cli/src/inspect.ts +++ b/packages/cli/src/inspect.ts @@ -11,7 +11,10 @@ export type InspectTarget = export function inspectComponent(appRoot: string, requestedName: string): unknown { const root = resolve(appRoot); - const router = buildRouter(join(root, "app"), { componentDirs: [uiComponentsDir()] }); + const bundledUiDir = uiComponentsDir(); + const router = buildRouter(join(root, "app"), { + componentDirs: [bundledUiDir, join(bundledUiDir, "..", "styles")], + }); const component = router.components.find( (candidate) => candidate.name.toLowerCase() === requestedName.toLowerCase(), ); @@ -139,7 +142,11 @@ export async function inspectProject(appRoot: string, target: InspectTarget): Pr database: database ?? "default", })); const router = buildRouter(join(root, "app"), { - componentDirs: [uiComponentsDir(), ...contributions.componentDirs], + componentDirs: [ + uiComponentsDir(), + join(uiComponentsDir(), "..", "styles"), + ...contributions.componentDirs, + ], externalRoutes: contributions.routes, middlewareFiles: contributions.middleware, }); diff --git a/packages/dev-server/src/index.ts b/packages/dev-server/src/index.ts index 5dbbeeb4..6ded2862 100644 --- a/packages/dev-server/src/index.ts +++ b/packages/dev-server/src/index.ts @@ -309,7 +309,12 @@ export async function startServer(opts: ServeOptions): Promise { console.log(`[wrnexus:plugin] contributed routes: ${pluginContributions.routes.length}`); const pluginToolbarPanels = await pluginRunner.devToolbarPanels(); - const componentDirs = [uiComponentsDir(), ...pluginContributions.componentDirs]; + const bundledUiDir = uiComponentsDir(); + const componentDirs = [ + bundledUiDir, + join(bundledUiDir, "..", "styles"), + ...pluginContributions.componentDirs, + ]; const hmr = opts.hmr ?? mode === "development"; const port = opts.port ?? 3000; diff --git a/packages/ui/components/Accordion.wrn b/packages/ui/components/Accordion.wrn index 6a4342a6..ceb9ed1f 100644 --- a/packages/ui/components/Accordion.wrn +++ b/packages/ui/components/Accordion.wrn @@ -1,3 +1,5 @@ +import ComponentBaseStyles from "../styles/ComponentBaseStyles.wrn" + component Accordion { outputs { change(payload: { value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null) @@ -103,7 +105,7 @@ component Accordion { data-variant="{variant}" data-indicator="{indicator}" data-multiple="{allowsMultiple() ? 'true' : 'false'}" - class="wire-next wire-next--color-{color} wire-next--size-{size} wire-next--accordion wire-next--accordion-{variant} {bordered ? 'wire-next--accordion-bordered' : ''} {separated ? 'wire-next--accordion-separated' : ''} {flush ? 'wire-next--accordion-flush' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" + class="wire-component wire-component--color-{color} wire-component--size-{size} wire-next--accordion wire-next--accordion-{variant} {bordered ? 'wire-next--accordion-bordered' : ''} {separated ? 'wire-next--accordion-separated' : ''} {flush ? 'wire-next--accordion-flush' : ''} {disabled ? 'wire-next--disabled' : ''} {class}" > {#each items as item, index}
{/each} +
+