chore(release): publish db 0.8.21, cli 0.8.65 and seven in-flight packages
Carries the rollback refusal in db and the matching CLI message, together with the auth, captcha, csr, dev-server, dev-toolbar, ui and validation changes that were already in the working tree, since publishing stages from it and those files would otherwise ship without being recorded here. @wrnexus/auth 0.8.28 -> 0.8.29 @wrnexus/captcha 0.8.15 -> 0.8.16 @wrnexus/cli 0.8.64 -> 0.8.65 @wrnexus/csr 0.8.37 -> 0.8.38 @wrnexus/db 0.8.20 -> 0.8.21 @wrnexus/dev-server 0.8.60 -> 0.8.61 @wrnexus/dev-toolbar 0.8.17 -> 0.8.18 @wrnexus/ui 0.8.75 -> 0.8.76 @wrnexus/validation 0.8.12 -> 0.8.13 Also declares Event among the browser globals captcha's client asset already lists, which was the last lint failure, and reformats four files. typecheck, lint, 1998 tests and format:check all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b807f7b5a7
commit
06433e4ac4
28 files changed
+194
-43
No files matched your search
@@ -344,7 +344,7 @@ component AdvancedSelect {
|
||||
{#if searchable}
|
||||
<label class="wrn-next__select-search">
|
||||
<span class="wrn-visually-hidden">{searchPlaceholder}</span>
|
||||
<span class="wrn-next__search-icon" aria-hidden="true">⌕</span>
|
||||
<span class="wrn-next__search-icon icon-[lucide--search]" aria-hidden="true"></span>
|
||||
<input
|
||||
type="search"
|
||||
value="{query}"
|
||||
@@ -473,8 +473,17 @@ component AdvancedSelect {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.wrn-next__select-search .wrn-next__search-icon {
|
||||
inset-inline-start: 0.8em;
|
||||
left: auto;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wrn-next__select-search input {
|
||||
padding-left: 2.25em;
|
||||
padding-inline-start: 2.4em;
|
||||
padding-inline-end: 0.75em;
|
||||
}
|
||||
|
||||
.wrn-next__select-tags {
|
||||
|
||||
@@ -86,6 +86,16 @@ component Sidebar {
|
||||
output.close({ source: "drawer" })
|
||||
output.toggle({ open: false })
|
||||
}
|
||||
|
||||
client function revealActiveItem() {
|
||||
document.querySelector(".wrn-sidebar__rail .wrn-sidebar__link--active") && document.querySelector(".wrn-sidebar__rail .wrn-sidebar__link--active").scrollIntoView({ block: "nearest", inline: "nearest", behavior: "auto" })
|
||||
}
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
mount {
|
||||
revealActiveItem()
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
@@ -115,7 +125,7 @@ component Sidebar {
|
||||
<p class="wrn-sidebar__heading" data-show="entry.heading">{entry.heading}</p>
|
||||
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(entry) ? "wrn-sidebar__link--active" : ""}'
|
||||
data-show="!entry.heading"
|
||||
href='{entry.href || "#"}'
|
||||
data-wrn-roving-item="true"
|
||||
@@ -138,7 +148,7 @@ component Sidebar {
|
||||
{#each childrenOf(entry) as child}
|
||||
<li class="wrn-sidebar__entry">
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(child) ? "wrn-sidebar__link--active" : ""}'
|
||||
href='{child.href || "#"}'
|
||||
data-active='{isActive(child)}'
|
||||
aria-current='{isActive(child) ? "page" : "false"}'
|
||||
@@ -163,7 +173,7 @@ component Sidebar {
|
||||
{#each childrenOf(child) as leaf}
|
||||
<li class="wrn-sidebar__entry">
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(leaf) ? "wrn-sidebar__link--active" : ""}'
|
||||
href='{leaf.href || "#"}'
|
||||
data-active='{isActive(leaf)}'
|
||||
aria-current='{isActive(leaf) ? "page" : "false"}'
|
||||
@@ -201,7 +211,7 @@ component Sidebar {
|
||||
<p class="wrn-sidebar__heading" data-show="entry.heading">{entry.heading}</p>
|
||||
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(entry) ? "wrn-sidebar__link--active" : ""}'
|
||||
data-show="!entry.heading"
|
||||
href='{entry.href || "#"}'
|
||||
data-wrn-roving-item="true"
|
||||
@@ -224,7 +234,7 @@ component Sidebar {
|
||||
{#each childrenOf(entry) as child}
|
||||
<li class="wrn-sidebar__entry">
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(child) ? "wrn-sidebar__link--active" : ""}'
|
||||
href='{child.href || "#"}'
|
||||
data-active='{isActive(child)}'
|
||||
aria-current='{isActive(child) ? "page" : "false"}'
|
||||
@@ -249,7 +259,7 @@ component Sidebar {
|
||||
{#each childrenOf(child) as leaf}
|
||||
<li class="wrn-sidebar__entry">
|
||||
<a
|
||||
class="wrn-sidebar__link"
|
||||
class='wrn-sidebar__link {isActive(leaf) ? "wrn-sidebar__link--active" : ""}'
|
||||
href='{leaf.href || "#"}'
|
||||
data-active='{isActive(leaf)}'
|
||||
aria-current='{isActive(leaf) ? "page" : "false"}'
|
||||
|
||||
@@ -5,6 +5,7 @@ component Badge {
|
||||
|
||||
props {
|
||||
label: string = "Badge"
|
||||
humanize: boolean = true
|
||||
size: string = "md"
|
||||
color: string = "primary"
|
||||
variant: string = "solid"
|
||||
@@ -86,7 +87,7 @@ component Badge {
|
||||
{/if}
|
||||
{#if !dotOnly}
|
||||
<span class="wrn-next__badge-label {truncate ? 'wrn-next__badge-label--truncate' : ''}">
|
||||
{label}
|
||||
{humanize ? label.replaceAll('_', ' ').replaceAll('-', ' ') : label}
|
||||
</span>
|
||||
{/if}
|
||||
{#if icon && iconPosition === "end"}
|
||||
@@ -142,6 +143,10 @@ component Badge {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wrn-next__badge-label {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.wrn-next__badge[data-size="xs"] {
|
||||
min-height: 1.25rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
|
||||
@@ -28,6 +28,7 @@ label: string = "Button"
|
||||
ariaExpanded: string = ""
|
||||
ariaControls: string = ""
|
||||
title: string = ""
|
||||
tooltipPlacement: string = "top"
|
||||
autofocus: boolean = false
|
||||
controlClass: string = ""
|
||||
class: string = ""
|
||||
@@ -93,7 +94,8 @@ label: string = "Button"
|
||||
{/if}
|
||||
{#if (size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg") && (ariaLabel || label)}
|
||||
<span
|
||||
class="wrn-btn__tooltip"
|
||||
class="wrn-btn__tooltip wrn-btn__tooltip--{tooltipPlacement}"
|
||||
data-placement="{tooltipPlacement}"
|
||||
role="tooltip"
|
||||
aria-hidden="true"
|
||||
>
|
||||
@@ -154,7 +156,8 @@ label: string = "Button"
|
||||
{/if}
|
||||
{#if (size === "icon" || size === "icon-xs" || size === "icon-sm" || size === "icon-lg") && (ariaLabel || label)}
|
||||
<span
|
||||
class="wrn-btn__tooltip"
|
||||
class="wrn-btn__tooltip wrn-btn__tooltip--{tooltipPlacement}"
|
||||
data-placement="{tooltipPlacement}"
|
||||
role="tooltip"
|
||||
aria-hidden="true"
|
||||
>
|
||||
@@ -469,5 +472,11 @@ label: string = "Button"
|
||||
opacity var(--wrn-motion-fast) var(--wrn-ease-standard),
|
||||
transform var(--wrn-motion-fast) var(--wrn-ease-standard);
|
||||
}
|
||||
|
||||
.wrn-btn__tooltip--bottom {
|
||||
inset-block-start: calc(100% + 0.5rem);
|
||||
inset-block-end: auto;
|
||||
transform: translate(-50%, -0.25rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,7 +330,7 @@ size: string = "default"
|
||||
font-size: 0.82em;
|
||||
font-weight: 600;
|
||||
}
|
||||
.wrn-next__field-error:empty {
|
||||
.wrn-next--field[data-invalid="false"] > .wrn-next__field-error {
|
||||
display: none;
|
||||
}
|
||||
.wrn-next--field[data-invalid="true"] :is(input, textarea, select),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.8.70",
|
||||
"version": "0.8.76",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -153,9 +153,9 @@ describe("@wrnexus/ui redesign component pack", () => {
|
||||
|
||||
expect(source).toContain('<slot name="brand" />');
|
||||
expect(source).toContain("brand.logo || brand.icon || brand.label || brand.description");
|
||||
expect(source.indexOf("brand.logo || brand.icon || brand.label || brand.description")).toBeLessThan(
|
||||
source.indexOf('<slot name="brand" />'),
|
||||
);
|
||||
expect(
|
||||
source.indexOf("brand.logo || brand.icon || brand.label || brand.description"),
|
||||
).toBeLessThan(source.indexOf('<slot name="brand" />'));
|
||||
});
|
||||
|
||||
test("Navbar renders slotted utilities before its built-in actions", async () => {
|
||||
@@ -183,8 +183,8 @@ describe("@wrnexus/ui redesign component pack", () => {
|
||||
|
||||
expect(source).toContain("wrn-navbar__mobile-mega-link");
|
||||
expect(source).toContain("item.href || megaData(item).actionHref");
|
||||
expect(source).toContain('.wrn-navbar__mega { display: none; }');
|
||||
expect(source).toContain('.wrn-navbar__mobile-mega-link { display: flex; }');
|
||||
expect(source).toContain(".wrn-navbar__mega { display: none; }");
|
||||
expect(source).toContain(".wrn-navbar__mobile-mega-link { display: flex; }");
|
||||
});
|
||||
|
||||
test("Navbar supports in-flow floating and elevated menu panels", async () => {
|
||||
|
||||
@@ -241,6 +241,15 @@ test("screenshot-directed canonical components are bundled", () => {
|
||||
expect(uiComponentNames()).toEqual(expect.arrayContaining(required));
|
||||
});
|
||||
|
||||
test("badge labels are humanized and capitalized by default", () => {
|
||||
const source = readFileSync(uiComponentPath("Badge"), "utf8");
|
||||
const contract = parse(source);
|
||||
const defaults = new Map(contract.props.map((prop) => [prop.name, prop.default]));
|
||||
expect(defaults.get("humanize")).toBe("true");
|
||||
expect(source).toContain("label.replaceAll('_', ' ').replaceAll('-', ' ')");
|
||||
expect(source).toContain("text-transform: capitalize");
|
||||
});
|
||||
|
||||
test("navbar supports brands, nested menus, actions, utility slots, and public events", () => {
|
||||
const source = readFileSync(uiComponentPath("Navbar"), "utf8");
|
||||
expect(source).toContain('slot name="topbar"');
|
||||
@@ -638,12 +647,28 @@ test("every bundled UI component compiles", () => {
|
||||
|
||||
test("icon buttons expose their accessible label as a hover and focus tooltip", () => {
|
||||
const button = readFileSync(uiComponentPath("Button"), "utf8");
|
||||
expect(button).toContain('class="wrn-btn__tooltip"');
|
||||
expect(button).toContain('class="wrn-btn__tooltip wrn-btn__tooltip--{tooltipPlacement}"');
|
||||
expect(button).toContain("{ariaLabel || label}");
|
||||
expect(uiStyles()).toContain(".wrn-btn:hover > .wrn-btn__tooltip");
|
||||
expect(uiStyles()).toContain(".wrn-btn:focus-visible > .wrn-btn__tooltip");
|
||||
});
|
||||
|
||||
test("icon button tooltips support downward placement below sticky headers", () => {
|
||||
const button = readFileSync(uiComponentPath("Button"), "utf8");
|
||||
const contract = parse(button);
|
||||
const defaults = new Map(contract.props.map((prop) => [prop.name, prop.default]));
|
||||
expect(defaults.get("tooltipPlacement")).toBe('"top"');
|
||||
expect(button).toContain('data-placement="{tooltipPlacement}"');
|
||||
expect(uiStyles()).toContain(".wrn-btn__tooltip--bottom");
|
||||
expect(uiStyles()).toContain("inset-block-start: calc(100% + 0.5rem)");
|
||||
});
|
||||
|
||||
test("textarea does not reserve validation space while its error is empty", () => {
|
||||
const textarea = readFileSync(uiComponentPath("Textarea"), "utf8");
|
||||
expect(textarea).toContain('.wrn-next--field[data-invalid="false"] > .wrn-next__field-error');
|
||||
expect(textarea).not.toContain(".wrn-next__field-error:empty");
|
||||
});
|
||||
|
||||
test("button links navigate by default and only download when the native attribute is passed", () => {
|
||||
const button = readFileSync(uiComponentPath("Button"), "utf8");
|
||||
expect(button).not.toMatch(/^\s+download\s*=/m);
|
||||
@@ -2043,6 +2068,11 @@ test("advanced select opens, filters, and selects without reactive handler error
|
||||
expect(dom.querySelector(".wrn-next__select-dropdown")?.getAttribute("data-show")).toBe("true");
|
||||
expect(dom.querySelector('[role="listbox"]')).not.toBeNull();
|
||||
const search = dom.querySelector(".wrn-next__select-search input") as HTMLInputElement;
|
||||
expect(
|
||||
dom
|
||||
.querySelector(".wrn-next__select-search .wrn-next__search-icon")
|
||||
?.classList.contains("icon-[lucide--search]"),
|
||||
).toBe(true);
|
||||
search.value = "engine";
|
||||
search.dispatchEvent(
|
||||
new (dom.window as { Event: typeof Event }).Event("input", { bubbles: true }),
|
||||
@@ -3281,6 +3311,16 @@ test("sidebar composes Drawer for its off-canvas presentation", async () => {
|
||||
expect(source).toContain("<Drawer");
|
||||
});
|
||||
|
||||
test("sidebar reveals the active item when a long navigation rail mounts", () => {
|
||||
const source = readFileSync(uiComponentPath("Sidebar"), "utf8");
|
||||
expect(source).toContain("lifecycle {");
|
||||
expect(source).toContain("revealActiveItem()");
|
||||
expect(source).toContain(".wrn-sidebar__link--active");
|
||||
expect(source).toContain(
|
||||
'scrollIntoView({ block: "nearest", inline: "nearest", behavior: "auto" })',
|
||||
);
|
||||
});
|
||||
|
||||
test("scrollspy renders section links and marks the runtime observation target", async () => {
|
||||
const source = readFileSync(uiComponentPath("Scrollspy"), "utf8");
|
||||
const html = await renderComponent(source, {
|
||||
|
||||
Reference in new issue
Block a user