@
feat(ui): add DataTable and Toaster, drop the legacy Table, fix overlay dialogs DataTable replaces the 20-line Table scaffold entirely: columns, sorting, filtering, pagination, selection, bulk actions, comparison layout, sticky first column, custom HTML cells, and a remote source driven by a `request` output rather than a function prop (props travel as HTML attributes, so a function arrives as its own source text). Toaster replaces the hand-rolled status div: tone icons, actions, hover pause/resume and a progress bar. Overlays audit -- Modal and Drawer declared aria-modal="true" but nothing ever moved focus into the panel, so the @keydown handler on their root never ran and closeOnEscape did nothing. Focus, focus restore, a Tab trap and a body scroll lock now live in the reactive runtime, shared by both. ContextMenu placed pointer menus by subtracting a guessed 340x420 from the viewport, which pushed every menu that was not that size away from the pointer; it now positions at the pointer and lets the anchored clamp pull it back once it can be measured. The reactive runtime size budget moves 150k -> 175k to cover anchored overlays, dialog behaviour, the toaster and the DataTable client half. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> @
This commit is contained in:
@@ -70,7 +70,19 @@ const escapeText = (value) =>
|
||||
String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
||||
// WRN uses braces for reactive expressions. Encode braces inside documentation
|
||||
// code so hydration keeps them as literal, copyable source text.
|
||||
const escapeCode = (value) => escapeText(value).replaceAll("{", "{").replaceAll("}", "}");
|
||||
/*
|
||||
* Code samples: each brace goes in its own element.
|
||||
*
|
||||
* The entity alone is not enough. It survives the compiler, but the BROWSER
|
||||
* decodes it back to a brace, and the client runtime then walks text nodes
|
||||
* looking for {mustache} and evaluates whatever it finds -- so a JSON sample
|
||||
* was silently eaten, leaving "columns=[, , , ]" on the page. A text node can
|
||||
* only be mistaken for a template when it holds a complete pair, so splitting
|
||||
* the braces into their own nodes makes samples immune. A reader sees no
|
||||
* difference.
|
||||
*/
|
||||
const escapeCode = (value) =>
|
||||
escapeText(value).replaceAll("{", "<span>{</span>").replaceAll("}", "<span>}</span>");
|
||||
const escapeAttribute = (value) =>
|
||||
escapeText(value).replaceAll('"', """).replaceAll("'", "'");
|
||||
|
||||
@@ -1377,10 +1389,13 @@ function inputNumberConfiguration(variation) {
|
||||
function demoUses(component) {
|
||||
const profile = profileFor(component.name);
|
||||
if (profile?.demos?.length) {
|
||||
return profile.demos.map(({ eyebrow, title, description }) => ({
|
||||
// `before` is carried through: it is markup rendered beside the mount for
|
||||
// host components that have no slot to put controls in.
|
||||
return profile.demos.map(({ eyebrow, title, description, before }) => ({
|
||||
eyebrow,
|
||||
title,
|
||||
description,
|
||||
before,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1493,6 +1508,11 @@ function detailPage(component, categoryComponents) {
|
||||
const preview = validationSchema
|
||||
? `<form data-schema="${validationSchema}" class="demo-validation-form">${mount}<button type="submit" class="wire-btn wire-btn--variant-default">Validate selection</button></form>`
|
||||
: mount;
|
||||
// `before` renders markup NEXT TO the mount rather than inside its slot.
|
||||
// Host-style components (Toaster) have no slot at all: what a reader
|
||||
// needs to see is the controls that drive them, and slot content would
|
||||
// simply be dropped.
|
||||
const beforeMarkup = useCase.before ?? "";
|
||||
return `
|
||||
<article class="demo-case">
|
||||
<header class="demo-case-header">
|
||||
@@ -1503,7 +1523,7 @@ function detailPage(component, categoryComponents) {
|
||||
<div id="${slugOf(component.name)}-demo-${variation + 1}" class="demo-canvas demo-canvas--${variation + 1}">
|
||||
<div class="demo-browser-chrome"><span></span><span></span><span></span><small>Live preview</small></div>
|
||||
${isInteractiveOverlay(component) ? `<p class="demo-interaction-hint"><span class="icon-[lucide--mouse-pointer-click] size-4" aria-hidden="true"></span>${escapeText(overlayInteractionLabel(component))}</p>` : ""}
|
||||
<div class="demo-render">${preview}</div>
|
||||
<div class="demo-render">${beforeMarkup}${preview}</div>
|
||||
</div>
|
||||
<section class="demo-code" aria-label="${escapeAttribute(useCase.title)} usage">
|
||||
<header><span><span class="icon-[lucide--code-2] size-4" aria-hidden="true"></span>Component usage</span><small>.wrn</small></header>
|
||||
|
||||
Reference in New Issue
Block a user