@f-ewald/components 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/custom-elements.json +1071 -79
- package/dist/action-bar.d.ts +24 -0
- package/dist/action-bar.d.ts.map +1 -0
- package/dist/action-bar.js +67 -0
- package/dist/action-bar.js.map +1 -0
- package/dist/app-shell.d.ts +86 -0
- package/dist/app-shell.d.ts.map +1 -0
- package/dist/app-shell.js +460 -0
- package/dist/app-shell.js.map +1 -0
- package/dist/app-sidebar.d.ts +44 -0
- package/dist/app-sidebar.d.ts.map +1 -0
- package/dist/app-sidebar.js +211 -0
- package/dist/app-sidebar.js.map +1 -0
- package/dist/content-divider.d.ts +23 -0
- package/dist/content-divider.d.ts.map +1 -0
- package/dist/content-divider.js +86 -0
- package/dist/content-divider.js.map +1 -0
- package/dist/form-actions.d.ts +27 -0
- package/dist/form-actions.d.ts.map +1 -0
- package/dist/form-actions.js +65 -0
- package/dist/form-actions.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +82 -5
- package/dist/mcp-server.js.map +1 -1
- package/dist/page-header.d.ts +27 -0
- package/dist/page-header.d.ts.map +1 -0
- package/dist/page-header.js +106 -0
- package/dist/page-header.js.map +1 -0
- package/dist/pagination-nav.d.ts +34 -0
- package/dist/pagination-nav.d.ts.map +1 -0
- package/dist/pagination-nav.js +144 -0
- package/dist/pagination-nav.js.map +1 -0
- package/dist/timeline-container.d.ts +22 -0
- package/dist/timeline-container.d.ts.map +1 -0
- package/dist/timeline-container.js +42 -0
- package/dist/timeline-container.js.map +1 -0
- package/dist/timeline-entry.d.ts +31 -0
- package/dist/timeline-entry.d.ts.map +1 -0
- package/dist/timeline-entry.js +170 -0
- package/dist/timeline-entry.js.map +1 -0
- package/docs/action-bar.md +41 -0
- package/docs/app-shell.md +85 -0
- package/docs/app-sidebar.md +69 -0
- package/docs/content-divider.md +47 -0
- package/docs/design-language.md +74 -1
- package/docs/form-actions.md +43 -0
- package/docs/layouts/detail-only.md +52 -0
- package/docs/layouts/form-page.md +52 -0
- package/docs/layouts/list-detail.md +52 -0
- package/docs/layouts/list-only.md +50 -0
- package/docs/layouts/record-detail.md +88 -0
- package/docs/mcp-evaluation.md +21 -0
- package/docs/page-header.md +47 -0
- package/docs/pagination-nav.md +54 -0
- package/docs/timeline-container.md +44 -0
- package/docs/timeline-entry.md +52 -0
- package/llms.txt +251 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell.js","sourceRoot":"","sources":["../src/app-shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { iconBars3 } from \"./icons.js\";\nimport \"./kbd-hint.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** Fired when the built-in toggle changes the sidebar state. */\nexport interface SidebarToggleDetail {\n /** Desktop rail state. */\n collapsed: boolean;\n /** Mobile drawer open state. */\n mobileOpen: boolean;\n}\n\n/**\n * The dashboard page shell: a slot-based CSS-grid backbone that arranges a\n * full-height sidebar, a top bar, the main content, an optional right-hand\n * detail column, and an optional footer. It owns the responsive behavior so\n * consumers don't re-implement it — above the shared 48rem breakpoint the\n * sidebar collapses to an icon rail and the detail region is an inline column;\n * at or below it the sidebar becomes an off-canvas drawer and the detail region\n * an overlay, both dismissed by a scrim or Escape.\n *\n * Widths are tunable per instance via `--component-sidebar-width` (16rem),\n * `--component-sidebar-rail-width` (3.5rem), and `--component-topbar-height`\n * (3rem); the detail column reuses the 20rem/25rem panel widths. The main\n * content area is white by default — override it with\n * `--component-main-background`. Give the shell a height (e.g. `height: 100vh`)\n * so the sidebar and main can size and scroll.\n *\n * The built-in top-bar button toggles the sidebar, and so does pressing `[`\n * anywhere on the page (ignored while typing in a text field or with a\n * modifier held). Hovering or keyboard-focusing the toggle reveals a tooltip\n * naming the action and its `[` shortcut — the shortcut is not shown as\n * permanent chrome.\n *\n * @element app-shell\n * @slot - Main content area.\n * @slot sidebar - Full-height navigation (typically `app-sidebar`).\n * @slot topbar - Top bar content, right of the built-in toggle.\n * @slot detail - Optional right-hand detail; shown when `detail-open` is set.\n * @slot footer - Optional footer beneath the main content.\n * @fires sidebar-toggle - The built-in toggle changed the sidebar state.\n * @fires detail-close - The scrim or Escape dismissed the mobile detail overlay.\n */\n@customElement(\"app-shell\")\nexport class AppShell extends LitElement {\n /** Collapses the sidebar to an icon rail on desktop. */\n @property({ type: Boolean, reflect: true, attribute: \"sidebar-collapsed\" })\n sidebarCollapsed = false;\n /** Shows the right-hand detail region (inline column, or overlay on mobile). */\n @property({ type: Boolean, reflect: true, attribute: \"detail-open\" }) detailOpen = false;\n /** Detail width: `compact` (20rem) or `comfortable` (25rem). */\n @property({ attribute: \"detail-width\" }) detailWidth: \"compact\" | \"comfortable\" = \"compact\";\n\n /** Whether the viewport is at/below the 48rem breakpoint. */\n @state() private _mobile = false;\n /** Whether the mobile off-canvas nav drawer is open. */\n @state() private _mobileNavOpen = false;\n /** Whether the footer slot has assigned content. */\n @state() private _hasFooter = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n block-size: 100%;\n }\n .shell {\n --_sidebar-w: var(--component-sidebar-width, 16rem);\n --_detail-w: 0px;\n display: grid;\n grid-template-columns: var(--_sidebar-w) minmax(0, 1fr) var(--_detail-w);\n grid-template-rows: auto minmax(0, 1fr) auto;\n grid-template-areas:\n \"sidebar topbar topbar\"\n \"sidebar main detail\"\n \"sidebar footer footer\";\n block-size: 100%;\n min-height: 0;\n background: var(--ui-surface, #ffffff);\n }\n :host([sidebar-collapsed]) .shell {\n --_sidebar-w: var(--component-sidebar-rail-width, 3.5rem);\n }\n :host([detail-open]) .shell {\n --_detail-w: 20rem;\n }\n :host([detail-open][detail-width=\"comfortable\"]) .shell {\n --_detail-w: 25rem;\n }\n .sidebar {\n grid-area: sidebar;\n min-height: 0;\n overflow: hidden;\n border-right: 1px solid var(--ui-border, #e2e8f0);\n background: var(--ui-surface, #ffffff);\n }\n .topbar {\n grid-area: topbar;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n min-height: var(--component-topbar-height, 3rem);\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n background: var(--ui-surface, #ffffff);\n }\n .nav-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 2rem;\n height: 2rem;\n padding: 0;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--ui-text-muted, #64748b);\n border-radius: var(--ui-radius-sm, 0.25rem);\n }\n .nav-group {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n flex: 0 0 auto;\n }\n .nav-tip {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 0.25rem;\n z-index: var(--component-layer-z, 100);\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n white-space: nowrap;\n padding: 0.25rem 0.5rem;\n border-radius: var(--ui-radius-sm, 0.25rem);\n background: var(--ui-tooltip, #0f172a);\n color: var(--ui-on-accent, #ffffff);\n box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));\n font-size: var(--ui-font-size-sm, 0.75rem);\n line-height: var(--ui-line-height-tight, 1.25);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition: opacity 120ms ease;\n }\n .nav-toggle:hover + .nav-tip,\n .nav-toggle:focus-visible + .nav-tip {\n opacity: 1;\n visibility: visible;\n }\n .nav-toggle:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .nav-toggle:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .topbar-content {\n flex: 1 1 auto;\n min-width: 0;\n }\n .main {\n grid-area: main;\n min-height: 0;\n min-width: 0;\n overflow: auto;\n padding: 1rem;\n background: var(--component-main-background, var(--ui-surface, #ffffff));\n }\n .detail {\n grid-area: detail;\n display: none;\n min-height: 0;\n overflow: auto;\n border-left: 1px solid var(--ui-border, #e2e8f0);\n background: var(--ui-surface, #ffffff);\n }\n :host([detail-open]) .detail {\n display: block;\n }\n .footer {\n grid-area: footer;\n padding: 0.5rem 0.75rem;\n border-top: 1px solid var(--ui-border, #e2e8f0);\n background: var(--ui-surface, #ffffff);\n }\n .footer.empty {\n display: none;\n }\n .scrim {\n display: none;\n }\n @media (max-width: 48rem) {\n .shell {\n grid-template-columns: minmax(0, 1fr);\n grid-template-rows: auto minmax(0, 1fr) auto;\n grid-template-areas:\n \"topbar\"\n \"main\"\n \"footer\";\n }\n .sidebar {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n width: var(--component-sidebar-width, 16rem);\n z-index: var(--component-layer-z, 100);\n transform: translateX(-100%);\n transition: transform 250ms ease;\n }\n .shell.nav-open .sidebar {\n transform: translateX(0);\n box-shadow: var(\n --ui-shadow-lg,\n 0 20px 25px -5px rgb(0 0 0 / 0.1),\n 0 8px 10px -6px rgb(0 0 0 / 0.1)\n );\n }\n .detail {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: var(--_detail-w, 20rem);\n max-width: calc(100vw - 3rem);\n z-index: var(--component-layer-z, 100);\n transform: translateX(110%);\n transition: transform 250ms ease;\n }\n :host([detail-open]) .detail {\n transform: translateX(0);\n box-shadow: var(\n --ui-shadow-lg,\n 0 20px 25px -5px rgb(0 0 0 / 0.1),\n 0 8px 10px -6px rgb(0 0 0 / 0.1)\n );\n }\n .scrim.show {\n display: block;\n position: fixed;\n inset: 0;\n z-index: calc(var(--component-layer-z, 100) - 1);\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n border: none;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .sidebar,\n .detail,\n .nav-tip {\n transition: none;\n }\n }\n @media (forced-colors: active) {\n .nav-toggle:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n .nav-tip {\n border: 1px solid CanvasText;\n }\n }\n `,\n ];\n\n private _mediaQuery: MediaQueryList | null = null;\n private _previousFocus: HTMLElement | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._mediaQuery = window.matchMedia(\"(max-width: 48rem)\");\n this._mobile = this._mediaQuery.matches;\n this._mediaQuery.addEventListener(\"change\", this._onMediaChange);\n window.addEventListener(\"keydown\", this._onKeydown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._mediaQuery?.removeEventListener(\"change\", this._onMediaChange);\n this._mediaQuery = null;\n window.removeEventListener(\"keydown\", this._onKeydown);\n }\n\n /** Tracks the breakpoint and closes the mobile drawer when returning to desktop. */\n private _onMediaChange = (event: MediaQueryListEvent): void => {\n this._mobile = event.matches;\n if (!event.matches) this._mobileNavOpen = false;\n };\n\n /** Handles the `[` sidebar shortcut and Escape dismissal of mobile overlays. */\n private _onKeydown = (event: KeyboardEvent): void => {\n if (event.defaultPrevented) return;\n if (event.key === \"Escape\" && this._mobile) {\n if (this.detailOpen) {\n event.preventDefault();\n this._closeDetail();\n } else if (this._mobileNavOpen) {\n event.preventDefault();\n this._mobileNavOpen = false;\n }\n return;\n }\n if (\n event.key === \"[\" &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey &&\n !this._isEditableTarget(event)\n ) {\n event.preventDefault();\n this._toggleSidebar();\n }\n };\n\n /** Whether the keydown originated in a text field, so the shortcut defers to typing. */\n private _isEditableTarget(event: KeyboardEvent): boolean {\n const target = event.composedPath()[0] as HTMLElement | undefined;\n if (!target) return false;\n if (target.isContentEditable) return true;\n const tag = target.tagName;\n return tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\";\n }\n\n /** Toggles the rail (desktop) or the off-canvas drawer (mobile) and announces it. */\n private _toggleSidebar(): void {\n if (this._mobile) {\n this._mobileNavOpen = !this._mobileNavOpen;\n if (this._mobileNavOpen) this._previousFocus = document.activeElement as HTMLElement | null;\n } else {\n this.sidebarCollapsed = !this.sidebarCollapsed;\n }\n this.dispatchEvent(\n new CustomEvent<SidebarToggleDetail>(\"sidebar-toggle\", {\n detail: { collapsed: this.sidebarCollapsed, mobileOpen: this._mobileNavOpen },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** Closes the detail overlay and notifies the consumer that owns `detail-open`. */\n private _closeDetail(): void {\n this.detailOpen = false;\n this.dispatchEvent(new CustomEvent(\"detail-close\", { bubbles: true, composed: true }));\n }\n\n /** Scrim click dismisses whichever overlay is open. */\n private _onScrim(): void {\n if (this.detailOpen) this._closeDetail();\n if (this._mobileNavOpen) this._mobileNavOpen = false;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"sidebarCollapsed\") || changed.has(\"_mobile\")) this._syncSidebar();\n if (!changed.has(\"_mobileNavOpen\")) return;\n if (this._mobileNavOpen) {\n this.shadowRoot?.querySelector<HTMLElement>(\".sidebar\")?.focus();\n return;\n }\n if (this._previousFocus?.isConnected) this._previousFocus.focus();\n this._previousFocus = null;\n }\n\n /**\n * Mirrors the shell's rail state onto the slotted sidebar so it hides labels\n * when collapsed on desktop, and always shows them in the mobile drawer.\n */\n private _syncSidebar(): void {\n const rail = this.sidebarCollapsed && !this._mobile;\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"sidebar\"]');\n for (const element of slot?.assignedElements() ?? []) {\n element.toggleAttribute(\"collapsed\", rail);\n }\n }\n\n override render() {\n const scrimActive = this._mobile && (this._mobileNavOpen || this.detailOpen);\n return html`\n <div class=\"shell ${this._mobileNavOpen ? \"nav-open\" : \"\"}\">\n <aside class=\"sidebar\" tabindex=\"-1\" aria-label=\"Primary\">\n <slot name=\"sidebar\" @slotchange=${this._syncSidebar}></slot>\n </aside>\n <header class=\"topbar\">\n <div class=\"nav-group\">\n <button\n class=\"nav-toggle\"\n type=\"button\"\n aria-label=\"Toggle navigation\"\n aria-keyshortcuts=\"[\"\n aria-describedby=\"nav-tip\"\n aria-expanded=${this._mobile ? String(this._mobileNavOpen) : String(!this.sidebarCollapsed)}\n @click=${this._toggleSidebar}\n >\n ${iconBars3(18)}\n </button>\n <span class=\"nav-tip\" id=\"nav-tip\" role=\"tooltip\">\n <span\n >${this._mobile\n ? \"Navigation\"\n : this.sidebarCollapsed\n ? \"Expand sidebar\"\n : \"Collapse sidebar\"}</span\n >\n ${this._mobile ? nothing : html`<kbd-hint keys=\"[\"></kbd-hint>`}\n </span>\n </div>\n <div class=\"topbar-content\"><slot name=\"topbar\"></slot></div>\n </header>\n <main class=\"main\"><slot></slot></main>\n <aside\n class=\"detail\"\n aria-label=\"Detail\"\n ?inert=${!this.detailOpen}\n aria-hidden=${String(!this.detailOpen)}\n >\n <slot name=\"detail\"></slot>\n </aside>\n <footer class=\"footer ${this._hasFooter ? \"\" : \"empty\"}\">\n <slot name=\"footer\" @slotchange=${this._onFooterSlotChange}></slot>\n </footer>\n <button\n class=\"scrim ${scrimActive ? \"show\" : \"\"}\"\n type=\"button\"\n tabindex=\"-1\"\n aria-label=\"Close\"\n @click=${this._onScrim}\n ?hidden=${!scrimActive}\n ></button>\n </div>\n `;\n }\n\n /** Collapses the footer row when nothing is slotted into it. */\n private _onFooterSlotChange(event: Event): void {\n this._hasFooter = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"app-shell\": AppShell;\n }\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* Collapsible navigation sidebar for the `app-shell` sidebar slot. It is
|
|
4
|
+
* deliberately presentational and router-agnostic: the consumer supplies the
|
|
5
|
+
* nav items as plain `<a>`/`<button>` elements (each an icon followed by a
|
|
6
|
+
* label), optional `<p>` group headings, and marks the active item with
|
|
7
|
+
* `aria-current="page"`. The sidebar styles them, tracks hover/active/focus,
|
|
8
|
+
* and — in collapsed "rail" mode — centers the icons and hides the labels.
|
|
9
|
+
*
|
|
10
|
+
* Rail mode is driven by the `collapsed` attribute (the parent `app-shell`
|
|
11
|
+
* toggles it). Labels are hidden by the inherited `--app-sidebar-label` custom
|
|
12
|
+
* property, so each label element should read it, e.g.
|
|
13
|
+
* `<span style="display: var(--app-sidebar-label, inline)">Reports</span>`;
|
|
14
|
+
* keep an `aria-label` on the item so its accessible name survives collapse.
|
|
15
|
+
* The sidebar fills the width and height of its container — `app-shell` owns
|
|
16
|
+
* the actual rail/expanded width.
|
|
17
|
+
*
|
|
18
|
+
* @element app-sidebar
|
|
19
|
+
* @slot - Navigation items: `<a>`/`<button>` links and optional `<p>` headings.
|
|
20
|
+
* @slot header - Optional brand pinned to the top: a small logo plus a name.
|
|
21
|
+
* Wrap the name in a `--app-sidebar-label` element so rail mode shows only the
|
|
22
|
+
* logo, centered in line with the nav icons.
|
|
23
|
+
* @slot footer - Optional account/settings area pinned to the bottom.
|
|
24
|
+
*/
|
|
25
|
+
export declare class AppSidebar extends LitElement {
|
|
26
|
+
/** Collapses the sidebar to an icon rail (centers icons, hides labels). */
|
|
27
|
+
collapsed: boolean;
|
|
28
|
+
/** Whether the header slot has assigned content. */
|
|
29
|
+
private _hasHeader;
|
|
30
|
+
/** Whether the footer slot has assigned content. */
|
|
31
|
+
private _hasFooter;
|
|
32
|
+
static styles: import("lit").CSSResult[];
|
|
33
|
+
/** Collapses the header row when nothing is slotted into it. */
|
|
34
|
+
private _onHeaderSlotChange;
|
|
35
|
+
/** Collapses the footer row when nothing is slotted into it. */
|
|
36
|
+
private _onFooterSlotChange;
|
|
37
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
38
|
+
}
|
|
39
|
+
declare global {
|
|
40
|
+
interface HTMLElementTagNameMap {
|
|
41
|
+
"app-sidebar": AppSidebar;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=app-sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-sidebar.d.ts","sourceRoot":"","sources":["../src/app-sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,2EAA2E;IAC/B,SAAS,UAAS;IAE9D,oDAAoD;IAC3C,OAAO,CAAC,UAAU,CAAS;IACpC,oDAAoD;IAC3C,OAAO,CAAC,UAAU,CAAS;IAEpC,OAAgB,MAAM,4BAkIpB;IAEF,gEAAgE;IAChE,OAAO,CAAC,mBAAmB;IAI3B,gEAAgE;IAChE,OAAO,CAAC,mBAAmB;IAIlB,MAAM,yCAcd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from "lit";
|
|
8
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
9
|
+
import { tokens } from "./tokens.js";
|
|
10
|
+
/**
|
|
11
|
+
* Collapsible navigation sidebar for the `app-shell` sidebar slot. It is
|
|
12
|
+
* deliberately presentational and router-agnostic: the consumer supplies the
|
|
13
|
+
* nav items as plain `<a>`/`<button>` elements (each an icon followed by a
|
|
14
|
+
* label), optional `<p>` group headings, and marks the active item with
|
|
15
|
+
* `aria-current="page"`. The sidebar styles them, tracks hover/active/focus,
|
|
16
|
+
* and — in collapsed "rail" mode — centers the icons and hides the labels.
|
|
17
|
+
*
|
|
18
|
+
* Rail mode is driven by the `collapsed` attribute (the parent `app-shell`
|
|
19
|
+
* toggles it). Labels are hidden by the inherited `--app-sidebar-label` custom
|
|
20
|
+
* property, so each label element should read it, e.g.
|
|
21
|
+
* `<span style="display: var(--app-sidebar-label, inline)">Reports</span>`;
|
|
22
|
+
* keep an `aria-label` on the item so its accessible name survives collapse.
|
|
23
|
+
* The sidebar fills the width and height of its container — `app-shell` owns
|
|
24
|
+
* the actual rail/expanded width.
|
|
25
|
+
*
|
|
26
|
+
* @element app-sidebar
|
|
27
|
+
* @slot - Navigation items: `<a>`/`<button>` links and optional `<p>` headings.
|
|
28
|
+
* @slot header - Optional brand pinned to the top: a small logo plus a name.
|
|
29
|
+
* Wrap the name in a `--app-sidebar-label` element so rail mode shows only the
|
|
30
|
+
* logo, centered in line with the nav icons.
|
|
31
|
+
* @slot footer - Optional account/settings area pinned to the bottom.
|
|
32
|
+
*/
|
|
33
|
+
let AppSidebar = class AppSidebar extends LitElement {
|
|
34
|
+
constructor() {
|
|
35
|
+
super(...arguments);
|
|
36
|
+
/** Collapses the sidebar to an icon rail (centers icons, hides labels). */
|
|
37
|
+
this.collapsed = false;
|
|
38
|
+
/** Whether the header slot has assigned content. */
|
|
39
|
+
this._hasHeader = false;
|
|
40
|
+
/** Whether the footer slot has assigned content. */
|
|
41
|
+
this._hasFooter = false;
|
|
42
|
+
}
|
|
43
|
+
static { this.styles = [
|
|
44
|
+
tokens,
|
|
45
|
+
css `
|
|
46
|
+
:host {
|
|
47
|
+
display: block;
|
|
48
|
+
height: 100%;
|
|
49
|
+
--app-sidebar-label: inline;
|
|
50
|
+
}
|
|
51
|
+
:host([collapsed]) {
|
|
52
|
+
--app-sidebar-label: none;
|
|
53
|
+
}
|
|
54
|
+
.sidebar {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
height: 100%;
|
|
58
|
+
min-height: 0;
|
|
59
|
+
background: var(--ui-surface, #ffffff);
|
|
60
|
+
color: var(--ui-text, #0f172a);
|
|
61
|
+
font-family: var(
|
|
62
|
+
--ui-font,
|
|
63
|
+
ui-sans-serif,
|
|
64
|
+
system-ui,
|
|
65
|
+
sans-serif,
|
|
66
|
+
"Apple Color Emoji",
|
|
67
|
+
"Segoe UI Emoji",
|
|
68
|
+
"Segoe UI Symbol",
|
|
69
|
+
"Noto Color Emoji"
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
.brand {
|
|
73
|
+
flex: 0 0 auto;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
padding: 0.75rem;
|
|
77
|
+
border-bottom: 1px solid var(--ui-border, #e2e8f0);
|
|
78
|
+
}
|
|
79
|
+
.foot {
|
|
80
|
+
flex: 0 0 auto;
|
|
81
|
+
padding: 0.75rem;
|
|
82
|
+
border-top: 1px solid var(--ui-border, #e2e8f0);
|
|
83
|
+
}
|
|
84
|
+
.brand.empty,
|
|
85
|
+
.foot.empty {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
.nav {
|
|
89
|
+
flex: 1 1 auto;
|
|
90
|
+
min-height: 0;
|
|
91
|
+
overflow-y: auto;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: 0.25rem;
|
|
95
|
+
padding: 0.5rem;
|
|
96
|
+
}
|
|
97
|
+
::slotted(a),
|
|
98
|
+
::slotted(button) {
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
gap: 0.5rem;
|
|
102
|
+
width: 100%;
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
padding: 0.5rem;
|
|
105
|
+
border: none;
|
|
106
|
+
border-radius: var(--ui-radius-sm, 0.25rem);
|
|
107
|
+
background: none;
|
|
108
|
+
color: var(--ui-text, #0f172a);
|
|
109
|
+
text-align: left;
|
|
110
|
+
text-decoration: none;
|
|
111
|
+
white-space: nowrap;
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
114
|
+
font-weight: var(--ui-font-weight-medium, 500);
|
|
115
|
+
line-height: var(--ui-line-height-tight, 1.25);
|
|
116
|
+
font-family: var(
|
|
117
|
+
--ui-font,
|
|
118
|
+
ui-sans-serif,
|
|
119
|
+
system-ui,
|
|
120
|
+
sans-serif,
|
|
121
|
+
"Apple Color Emoji",
|
|
122
|
+
"Segoe UI Emoji",
|
|
123
|
+
"Segoe UI Symbol",
|
|
124
|
+
"Noto Color Emoji"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
::slotted(a:hover),
|
|
128
|
+
::slotted(button:hover) {
|
|
129
|
+
background: var(--ui-surface-muted, #f8fafc);
|
|
130
|
+
}
|
|
131
|
+
::slotted(a[aria-current]),
|
|
132
|
+
::slotted(button[aria-current]) {
|
|
133
|
+
background: var(--ui-surface-muted, #f8fafc);
|
|
134
|
+
color: var(--ui-primary, #4f46e5);
|
|
135
|
+
font-weight: var(--ui-font-weight-semibold, 600);
|
|
136
|
+
}
|
|
137
|
+
::slotted(a:focus-visible),
|
|
138
|
+
::slotted(button:focus-visible) {
|
|
139
|
+
outline: none;
|
|
140
|
+
box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
|
|
141
|
+
}
|
|
142
|
+
::slotted(p) {
|
|
143
|
+
margin: 0;
|
|
144
|
+
padding: 0.5rem 0.5rem 0.25rem;
|
|
145
|
+
font-size: var(--ui-font-size-xs, 0.6875rem);
|
|
146
|
+
font-weight: var(--ui-font-weight-semibold, 600);
|
|
147
|
+
line-height: var(--ui-line-height-tight, 1.25);
|
|
148
|
+
text-transform: uppercase;
|
|
149
|
+
letter-spacing: var(--ui-tracking-wide, 0.04em);
|
|
150
|
+
color: var(--ui-text-muted, #64748b);
|
|
151
|
+
}
|
|
152
|
+
:host([collapsed]) ::slotted(a),
|
|
153
|
+
:host([collapsed]) ::slotted(button) {
|
|
154
|
+
justify-content: center;
|
|
155
|
+
}
|
|
156
|
+
:host([collapsed]) ::slotted(p) {
|
|
157
|
+
display: none;
|
|
158
|
+
}
|
|
159
|
+
:host([collapsed]) .brand {
|
|
160
|
+
justify-content: center;
|
|
161
|
+
padding-left: 0.5rem;
|
|
162
|
+
padding-right: 0.5rem;
|
|
163
|
+
}
|
|
164
|
+
@media (forced-colors: active) {
|
|
165
|
+
::slotted(a:focus-visible),
|
|
166
|
+
::slotted(button:focus-visible) {
|
|
167
|
+
outline: 2px solid CanvasText;
|
|
168
|
+
outline-offset: 2px;
|
|
169
|
+
box-shadow: none;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
`,
|
|
173
|
+
]; }
|
|
174
|
+
/** Collapses the header row when nothing is slotted into it. */
|
|
175
|
+
_onHeaderSlotChange(event) {
|
|
176
|
+
this._hasHeader = event.target.assignedNodes({ flatten: true }).length > 0;
|
|
177
|
+
}
|
|
178
|
+
/** Collapses the footer row when nothing is slotted into it. */
|
|
179
|
+
_onFooterSlotChange(event) {
|
|
180
|
+
this._hasFooter = event.target.assignedNodes({ flatten: true }).length > 0;
|
|
181
|
+
}
|
|
182
|
+
render() {
|
|
183
|
+
return html `
|
|
184
|
+
<div class="sidebar">
|
|
185
|
+
<div class="brand ${this._hasHeader ? "" : "empty"}">
|
|
186
|
+
<slot name="header" @slotchange=${this._onHeaderSlotChange}></slot>
|
|
187
|
+
</div>
|
|
188
|
+
<nav class="nav" aria-label="Sidebar">
|
|
189
|
+
<slot></slot>
|
|
190
|
+
</nav>
|
|
191
|
+
<div class="foot ${this._hasFooter ? "" : "empty"}">
|
|
192
|
+
<slot name="footer" @slotchange=${this._onFooterSlotChange}></slot>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
__decorate([
|
|
199
|
+
property({ type: Boolean, reflect: true })
|
|
200
|
+
], AppSidebar.prototype, "collapsed", void 0);
|
|
201
|
+
__decorate([
|
|
202
|
+
state()
|
|
203
|
+
], AppSidebar.prototype, "_hasHeader", void 0);
|
|
204
|
+
__decorate([
|
|
205
|
+
state()
|
|
206
|
+
], AppSidebar.prototype, "_hasFooter", void 0);
|
|
207
|
+
AppSidebar = __decorate([
|
|
208
|
+
customElement("app-sidebar")
|
|
209
|
+
], AppSidebar);
|
|
210
|
+
export { AppSidebar };
|
|
211
|
+
//# sourceMappingURL=app-sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-sidebar.js","sourceRoot":"","sources":["../src/app-sidebar.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QACL,2EAA2E;QAC/B,cAAS,GAAG,KAAK,CAAC;QAE9D,oDAAoD;QACnC,eAAU,GAAG,KAAK,CAAC;QACpC,oDAAoD;QACnC,eAAU,GAAG,KAAK,CAAC;IA+JtC,CAAC;aA7JiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+HF;KACF,AAlIqB,CAkIpB;IAEF,gEAAgE;IACxD,mBAAmB,CAAC,KAAY;QACtC,IAAI,CAAC,UAAU,GAAI,KAAK,CAAC,MAA0B,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAClG,CAAC;IAED,gEAAgE;IACxD,mBAAmB,CAAC,KAAY;QACtC,IAAI,CAAC,UAAU,GAAI,KAAK,CAAC,MAA0B,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAClG,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;4BAEa,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;4CACd,IAAI,CAAC,mBAAmB;;;;;2BAKzC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;4CACb,IAAI,CAAC,mBAAmB;;;KAG/D,CAAC;IACJ,CAAC;CACF,CAAA;AApK6C;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;6CAAmB;AAG7C;IAAhB,KAAK,EAAE;8CAA4B;AAEnB;IAAhB,KAAK,EAAE;8CAA4B;AAPzB,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAsKtB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Collapsible navigation sidebar for the `app-shell` sidebar slot. It is\n * deliberately presentational and router-agnostic: the consumer supplies the\n * nav items as plain `<a>`/`<button>` elements (each an icon followed by a\n * label), optional `<p>` group headings, and marks the active item with\n * `aria-current=\"page\"`. The sidebar styles them, tracks hover/active/focus,\n * and — in collapsed \"rail\" mode — centers the icons and hides the labels.\n *\n * Rail mode is driven by the `collapsed` attribute (the parent `app-shell`\n * toggles it). Labels are hidden by the inherited `--app-sidebar-label` custom\n * property, so each label element should read it, e.g.\n * `<span style=\"display: var(--app-sidebar-label, inline)\">Reports</span>`;\n * keep an `aria-label` on the item so its accessible name survives collapse.\n * The sidebar fills the width and height of its container — `app-shell` owns\n * the actual rail/expanded width.\n *\n * @element app-sidebar\n * @slot - Navigation items: `<a>`/`<button>` links and optional `<p>` headings.\n * @slot header - Optional brand pinned to the top: a small logo plus a name.\n * Wrap the name in a `--app-sidebar-label` element so rail mode shows only the\n * logo, centered in line with the nav icons.\n * @slot footer - Optional account/settings area pinned to the bottom.\n */\n@customElement(\"app-sidebar\")\nexport class AppSidebar extends LitElement {\n /** Collapses the sidebar to an icon rail (centers icons, hides labels). */\n @property({ type: Boolean, reflect: true }) collapsed = false;\n\n /** Whether the header slot has assigned content. */\n @state() private _hasHeader = false;\n /** Whether the footer slot has assigned content. */\n @state() private _hasFooter = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n height: 100%;\n --app-sidebar-label: inline;\n }\n :host([collapsed]) {\n --app-sidebar-label: none;\n }\n .sidebar {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--ui-surface, #ffffff);\n color: var(--ui-text, #0f172a);\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n .brand {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n padding: 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n }\n .foot {\n flex: 0 0 auto;\n padding: 0.75rem;\n border-top: 1px solid var(--ui-border, #e2e8f0);\n }\n .brand.empty,\n .foot.empty {\n display: none;\n }\n .nav {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n padding: 0.5rem;\n }\n ::slotted(a),\n ::slotted(button) {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n box-sizing: border-box;\n padding: 0.5rem;\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n background: none;\n color: var(--ui-text, #0f172a);\n text-align: left;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n ::slotted(a:hover),\n ::slotted(button:hover) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n ::slotted(a[aria-current]),\n ::slotted(button[aria-current]) {\n background: var(--ui-surface-muted, #f8fafc);\n color: var(--ui-primary, #4f46e5);\n font-weight: var(--ui-font-weight-semibold, 600);\n }\n ::slotted(a:focus-visible),\n ::slotted(button:focus-visible) {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n ::slotted(p) {\n margin: 0;\n padding: 0.5rem 0.5rem 0.25rem;\n font-size: var(--ui-font-size-xs, 0.6875rem);\n font-weight: var(--ui-font-weight-semibold, 600);\n line-height: var(--ui-line-height-tight, 1.25);\n text-transform: uppercase;\n letter-spacing: var(--ui-tracking-wide, 0.04em);\n color: var(--ui-text-muted, #64748b);\n }\n :host([collapsed]) ::slotted(a),\n :host([collapsed]) ::slotted(button) {\n justify-content: center;\n }\n :host([collapsed]) ::slotted(p) {\n display: none;\n }\n :host([collapsed]) .brand {\n justify-content: center;\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n }\n @media (forced-colors: active) {\n ::slotted(a:focus-visible),\n ::slotted(button:focus-visible) {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n /** Collapses the header row when nothing is slotted into it. */\n private _onHeaderSlotChange(event: Event): void {\n this._hasHeader = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n }\n\n /** Collapses the footer row when nothing is slotted into it. */\n private _onFooterSlotChange(event: Event): void {\n this._hasFooter = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n }\n\n override render() {\n return html`\n <div class=\"sidebar\">\n <div class=\"brand ${this._hasHeader ? \"\" : \"empty\"}\">\n <slot name=\"header\" @slotchange=${this._onHeaderSlotChange}></slot>\n </div>\n <nav class=\"nav\" aria-label=\"Sidebar\">\n <slot></slot>\n </nav>\n <div class=\"foot ${this._hasFooter ? \"\" : \"empty\"}\">\n <slot name=\"footer\" @slotchange=${this._onFooterSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"app-sidebar\": AppSidebar;\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* A horizontal divider: a thin rule that visually separates two pieces of
|
|
4
|
+
* content that are not otherwise contained in a box or frame and would bleed
|
|
5
|
+
* into each other. With a `label` it renders the common "─── OR ───"
|
|
6
|
+
* pattern — text centered between two line segments; without one it is a
|
|
7
|
+
* single full-width rule. Exposed to assistive technology as a horizontal
|
|
8
|
+
* separator, so it renders correctly with zero external CSS.
|
|
9
|
+
*
|
|
10
|
+
* @element content-divider
|
|
11
|
+
*/
|
|
12
|
+
export declare class ContentDivider extends LitElement {
|
|
13
|
+
static styles: import("lit").CSSResult[];
|
|
14
|
+
/** Optional centered label; empty renders a plain full-width rule. */
|
|
15
|
+
label: string;
|
|
16
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
17
|
+
}
|
|
18
|
+
declare global {
|
|
19
|
+
interface HTMLElementTagNameMap {
|
|
20
|
+
"content-divider": ContentDivider;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=content-divider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-divider.d.ts","sourceRoot":"","sources":["../src/content-divider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAIrD;;;;;;;;;GASG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,OAAgB,MAAM,4BAkCpB;IAEF,sEAAsE;IAC1D,KAAK,SAAM;IAEd,MAAM,yCAgBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html, nothing } from "lit";
|
|
8
|
+
import { customElement, property } from "lit/decorators.js";
|
|
9
|
+
import { tokens } from "./tokens.js";
|
|
10
|
+
/**
|
|
11
|
+
* A horizontal divider: a thin rule that visually separates two pieces of
|
|
12
|
+
* content that are not otherwise contained in a box or frame and would bleed
|
|
13
|
+
* into each other. With a `label` it renders the common "─── OR ───"
|
|
14
|
+
* pattern — text centered between two line segments; without one it is a
|
|
15
|
+
* single full-width rule. Exposed to assistive technology as a horizontal
|
|
16
|
+
* separator, so it renders correctly with zero external CSS.
|
|
17
|
+
*
|
|
18
|
+
* @element content-divider
|
|
19
|
+
*/
|
|
20
|
+
let ContentDivider = class ContentDivider extends LitElement {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
/** Optional centered label; empty renders a plain full-width rule. */
|
|
24
|
+
this.label = "";
|
|
25
|
+
}
|
|
26
|
+
static { this.styles = [
|
|
27
|
+
tokens,
|
|
28
|
+
css `
|
|
29
|
+
:host {
|
|
30
|
+
display: block;
|
|
31
|
+
margin: 1rem 0;
|
|
32
|
+
}
|
|
33
|
+
.rule {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: 0.75rem;
|
|
37
|
+
}
|
|
38
|
+
.line {
|
|
39
|
+
flex: 1 1 auto;
|
|
40
|
+
border-top: 1px solid var(--ui-border, #e2e8f0);
|
|
41
|
+
}
|
|
42
|
+
.label {
|
|
43
|
+
flex: 0 0 auto;
|
|
44
|
+
color: var(--ui-text-muted, #64748b);
|
|
45
|
+
font-family: var(
|
|
46
|
+
--ui-font,
|
|
47
|
+
ui-sans-serif,
|
|
48
|
+
system-ui,
|
|
49
|
+
sans-serif,
|
|
50
|
+
"Apple Color Emoji",
|
|
51
|
+
"Segoe UI Emoji",
|
|
52
|
+
"Segoe UI Symbol",
|
|
53
|
+
"Noto Color Emoji"
|
|
54
|
+
);
|
|
55
|
+
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
56
|
+
font-weight: var(--ui-font-weight-medium, 500);
|
|
57
|
+
line-height: var(--ui-line-height-tight, 1.25);
|
|
58
|
+
}
|
|
59
|
+
`,
|
|
60
|
+
]; }
|
|
61
|
+
render() {
|
|
62
|
+
const hasLabel = this.label.trim().length > 0;
|
|
63
|
+
return html `
|
|
64
|
+
<div
|
|
65
|
+
class="rule"
|
|
66
|
+
role="separator"
|
|
67
|
+
aria-orientation="horizontal"
|
|
68
|
+
aria-label=${hasLabel ? this.label : nothing}
|
|
69
|
+
>
|
|
70
|
+
<span class="line"></span>
|
|
71
|
+
${hasLabel
|
|
72
|
+
? html `<span class="label" aria-hidden="true">${this.label}</span>
|
|
73
|
+
<span class="line"></span>`
|
|
74
|
+
: nothing}
|
|
75
|
+
</div>
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
__decorate([
|
|
80
|
+
property()
|
|
81
|
+
], ContentDivider.prototype, "label", void 0);
|
|
82
|
+
ContentDivider = __decorate([
|
|
83
|
+
customElement("content-divider")
|
|
84
|
+
], ContentDivider);
|
|
85
|
+
export { ContentDivider };
|
|
86
|
+
//# sourceMappingURL=content-divider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-divider.js","sourceRoot":"","sources":["../src/content-divider.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;GASG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QAqCL,sEAAsE;QAC1D,UAAK,GAAG,EAAE,CAAC;IAmBzB,CAAC;aAxDiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+BF;KACF,AAlCqB,CAkCpB;IAKO,MAAM;QACb,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAA;;;;;qBAKM,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO;;;UAG1C,QAAQ;YACR,CAAC,CAAC,IAAI,CAAA,0CAA0C,IAAI,CAAC,KAAK;yCAC3B;YAC/B,CAAC,CAAC,OAAO;;KAEd,CAAC;IACJ,CAAC;CACF,CAAA;AAnBa;IAAX,QAAQ,EAAE;6CAAY;AAtCZ,cAAc;IAD1B,aAAa,CAAC,iBAAiB,CAAC;GACpB,cAAc,CAyD1B","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A horizontal divider: a thin rule that visually separates two pieces of\n * content that are not otherwise contained in a box or frame and would bleed\n * into each other. With a `label` it renders the common \"─── OR ───\"\n * pattern — text centered between two line segments; without one it is a\n * single full-width rule. Exposed to assistive technology as a horizontal\n * separator, so it renders correctly with zero external CSS.\n *\n * @element content-divider\n */\n@customElement(\"content-divider\")\nexport class ContentDivider extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n margin: 1rem 0;\n }\n .rule {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n }\n .line {\n flex: 1 1 auto;\n border-top: 1px solid var(--ui-border, #e2e8f0);\n }\n .label {\n flex: 0 0 auto;\n color: var(--ui-text-muted, #64748b);\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n }\n `,\n ];\n\n /** Optional centered label; empty renders a plain full-width rule. */\n @property() label = \"\";\n\n override render() {\n const hasLabel = this.label.trim().length > 0;\n return html`\n <div\n class=\"rule\"\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label=${hasLabel ? this.label : nothing}\n >\n <span class=\"line\"></span>\n ${hasLabel\n ? html`<span class=\"label\" aria-hidden=\"true\">${this.label}</span>\n <span class=\"line\"></span>`\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"content-divider\": ContentDivider;\n }\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* Form footer button bar with a fixed action order for internal apps: the
|
|
4
|
+
* primary (submit) button is always rightmost, the secondary (cancel) button
|
|
5
|
+
* sits to its immediate left, and an optional tertiary/destructive action is
|
|
6
|
+
* pinned to the far left. The order is enforced by the component regardless of
|
|
7
|
+
* the source order the buttons are authored in, so every form in a product
|
|
8
|
+
* reads the same way.
|
|
9
|
+
*
|
|
10
|
+
* Purely presentational: it lays out whatever controls (usually `ui-button`)
|
|
11
|
+
* are slotted and never intercepts their clicks, `type="submit"`, or events.
|
|
12
|
+
*
|
|
13
|
+
* @element form-actions
|
|
14
|
+
* @slot start - Optional far-left action (e.g. a destructive "Delete").
|
|
15
|
+
* @slot secondary - The secondary/cancel action, placed left of primary.
|
|
16
|
+
* @slot primary - The primary/submit action, always rightmost.
|
|
17
|
+
*/
|
|
18
|
+
export declare class FormActions extends LitElement {
|
|
19
|
+
static styles: import("lit").CSSResult[];
|
|
20
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
21
|
+
}
|
|
22
|
+
declare global {
|
|
23
|
+
interface HTMLElementTagNameMap {
|
|
24
|
+
"form-actions": FormActions;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=form-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-actions.d.ts","sourceRoot":"","sources":["../src/form-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;;;;;;;;;;;;GAeG;AACH,qBACa,WAAY,SAAQ,UAAU;IACzC,OAAgB,MAAM,4BAuBpB;IAEO,MAAM,yCAQd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,WAAW,CAAC;KAC7B;CACF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from "lit";
|
|
8
|
+
import { customElement } from "lit/decorators.js";
|
|
9
|
+
import { tokens } from "./tokens.js";
|
|
10
|
+
/**
|
|
11
|
+
* Form footer button bar with a fixed action order for internal apps: the
|
|
12
|
+
* primary (submit) button is always rightmost, the secondary (cancel) button
|
|
13
|
+
* sits to its immediate left, and an optional tertiary/destructive action is
|
|
14
|
+
* pinned to the far left. The order is enforced by the component regardless of
|
|
15
|
+
* the source order the buttons are authored in, so every form in a product
|
|
16
|
+
* reads the same way.
|
|
17
|
+
*
|
|
18
|
+
* Purely presentational: it lays out whatever controls (usually `ui-button`)
|
|
19
|
+
* are slotted and never intercepts their clicks, `type="submit"`, or events.
|
|
20
|
+
*
|
|
21
|
+
* @element form-actions
|
|
22
|
+
* @slot start - Optional far-left action (e.g. a destructive "Delete").
|
|
23
|
+
* @slot secondary - The secondary/cancel action, placed left of primary.
|
|
24
|
+
* @slot primary - The primary/submit action, always rightmost.
|
|
25
|
+
*/
|
|
26
|
+
let FormActions = class FormActions extends LitElement {
|
|
27
|
+
static { this.styles = [
|
|
28
|
+
tokens,
|
|
29
|
+
css `
|
|
30
|
+
:host {
|
|
31
|
+
display: block;
|
|
32
|
+
}
|
|
33
|
+
.actions {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-wrap: wrap;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: flex-end;
|
|
38
|
+
gap: 0.5rem;
|
|
39
|
+
}
|
|
40
|
+
.start {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 0.5rem;
|
|
44
|
+
margin-right: auto;
|
|
45
|
+
}
|
|
46
|
+
::slotted(*) {
|
|
47
|
+
margin: 0;
|
|
48
|
+
}
|
|
49
|
+
`,
|
|
50
|
+
]; }
|
|
51
|
+
render() {
|
|
52
|
+
return html `
|
|
53
|
+
<div class="actions">
|
|
54
|
+
<span class="start"><slot name="start"></slot></span>
|
|
55
|
+
<slot name="secondary"></slot>
|
|
56
|
+
<slot name="primary"></slot>
|
|
57
|
+
</div>
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
FormActions = __decorate([
|
|
62
|
+
customElement("form-actions")
|
|
63
|
+
], FormActions);
|
|
64
|
+
export { FormActions };
|
|
65
|
+
//# sourceMappingURL=form-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-actions.js","sourceRoot":"","sources":["../src/form-actions.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;GAeG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;aACzB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;KAoBF;KACF,AAvBqB,CAuBpB;IAEO,MAAM;QACb,OAAO,IAAI,CAAA;;;;;;KAMV,CAAC;IACJ,CAAC;CACF,CAAA;AAnCY,WAAW;IADvB,aAAa,CAAC,cAAc,CAAC;GACjB,WAAW,CAmCvB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Form footer button bar with a fixed action order for internal apps: the\n * primary (submit) button is always rightmost, the secondary (cancel) button\n * sits to its immediate left, and an optional tertiary/destructive action is\n * pinned to the far left. The order is enforced by the component regardless of\n * the source order the buttons are authored in, so every form in a product\n * reads the same way.\n *\n * Purely presentational: it lays out whatever controls (usually `ui-button`)\n * are slotted and never intercepts their clicks, `type=\"submit\"`, or events.\n *\n * @element form-actions\n * @slot start - Optional far-left action (e.g. a destructive \"Delete\").\n * @slot secondary - The secondary/cancel action, placed left of primary.\n * @slot primary - The primary/submit action, always rightmost.\n */\n@customElement(\"form-actions\")\nexport class FormActions extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: 0.5rem;\n }\n .start {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-right: auto;\n }\n ::slotted(*) {\n margin: 0;\n }\n `,\n ];\n\n override render() {\n return html`\n <div class=\"actions\">\n <span class=\"start\"><slot name=\"start\"></slot></span>\n <slot name=\"secondary\"></slot>\n <slot name=\"primary\"></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"form-actions\": FormActions;\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { PhotoGallery, type PhotoGalleryChangeReason, type PhotoGalleryObjectFit
|
|
|
5
5
|
export { RevealButton } from "./reveal-button.js";
|
|
6
6
|
export { RomanNumeral } from "./roman-numeral.js";
|
|
7
7
|
export { ConfirmDialog } from "./confirm-dialog.js";
|
|
8
|
+
export { ContentDivider } from "./content-divider.js";
|
|
8
9
|
export { ToastNotification, notifySuccess, notifyError, notifyInfo, type ToastVariant, } from "./toast-notification.js";
|
|
9
10
|
export { SlidePanel } from "./slide-panel.js";
|
|
10
11
|
export { CopyLinkButton } from "./copy-link-button.js";
|
|
@@ -36,6 +37,14 @@ export { DropdownButton, type DropdownOption } from "./dropdown-button.js";
|
|
|
36
37
|
export { IconButton } from "./icon-button.js";
|
|
37
38
|
export { KbdHint, type KbdPlatform } from "./kbd-hint.js";
|
|
38
39
|
export { FrameBox } from "./frame-box.js";
|
|
40
|
+
export { AppShell, type SidebarToggleDetail } from "./app-shell.js";
|
|
41
|
+
export { AppSidebar } from "./app-sidebar.js";
|
|
42
|
+
export { ActionBar } from "./action-bar.js";
|
|
43
|
+
export { PageHeader } from "./page-header.js";
|
|
44
|
+
export { PaginationNav, type PageChangeDetail } from "./pagination-nav.js";
|
|
45
|
+
export { FormActions } from "./form-actions.js";
|
|
46
|
+
export { TimelineContainer } from "./timeline-container.js";
|
|
47
|
+
export { TimelineEntry } from "./timeline-entry.js";
|
|
39
48
|
export { CalendarEntry } from "./calendar-entry.js";
|
|
40
49
|
export { CalendarMonth } from "./calendar-month.js";
|
|
41
50
|
export { CalendarYear } from "./calendar-year.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { PhotoGallery, } from "./photo-gallery.js";
|
|
|
5
5
|
export { RevealButton } from "./reveal-button.js";
|
|
6
6
|
export { RomanNumeral } from "./roman-numeral.js";
|
|
7
7
|
export { ConfirmDialog } from "./confirm-dialog.js";
|
|
8
|
+
export { ContentDivider } from "./content-divider.js";
|
|
8
9
|
export { ToastNotification, notifySuccess, notifyError, notifyInfo, } from "./toast-notification.js";
|
|
9
10
|
export { SlidePanel } from "./slide-panel.js";
|
|
10
11
|
export { CopyLinkButton } from "./copy-link-button.js";
|
|
@@ -36,6 +37,14 @@ export { DropdownButton } from "./dropdown-button.js";
|
|
|
36
37
|
export { IconButton } from "./icon-button.js";
|
|
37
38
|
export { KbdHint } from "./kbd-hint.js";
|
|
38
39
|
export { FrameBox } from "./frame-box.js";
|
|
40
|
+
export { AppShell } from "./app-shell.js";
|
|
41
|
+
export { AppSidebar } from "./app-sidebar.js";
|
|
42
|
+
export { ActionBar } from "./action-bar.js";
|
|
43
|
+
export { PageHeader } from "./page-header.js";
|
|
44
|
+
export { PaginationNav } from "./pagination-nav.js";
|
|
45
|
+
export { FormActions } from "./form-actions.js";
|
|
46
|
+
export { TimelineContainer } from "./timeline-container.js";
|
|
47
|
+
export { TimelineEntry } from "./timeline-entry.js";
|
|
39
48
|
export { CalendarEntry } from "./calendar-entry.js";
|
|
40
49
|
export { CalendarMonth } from "./calendar-month.js";
|
|
41
50
|
export { CalendarYear } from "./calendar-year.js";
|