feat(blocks): add reusable application shell blocks

- add appearance state, theme presets, preference controls, and preview components

- add responsive primary, nested, mobile, and flyout navigation with route-aware breadcrumbs

- add application layout, sidebar state, header actions, user menu, query refresh, and scroll utilities

- add configurable chat and notification surfaces backed by consumer-provided data and queries

- expose package entry points and cover theme, state, and command behavior with tests
This commit is contained in:
Maofeng
2026-07-29 21:22:47 +08:00
parent 7b9270ef67
commit 011e7d8115
51 changed files with 5253 additions and 0 deletions
@@ -0,0 +1,35 @@
// @vitest-environment jsdom
import { fireEvent, render } from "@testing-library/react"
import { describe, expect, it, vi } from "vitest"
import {
getNavigationCommandProps,
NavigationActionTarget,
navigationActions,
} from "./command-actions"
describe("navigation command", () => {
it("connects an action button to its command target", () => {
expect(getNavigationCommandProps(navigationActions.search)).toEqual({
command: "--invoke",
commandfor: "navigation-action-search",
})
})
it("invokes the matching command target", () => {
const onInvoke = vi.fn()
const { container } = render(
<NavigationActionTarget
action={navigationActions.search}
onInvoke={onInvoke}
/>
)
const target = container.querySelector("#navigation-action-search")
const event = new Event("command")
Object.defineProperty(event, "command", { value: "--invoke" })
fireEvent(target!, event)
expect(onInvoke).toHaveBeenCalledOnce()
})
})
@@ -0,0 +1,55 @@
import React from "react"
export const navigationActions = {
appearance: "appearance",
logout: "logout",
passwords: "passwords",
search: "search",
userMenu: "user-menu",
} as const
export type NavigationAction =
(typeof navigationActions)[keyof typeof navigationActions]
const NAVIGATION_INVOKE_COMMAND = "--invoke"
const NAVIGATION_ACTION_TARGET_PREFIX = "navigation-action-"
export function getNavigationCommandProps(action: NavigationAction) {
return {
command: NAVIGATION_INVOKE_COMMAND,
commandfor: `${NAVIGATION_ACTION_TARGET_PREFIX}${action}`,
}
}
export function NavigationActionTarget({
action,
onInvoke,
}: {
action: NavigationAction
onInvoke: VoidFunction
}) {
const targetRef = React.useRef<HTMLSpanElement>(null)
const invoke = React.useEffectEvent(onInvoke)
React.useEffect(() => {
const target = targetRef.current
if (!target) return
const handleCommand = (event: Event) => {
if ((event as CommandEvent).command === NAVIGATION_INVOKE_COMMAND) {
invoke()
}
}
target.addEventListener("command", handleCommand)
return () => target.removeEventListener("command", handleCommand)
}, [])
return (
<span
ref={targetRef}
id={`${NAVIGATION_ACTION_TARGET_PREFIX}${action}`}
hidden
/>
)
}