@iyulab/desktop-patterns 0.1.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/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/components/page/dp-page.d.ts +17 -0
- package/dist/components/shell/dp-shell.d.ts +38 -0
- package/dist/components/shortcut-overlay/dp-shortcut-overlay.d.ts +37 -0
- package/dist/components/sidebar/dp-sidebar.d.ts +31 -0
- package/dist/components/toolbar/dp-toolbar.d.ts +52 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +16 -0
- package/dist/page.js +48 -0
- package/dist/shell.js +93 -0
- package/dist/shortcut-overlay.js +172 -0
- package/dist/sidebar.js +154 -0
- package/dist/toolbar.js +108 -0
- package/package.json +54 -0
- package/tokens.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iyulab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# desktop-patterns
|
|
2
|
+
|
|
3
|
+
App-shell and structural layout patterns assembled on top of
|
|
4
|
+
[`desktop-compact`](https://github.com/iyulab/desktop-compact)'s primitives. Framework-neutral custom
|
|
5
|
+
elements ([Lit](https://lit.dev)), zero built-in strings, every content region a slot.
|
|
6
|
+
|
|
7
|
+
Structure only — atomic controls (buttons, inputs, dialogs) belong in `desktop-compact`; native
|
|
8
|
+
platform integration (file dialogs, tray, window control) belongs in
|
|
9
|
+
[`electron-kit`](https://github.com/iyulab/electron-kit). This package doesn't call any platform API
|
|
10
|
+
itself, and knows nothing about any specific consuming application.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
Requires Node ≥22.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @iyulab/desktop-patterns @iyulab/desktop-compact
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Import only the components you use — each ships as its own subpath for tree-shaking:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import '@iyulab/desktop-patterns/shell'
|
|
24
|
+
import '@iyulab/desktop-patterns/sidebar'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or import everything via the barrel:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import '@iyulab/desktop-patterns'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<dp-shell sidebar-open>
|
|
37
|
+
<dp-sidebar slot="sidebar" active-id="overview" header="My App" id="nav"></dp-sidebar>
|
|
38
|
+
<dp-toolbar slot="toolbar" heading="My App" show-toggle></dp-toolbar>
|
|
39
|
+
<dp-page>
|
|
40
|
+
<h2>Overview</h2>
|
|
41
|
+
<p>Main content.</p>
|
|
42
|
+
</dp-page>
|
|
43
|
+
</dp-shell>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`items`/`bottomItems` are arrays, so they're set as JS properties (not plain HTML attributes) — same
|
|
47
|
+
as any Lit custom element:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
document.querySelector<HTMLElementTagNameMap['dp-sidebar']>('#nav')!.items = [
|
|
51
|
+
{ id: 'overview', icon: '■', label: 'Overview' },
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
document.querySelector('dp-sidebar')!.addEventListener('dp-sidebar-select', (e) => {
|
|
55
|
+
// consumer owns activeId / routing
|
|
56
|
+
})
|
|
57
|
+
document.querySelector('dp-toolbar')!.addEventListener('dp-toolbar-toggle', () => {
|
|
58
|
+
// consumer owns sidebar-open state on dp-shell
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Every component takes its user-facing text as a plain attribute/property or slot — there is no
|
|
63
|
+
built-in i18n layer. See each component's Storybook story (`npm run storybook`) for its full API.
|
|
64
|
+
|
|
65
|
+
## Theming
|
|
66
|
+
|
|
67
|
+
Import both token sheets once in your app's global stylesheet:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import '@iyulab/desktop-compact/tokens.css'
|
|
71
|
+
import '@iyulab/desktop-patterns/tokens.css'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Color/spacing/radius/typography all come from `desktop-compact`'s `--dc-*` tokens — this package adds
|
|
75
|
+
only the structural dimensions `desktop-compact` has no concept of (`--dp-sidebar-width`,
|
|
76
|
+
`--dp-sidebar-width-collapsed`, `--dp-header-height`). Every component ships with sane fallback
|
|
77
|
+
values, so it still renders correctly even without either stylesheet.
|
|
78
|
+
|
|
79
|
+
## Platform boundary — drag regions
|
|
80
|
+
|
|
81
|
+
`dp-toolbar` exposes a neutral `drag-region` flag (not the native `draggable`, which already means
|
|
82
|
+
something else) but never emits any platform-specific CSS itself. The flag reflects to the host
|
|
83
|
+
attribute, but the actual drag surface is a dedicated `part="drag-handle"` spacer between the start
|
|
84
|
+
group and the `actions` slot — never the whole host — so the mapping can never reach the toggle
|
|
85
|
+
button or slotted actions. Mapping that part to an actual window-drag behavior (e.g.
|
|
86
|
+
`-webkit-app-region: drag` in Electron/Chromium-based webviews) is `electron-kit`'s job:
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
dp-toolbar[drag-region]::part(drag-handle) {
|
|
90
|
+
-webkit-app-region: drag;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`dp-shell` does not mark any drag region of its own — it has no opinion on what's slotted into
|
|
95
|
+
`toolbar`, so ownership of the drag handle stays entirely with whatever renders there (typically
|
|
96
|
+
`dp-toolbar`).
|
|
97
|
+
|
|
98
|
+
## Components (v1 — complete, 5/5)
|
|
99
|
+
|
|
100
|
+
| Component | Description |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `dp-page` | Scrollable content region with a centered, max-width column — the page-body every view renders into |
|
|
103
|
+
| `dp-sidebar` | App-shell navigation rail — expanded/collapsed states, an optional pinned bottom group, a `footer` slot for whatever a consumer wants to anchor there |
|
|
104
|
+
| `dp-toolbar` | App-shell header bar — `heading`/`subtitle`, an optional collapse toggle, a right-side `actions` slot |
|
|
105
|
+
| `dp-shell` | Top-level layout composing `sidebar`/`toolbar`/`banner`/main-content regions, with a responsive drawer (backdrop + overlay sidebar) below a 1024px breakpoint |
|
|
106
|
+
| `dp-shortcut-overlay` | Display-only keyboard-shortcuts help panel — a `shortcuts` list + `open` flag; no registration/binding infrastructure (that stays the consumer's) |
|
|
107
|
+
|
|
108
|
+
Run `npm run storybook` to browse every component interactively, including `dp-shell` composing real
|
|
109
|
+
`dp-sidebar`+`dp-toolbar`+`dp-page` together.
|
|
110
|
+
|
|
111
|
+
## Accessibility
|
|
112
|
+
|
|
113
|
+
Every component ships with an axe accessibility test as part of its test suite (`npm test`). Landmarks
|
|
114
|
+
follow ARIA APG conventions — `dp-sidebar` uses a semantic `<nav>` (no redundant host-level role),
|
|
115
|
+
`dp-shortcut-overlay` uses `role="dialog"` with `aria-labelledby` pointing at its visible heading.
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install
|
|
121
|
+
npm test # @web/test-runner, real Chromium
|
|
122
|
+
npm run typecheck
|
|
123
|
+
npm run guard # forge-ignorance + platform-agnosticism scan (this package must stay domain-neutral and platform-neutral)
|
|
124
|
+
npm run build # per-component ESM output, type declarations
|
|
125
|
+
npm run storybook # interactive component browser
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Until `@iyulab/desktop-compact` publishes its first npm release, this package resolves it via
|
|
129
|
+
`file:../desktop-compact` for local development (a sibling checkout at that relative path) — this
|
|
130
|
+
switches to a registry semver range once `desktop-compact` publishes.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export type PageMaxWidth = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
3
|
+
/**
|
|
4
|
+
* Scrollable content region with a centered, max-width column — the page-body
|
|
5
|
+
* pattern every view in an app shell renders into. Pure layout: it has no
|
|
6
|
+
* opinion on what it contains (default slot only).
|
|
7
|
+
*/
|
|
8
|
+
export declare class DpPage extends LitElement {
|
|
9
|
+
static styles: import('lit').CSSResult;
|
|
10
|
+
maxWidth: PageMaxWidth;
|
|
11
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
12
|
+
}
|
|
13
|
+
declare global {
|
|
14
|
+
interface HTMLElementTagNameMap {
|
|
15
|
+
'dp-page': DpPage;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class DpShellSidebarCloseEvent extends Event {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Top-level app-shell layout: a responsive sidebar region (a fixed
|
|
7
|
+
* backdrop-covered drawer below the desktop breakpoint, static beside the
|
|
8
|
+
* content above it), a toolbar row, an optional banner row, and the main
|
|
9
|
+
* content area. Pure composition — every region is a slot, this component
|
|
10
|
+
* has no opinion on what's inside any of them.
|
|
11
|
+
*
|
|
12
|
+
* The original component this generalizes rendered a fixed status banner
|
|
13
|
+
* unconditionally above its `banner` slot; that hardcoded element is gone
|
|
14
|
+
* here — the existing `banner` slot alone is enough for a consumer to put
|
|
15
|
+
* anything there, and this repo has no business knowing what that banner
|
|
16
|
+
* should be.
|
|
17
|
+
*
|
|
18
|
+
* Drag region: this component does not mark any drag region of its own.
|
|
19
|
+
* The `toolbar-row` wrapper is sized exactly to whatever is slotted into
|
|
20
|
+
* `toolbar` — it has no empty space that is safely distinct from the
|
|
21
|
+
* slotted content's own interactive children, so a wrapper-level flag here
|
|
22
|
+
* could only ever mark the same box `dp-toolbar` already marks (redundant)
|
|
23
|
+
* or, worse, extend the drag region across content this component has no
|
|
24
|
+
* visibility into (unsafe — this component "has no opinion on what's
|
|
25
|
+
* inside any [slot]", per the class doc above). Drag-region ownership
|
|
26
|
+
* belongs entirely to whatever renders into the `toolbar` slot — see
|
|
27
|
+
* `dp-toolbar`'s own `part="drag-handle"`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class DpShell extends LitElement {
|
|
30
|
+
static styles: import('lit').CSSResult;
|
|
31
|
+
sidebarOpen: boolean;
|
|
32
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
33
|
+
}
|
|
34
|
+
declare global {
|
|
35
|
+
interface HTMLElementTagNameMap {
|
|
36
|
+
'dp-shell': DpShell;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LitElement, nothing } from 'lit';
|
|
2
|
+
export interface ShortcutEntry {
|
|
3
|
+
combo: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class DpShortcutOverlayDismissEvent extends Event {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Display-only keyboard-shortcuts help panel: a `shortcuts` list + an `open`
|
|
11
|
+
* flag, nothing else. This component owns no registry and no trigger
|
|
12
|
+
* keybinding — the original component this generalizes bound its own
|
|
13
|
+
* `shift+/` shortcut and read from a module-level, framework-hook-specific
|
|
14
|
+
* registry; both are the consumer's responsibility here (see
|
|
15
|
+
* docs/superpowers/specs/2026-09-02-desktop-patterns-design.md, the
|
|
16
|
+
* dp-shortcut-overlay row). This component only dismisses itself (outside
|
|
17
|
+
* click / Escape) by asking — it dispatches `dp-shortcut-overlay-dismiss`
|
|
18
|
+
* rather than setting its own `open` to false, since `open` is the
|
|
19
|
+
* consumer's state to own, not this component's.
|
|
20
|
+
*/
|
|
21
|
+
export declare class DpShortcutOverlay extends LitElement {
|
|
22
|
+
#private;
|
|
23
|
+
static styles: import('lit').CSSResult;
|
|
24
|
+
shortcuts: ShortcutEntry[];
|
|
25
|
+
open: boolean;
|
|
26
|
+
heading: string;
|
|
27
|
+
emptyMessage: string;
|
|
28
|
+
private headingId;
|
|
29
|
+
updated(changed: Map<string, unknown>): void;
|
|
30
|
+
disconnectedCallback(): void;
|
|
31
|
+
render(): import('lit-html').TemplateResult<1> | typeof nothing;
|
|
32
|
+
}
|
|
33
|
+
declare global {
|
|
34
|
+
interface HTMLElementTagNameMap {
|
|
35
|
+
'dp-shortcut-overlay': DpShortcutOverlay;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export interface SidebarItem {
|
|
3
|
+
id: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class DpSidebarSelectEvent extends Event {
|
|
8
|
+
readonly itemId: string;
|
|
9
|
+
constructor(itemId: string);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* App-shell navigation rail: an icon+label list with an expanded/collapsed
|
|
13
|
+
* state, an optional pinned bottom group, and a `footer` slot for whatever
|
|
14
|
+
* the consumer wants to anchor at the bottom — a status badge, a version
|
|
15
|
+
* string, anything; this repo doesn't know what.
|
|
16
|
+
*/
|
|
17
|
+
export declare class DpSidebar extends LitElement {
|
|
18
|
+
#private;
|
|
19
|
+
static styles: import('lit').CSSResult;
|
|
20
|
+
items: SidebarItem[];
|
|
21
|
+
bottomItems: SidebarItem[];
|
|
22
|
+
activeId: string;
|
|
23
|
+
header: string;
|
|
24
|
+
collapsed: boolean;
|
|
25
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
26
|
+
}
|
|
27
|
+
declare global {
|
|
28
|
+
interface HTMLElementTagNameMap {
|
|
29
|
+
'dp-sidebar': DpSidebar;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class DpToolbarToggleEvent extends Event {
|
|
3
|
+
constructor();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* App-shell header bar: a `heading` (optionally overridden per-view by
|
|
7
|
+
* `subtitle`), an optional collapse/expand toggle, and a right-side
|
|
8
|
+
* `actions` slot. Pure layout — this repo does not call any platform API.
|
|
9
|
+
*
|
|
10
|
+
* Named `heading`, not `title` — matches dc-section-heading's own
|
|
11
|
+
* established convention for this kind of headline text, and avoids
|
|
12
|
+
* shadowing the native HTMLElement.prototype.title (tooltip) accessor with
|
|
13
|
+
* an unrelated meaning, the same reasoning already applied to `drag-region`
|
|
14
|
+
* below.
|
|
15
|
+
*
|
|
16
|
+
* Drag region: the `drag-region` attribute reflects intent only, mirroring
|
|
17
|
+
* dp-shell — this repo never emits any platform-specific CSS itself (see
|
|
18
|
+
* docs/superpowers/specs/2026-09-02-desktop-patterns-design.md, "플랫폼 API
|
|
19
|
+
* 경계"). Named `drag-region`, not the native `draggable` — the platform HTML5
|
|
20
|
+
* Drag-and-Drop attribute already owns that name/IDL property with unrelated
|
|
21
|
+
* semantics (HTMLElement.prototype.draggable); reusing it here would shadow
|
|
22
|
+
* the native accessor on this custom element for a completely different
|
|
23
|
+
* concept (a window-chrome drag handle, not drag-and-drop). This component's
|
|
24
|
+
* original source also hardcoded extra end-padding to reserve room for
|
|
25
|
+
* native window-chrome controls — a platform assumption this repo can't make
|
|
26
|
+
* either. `--dp-toolbar-inset-start`/`--dp-toolbar-inset-end` (default 0)
|
|
27
|
+
* generalize that into a neutral extension point a platform-adapter layer
|
|
28
|
+
* can set.
|
|
29
|
+
*
|
|
30
|
+
* The drag CSS a consumer maps onto `drag-region` must never target the host
|
|
31
|
+
* itself — the host also contains the `.toggle` button and the `actions`
|
|
32
|
+
* slot, both interactive, and neither carries any no-drag exception. Instead
|
|
33
|
+
* a dedicated `part="drag-handle"` spacer sits between the start group and
|
|
34
|
+
* the actions group; it renders no content of its own (nothing is ever
|
|
35
|
+
* slotted into it), so it is structurally impossible for it to overlap an
|
|
36
|
+
* interactive child. Consumers scope the platform CSS to that one part, not
|
|
37
|
+
* to `dp-toolbar[drag-region]` alone — see this package's README (platform
|
|
38
|
+
* boundary — drag regions) for the exact selector.
|
|
39
|
+
*/
|
|
40
|
+
export declare class DpToolbar extends LitElement {
|
|
41
|
+
static styles: import('lit').CSSResult;
|
|
42
|
+
heading: string;
|
|
43
|
+
subtitle: string;
|
|
44
|
+
showToggle: boolean;
|
|
45
|
+
dragRegion: boolean;
|
|
46
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
47
|
+
}
|
|
48
|
+
declare global {
|
|
49
|
+
interface HTMLElementTagNameMap {
|
|
50
|
+
'dp-toolbar': DpToolbar;
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './components/page/dp-page.js';
|
|
2
|
+
export * from './components/sidebar/dp-sidebar.js';
|
|
3
|
+
export * from './components/toolbar/dp-toolbar.js';
|
|
4
|
+
export * from './components/shell/dp-shell.js';
|
|
5
|
+
export * from './components/shortcut-overlay/dp-shortcut-overlay.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DpPage as o } from "./page.js";
|
|
2
|
+
import { DpSidebar as t, DpSidebarSelectEvent as l } from "./sidebar.js";
|
|
3
|
+
import { DpToolbar as a, DpToolbarToggleEvent as S } from "./toolbar.js";
|
|
4
|
+
import { DpShell as v, DpShellSidebarCloseEvent as b } from "./shell.js";
|
|
5
|
+
import { DpShortcutOverlay as i, DpShortcutOverlayDismissEvent as x } from "./shortcut-overlay.js";
|
|
6
|
+
export {
|
|
7
|
+
o as DpPage,
|
|
8
|
+
v as DpShell,
|
|
9
|
+
b as DpShellSidebarCloseEvent,
|
|
10
|
+
i as DpShortcutOverlay,
|
|
11
|
+
x as DpShortcutOverlayDismissEvent,
|
|
12
|
+
t as DpSidebar,
|
|
13
|
+
l as DpSidebarSelectEvent,
|
|
14
|
+
a as DpToolbar,
|
|
15
|
+
S as DpToolbarToggleEvent
|
|
16
|
+
};
|
package/dist/page.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { css as a, LitElement as m, html as x } from "lit";
|
|
2
|
+
import { property as d, customElement as c } from "lit/decorators.js";
|
|
3
|
+
var h = Object.defineProperty, u = Object.getOwnPropertyDescriptor, n = (l, e, s, r) => {
|
|
4
|
+
for (var t = r > 1 ? void 0 : r ? u(e, s) : e, p = l.length - 1, i; p >= 0; p--)
|
|
5
|
+
(i = l[p]) && (t = (r ? i(e, s, t) : i(t)) || t);
|
|
6
|
+
return r && t && h(e, s, t), t;
|
|
7
|
+
};
|
|
8
|
+
const b = {
|
|
9
|
+
sm: "672px",
|
|
10
|
+
md: "768px",
|
|
11
|
+
lg: "896px",
|
|
12
|
+
xl: "1152px",
|
|
13
|
+
full: "none"
|
|
14
|
+
};
|
|
15
|
+
let o = class extends m {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments), this.maxWidth = "md";
|
|
18
|
+
}
|
|
19
|
+
render() {
|
|
20
|
+
return x`
|
|
21
|
+
<div class="inner" style="max-width: ${b[this.maxWidth]}">
|
|
22
|
+
<slot></slot>
|
|
23
|
+
</div>
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
o.styles = a`
|
|
28
|
+
:host {
|
|
29
|
+
display: block;
|
|
30
|
+
height: 100%;
|
|
31
|
+
overflow-y: auto;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
.inner {
|
|
35
|
+
margin: 0 auto;
|
|
36
|
+
padding: var(--dc-space-6, 24px);
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
n([
|
|
41
|
+
d({ attribute: "max-width", reflect: !0 })
|
|
42
|
+
], o.prototype, "maxWidth", 2);
|
|
43
|
+
o = n([
|
|
44
|
+
c("dp-page")
|
|
45
|
+
], o);
|
|
46
|
+
export {
|
|
47
|
+
o as DpPage
|
|
48
|
+
};
|
package/dist/shell.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { css as c, LitElement as p, nothing as b, html as a } from "lit";
|
|
2
|
+
import { property as f, customElement as m } from "lit/decorators.js";
|
|
3
|
+
var v = Object.defineProperty, u = Object.getOwnPropertyDescriptor, d = (r, o, t, s) => {
|
|
4
|
+
for (var e = s > 1 ? void 0 : s ? u(o, t) : o, l = r.length - 1, n; l >= 0; l--)
|
|
5
|
+
(n = r[l]) && (e = (s ? n(o, t, e) : n(e)) || e);
|
|
6
|
+
return s && e && v(o, t, e), e;
|
|
7
|
+
};
|
|
8
|
+
class h extends Event {
|
|
9
|
+
constructor() {
|
|
10
|
+
super("dp-shell-sidebar-close", { bubbles: !0, composed: !0 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
let i = class extends p {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments), this.sidebarOpen = !1;
|
|
16
|
+
}
|
|
17
|
+
render() {
|
|
18
|
+
return a`
|
|
19
|
+
${this.sidebarOpen ? a`<div class="backdrop" @click=${() => this.dispatchEvent(new h())}></div>` : b}
|
|
20
|
+
<div class="sidebar-region"><slot name="sidebar"></slot></div>
|
|
21
|
+
<div class="main-column">
|
|
22
|
+
<div class="toolbar-row">
|
|
23
|
+
<slot name="toolbar"></slot>
|
|
24
|
+
</div>
|
|
25
|
+
<slot name="banner"></slot>
|
|
26
|
+
<main><slot></slot></main>
|
|
27
|
+
</div>
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
i.styles = c`
|
|
32
|
+
:host {
|
|
33
|
+
display: flex;
|
|
34
|
+
width: 100vw;
|
|
35
|
+
height: 100vh;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
background: var(--dc-color-bg, #ffffff);
|
|
39
|
+
color: var(--dc-color-text, #1a1a1e);
|
|
40
|
+
font-family: var(--dc-font-family, system-ui, sans-serif);
|
|
41
|
+
}
|
|
42
|
+
.backdrop {
|
|
43
|
+
position: fixed;
|
|
44
|
+
inset: 0;
|
|
45
|
+
z-index: 30;
|
|
46
|
+
background: var(--dc-color-backdrop, rgba(0, 0, 0, 0.4));
|
|
47
|
+
}
|
|
48
|
+
.sidebar-region {
|
|
49
|
+
flex-shrink: 0;
|
|
50
|
+
display: none;
|
|
51
|
+
}
|
|
52
|
+
:host([sidebar-open]) .sidebar-region {
|
|
53
|
+
display: block;
|
|
54
|
+
position: fixed;
|
|
55
|
+
inset-block: 0;
|
|
56
|
+
inset-inline-start: 0;
|
|
57
|
+
z-index: 40;
|
|
58
|
+
}
|
|
59
|
+
@media (min-width: 1024px) {
|
|
60
|
+
.sidebar-region {
|
|
61
|
+
display: block;
|
|
62
|
+
position: relative;
|
|
63
|
+
inset: auto;
|
|
64
|
+
z-index: auto;
|
|
65
|
+
}
|
|
66
|
+
.backdrop {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
.main-column {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
flex: 1;
|
|
74
|
+
min-width: 0;
|
|
75
|
+
}
|
|
76
|
+
.toolbar-row {
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
}
|
|
79
|
+
main {
|
|
80
|
+
flex: 1;
|
|
81
|
+
overflow: auto;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
d([
|
|
85
|
+
f({ type: Boolean, reflect: !0, attribute: "sidebar-open" })
|
|
86
|
+
], i.prototype, "sidebarOpen", 2);
|
|
87
|
+
i = d([
|
|
88
|
+
m("dp-shell")
|
|
89
|
+
], i);
|
|
90
|
+
export {
|
|
91
|
+
i as DpShell,
|
|
92
|
+
h as DpShellSidebarCloseEvent
|
|
93
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { css as x, LitElement as b, nothing as w, html as d } from "lit";
|
|
2
|
+
import { property as l, state as _, customElement as k } from "lit/decorators.js";
|
|
3
|
+
var $ = Object.defineProperty, E = Object.getOwnPropertyDescriptor, g = (e) => {
|
|
4
|
+
throw TypeError(e);
|
|
5
|
+
}, a = (e, t, r, c) => {
|
|
6
|
+
for (var s = c > 1 ? void 0 : c ? E(t, r) : t, h = e.length - 1, v; h >= 0; h--)
|
|
7
|
+
(v = e[h]) && (s = (c ? v(t, r, s) : v(s)) || s);
|
|
8
|
+
return c && s && $(t, r, s), s;
|
|
9
|
+
}, m = (e, t, r) => t.has(e) || g("Cannot " + r), u = (e, t, r) => (m(e, t, "read from private field"), t.get(e)), y = (e, t, r) => t.has(e) ? g("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, r), f = (e, t, r) => (m(e, t, "access private method"), r), i, n, p;
|
|
10
|
+
class z extends Event {
|
|
11
|
+
constructor() {
|
|
12
|
+
super("dp-shortcut-overlay-dismiss", { bubbles: !0, composed: !0 });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
let C = 0, o = class extends b {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments), y(this, n), this.shortcuts = [], this.open = !1, this.heading = "Keyboard shortcuts", this.emptyMessage = "No shortcuts registered.", this.headingId = `dp-shortcut-overlay-heading-${++C}`, y(this, i, (e) => {
|
|
18
|
+
e.key === "Escape" && (e.preventDefault(), f(this, n, p).call(this));
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
updated(e) {
|
|
22
|
+
e.has("open") && (this.open ? window.addEventListener("keydown", u(this, i)) : window.removeEventListener("keydown", u(this, i)));
|
|
23
|
+
}
|
|
24
|
+
disconnectedCallback() {
|
|
25
|
+
super.disconnectedCallback(), window.removeEventListener("keydown", u(this, i));
|
|
26
|
+
}
|
|
27
|
+
render() {
|
|
28
|
+
return this.open ? d`
|
|
29
|
+
<div class="backdrop" @click=${() => f(this, n, p).call(this)}>
|
|
30
|
+
<div
|
|
31
|
+
class="panel"
|
|
32
|
+
role="dialog"
|
|
33
|
+
aria-modal="true"
|
|
34
|
+
aria-labelledby=${this.headingId}
|
|
35
|
+
@click=${(e) => e.stopPropagation()}
|
|
36
|
+
>
|
|
37
|
+
<div class="header">
|
|
38
|
+
<h2 id=${this.headingId}>${this.heading}</h2>
|
|
39
|
+
<button class="close" aria-label="Close" @click=${() => f(this, n, p).call(this)}>×</button>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="body">
|
|
42
|
+
${this.shortcuts.length === 0 ? d`<p class="empty">${this.emptyMessage}</p>` : d`
|
|
43
|
+
<ul>
|
|
44
|
+
${this.shortcuts.map(
|
|
45
|
+
(e) => d`
|
|
46
|
+
<li>
|
|
47
|
+
<span>${e.description}</span>
|
|
48
|
+
<kbd>${e.combo}</kbd>
|
|
49
|
+
</li>
|
|
50
|
+
`
|
|
51
|
+
)}
|
|
52
|
+
</ul>
|
|
53
|
+
`}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
` : w;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
i = /* @__PURE__ */ new WeakMap();
|
|
61
|
+
n = /* @__PURE__ */ new WeakSet();
|
|
62
|
+
p = function() {
|
|
63
|
+
this.dispatchEvent(new z());
|
|
64
|
+
};
|
|
65
|
+
o.styles = x`
|
|
66
|
+
:host {
|
|
67
|
+
display: contents;
|
|
68
|
+
font-family: var(--dc-font-family, system-ui, sans-serif);
|
|
69
|
+
}
|
|
70
|
+
.backdrop {
|
|
71
|
+
position: fixed;
|
|
72
|
+
inset: 0;
|
|
73
|
+
z-index: 100;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
background: var(--dc-color-backdrop, rgba(0, 0, 0, 0.4));
|
|
78
|
+
}
|
|
79
|
+
.panel {
|
|
80
|
+
width: 420px;
|
|
81
|
+
max-height: 70vh;
|
|
82
|
+
overflow-y: auto;
|
|
83
|
+
background: var(--dc-color-surface, #f7f7f8);
|
|
84
|
+
border: 1px solid var(--dc-color-border, #e2e2e4);
|
|
85
|
+
border-radius: var(--dc-radius-lg, 10px);
|
|
86
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
87
|
+
}
|
|
88
|
+
.header {
|
|
89
|
+
display: flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: space-between;
|
|
92
|
+
padding: var(--dc-space-3, 12px) var(--dc-space-4, 16px);
|
|
93
|
+
border-bottom: 1px solid var(--dc-color-border, #e2e2e4);
|
|
94
|
+
}
|
|
95
|
+
h2 {
|
|
96
|
+
margin: 0;
|
|
97
|
+
font-size: var(--dc-font-size-sm, 12px);
|
|
98
|
+
font-weight: var(--dc-font-weight-semibold, 600);
|
|
99
|
+
color: var(--dc-color-text, #1a1a1e);
|
|
100
|
+
}
|
|
101
|
+
.close {
|
|
102
|
+
appearance: none;
|
|
103
|
+
background: none;
|
|
104
|
+
border: none;
|
|
105
|
+
padding: 0;
|
|
106
|
+
font-size: var(--dc-font-size-lg, 15px);
|
|
107
|
+
line-height: 1;
|
|
108
|
+
color: var(--dc-color-text-muted, #8a8a92);
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
}
|
|
111
|
+
.close:hover {
|
|
112
|
+
color: var(--dc-color-text, #1a1a1e);
|
|
113
|
+
}
|
|
114
|
+
.close:focus-visible {
|
|
115
|
+
outline: 2px solid var(--dc-color-accent, #2563eb);
|
|
116
|
+
outline-offset: 2px;
|
|
117
|
+
}
|
|
118
|
+
.body {
|
|
119
|
+
padding: var(--dc-space-3, 12px) var(--dc-space-4, 16px);
|
|
120
|
+
}
|
|
121
|
+
.empty {
|
|
122
|
+
margin: 0;
|
|
123
|
+
font-size: var(--dc-font-size-xs, 11px);
|
|
124
|
+
color: var(--dc-color-text-muted, #8a8a92);
|
|
125
|
+
}
|
|
126
|
+
ul {
|
|
127
|
+
list-style: none;
|
|
128
|
+
margin: 0;
|
|
129
|
+
padding: 0;
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-direction: column;
|
|
132
|
+
gap: var(--dc-space-1, 4px);
|
|
133
|
+
}
|
|
134
|
+
li {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: space-between;
|
|
138
|
+
gap: var(--dc-space-3, 12px);
|
|
139
|
+
font-size: var(--dc-font-size-xs, 11px);
|
|
140
|
+
}
|
|
141
|
+
kbd {
|
|
142
|
+
padding: 2px 6px;
|
|
143
|
+
border-radius: var(--dc-radius-sm, 4px);
|
|
144
|
+
background: var(--dc-color-surface-hover, #ececed);
|
|
145
|
+
border: 1px solid var(--dc-color-border, #e2e2e4);
|
|
146
|
+
color: var(--dc-color-text-secondary, #55555c);
|
|
147
|
+
font-family: ui-monospace, monospace;
|
|
148
|
+
font-size: 10px;
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
a([
|
|
152
|
+
l({ type: Array })
|
|
153
|
+
], o.prototype, "shortcuts", 2);
|
|
154
|
+
a([
|
|
155
|
+
l({ type: Boolean, reflect: !0 })
|
|
156
|
+
], o.prototype, "open", 2);
|
|
157
|
+
a([
|
|
158
|
+
l()
|
|
159
|
+
], o.prototype, "heading", 2);
|
|
160
|
+
a([
|
|
161
|
+
l({ attribute: "empty-message" })
|
|
162
|
+
], o.prototype, "emptyMessage", 2);
|
|
163
|
+
a([
|
|
164
|
+
_()
|
|
165
|
+
], o.prototype, "headingId", 2);
|
|
166
|
+
o = a([
|
|
167
|
+
k("dp-shortcut-overlay")
|
|
168
|
+
], o);
|
|
169
|
+
export {
|
|
170
|
+
o as DpShortcutOverlay,
|
|
171
|
+
z as DpShortcutOverlayDismissEvent
|
|
172
|
+
};
|
package/dist/sidebar.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { css as m, LitElement as x, nothing as c, html as i } from "lit";
|
|
2
|
+
import { property as n, customElement as g } from "lit/decorators.js";
|
|
3
|
+
var y = Object.defineProperty, _ = Object.getOwnPropertyDescriptor, b = (e) => {
|
|
4
|
+
throw TypeError(e);
|
|
5
|
+
}, s = (e, t, r, p) => {
|
|
6
|
+
for (var a = p > 1 ? void 0 : p ? _(t, r) : t, l = e.length - 1, h; l >= 0; l--)
|
|
7
|
+
(h = e[l]) && (a = (p ? h(t, r, a) : h(a)) || a);
|
|
8
|
+
return p && a && y(t, r, a), a;
|
|
9
|
+
}, w = (e, t, r) => t.has(e) || b("Cannot " + r), I = (e, t, r) => t.has(e) ? b("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, r), v = (e, t, r) => (w(e, t, "access private method"), r), d, f, u;
|
|
10
|
+
class $ extends Event {
|
|
11
|
+
constructor(t) {
|
|
12
|
+
super("dp-sidebar-select", { bubbles: !0, composed: !0 }), this.itemId = t;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
let o = class extends x {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments), I(this, d), this.items = [], this.bottomItems = [], this.activeId = "", this.header = "", this.collapsed = !1;
|
|
18
|
+
}
|
|
19
|
+
render() {
|
|
20
|
+
return i`
|
|
21
|
+
<div class="header">
|
|
22
|
+
<slot name="icon"></slot>
|
|
23
|
+
${!this.collapsed && this.header ? i`<span class="header-label">${this.header}</span>` : c}
|
|
24
|
+
</div>
|
|
25
|
+
<nav>${this.items.map((e) => v(this, d, f).call(this, e))}</nav>
|
|
26
|
+
${this.bottomItems.length > 0 ? i`<div class="bottom-group">${this.bottomItems.map((e) => v(this, d, f).call(this, e))}</div>` : c}
|
|
27
|
+
<div class="footer"><slot name="footer"></slot></div>
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
d = /* @__PURE__ */ new WeakSet();
|
|
32
|
+
f = function(e) {
|
|
33
|
+
const t = e.id === this.activeId;
|
|
34
|
+
return i`
|
|
35
|
+
<button
|
|
36
|
+
title=${this.collapsed ? e.label : c}
|
|
37
|
+
aria-current=${t ? "page" : c}
|
|
38
|
+
@click=${() => v(this, d, u).call(this, e.id)}
|
|
39
|
+
>
|
|
40
|
+
<span class="icon" aria-hidden="true">${e.icon}</span>
|
|
41
|
+
${this.collapsed ? c : i`<span>${e.label}</span>`}
|
|
42
|
+
</button>
|
|
43
|
+
`;
|
|
44
|
+
};
|
|
45
|
+
u = function(e) {
|
|
46
|
+
e !== this.activeId && (this.activeId = e, this.dispatchEvent(new $(e)));
|
|
47
|
+
};
|
|
48
|
+
o.styles = m`
|
|
49
|
+
:host {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
height: 100%;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
width: var(--dp-sidebar-width, 220px);
|
|
55
|
+
background: var(--dc-color-surface, #f7f7f8);
|
|
56
|
+
border-right: 1px solid var(--dc-color-border, #e2e2e4);
|
|
57
|
+
font-family: var(--dc-font-family, system-ui, sans-serif);
|
|
58
|
+
}
|
|
59
|
+
:host([collapsed]) {
|
|
60
|
+
width: var(--dp-sidebar-width-collapsed, 52px);
|
|
61
|
+
}
|
|
62
|
+
.header {
|
|
63
|
+
height: var(--dp-header-height, 52px);
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: var(--dc-space-3, 12px);
|
|
67
|
+
padding: 0 var(--dc-space-3, 12px);
|
|
68
|
+
border-bottom: 1px solid var(--dc-color-border, #e2e2e4);
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
}
|
|
72
|
+
:host([collapsed]) .header {
|
|
73
|
+
justify-content: center;
|
|
74
|
+
padding: 0;
|
|
75
|
+
}
|
|
76
|
+
.header-label {
|
|
77
|
+
font-size: var(--dc-font-size-xs, 11px);
|
|
78
|
+
font-weight: var(--dc-font-weight-medium, 500);
|
|
79
|
+
color: var(--dc-color-text-secondary, #55555c);
|
|
80
|
+
text-transform: uppercase;
|
|
81
|
+
letter-spacing: 0.02em;
|
|
82
|
+
}
|
|
83
|
+
nav {
|
|
84
|
+
flex: 1;
|
|
85
|
+
overflow-y: auto;
|
|
86
|
+
padding: var(--dc-space-1, 4px) 0;
|
|
87
|
+
}
|
|
88
|
+
.bottom-group {
|
|
89
|
+
border-top: 1px solid var(--dc-color-border, #e2e2e4);
|
|
90
|
+
padding: var(--dc-space-1, 4px) 0;
|
|
91
|
+
}
|
|
92
|
+
button {
|
|
93
|
+
appearance: none;
|
|
94
|
+
background: none;
|
|
95
|
+
border: none;
|
|
96
|
+
border-left: 2px solid transparent;
|
|
97
|
+
width: 100%;
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: var(--dc-space-3, 12px);
|
|
101
|
+
padding: var(--dc-space-2, 8px) var(--dc-space-3, 12px);
|
|
102
|
+
font: inherit;
|
|
103
|
+
font-size: var(--dc-font-size-sm, 12px);
|
|
104
|
+
color: var(--dc-color-text-secondary, #55555c);
|
|
105
|
+
text-align: left;
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
}
|
|
108
|
+
:host([collapsed]) button {
|
|
109
|
+
justify-content: center;
|
|
110
|
+
padding: var(--dc-space-3, 12px) 0;
|
|
111
|
+
}
|
|
112
|
+
button[aria-current='page'] {
|
|
113
|
+
border-left-color: var(--dc-color-accent, #2563eb);
|
|
114
|
+
color: var(--dc-color-accent, #2563eb);
|
|
115
|
+
font-weight: var(--dc-font-weight-medium, 500);
|
|
116
|
+
}
|
|
117
|
+
button:hover {
|
|
118
|
+
background: var(--dc-color-surface-hover, #ececed);
|
|
119
|
+
}
|
|
120
|
+
button:focus-visible {
|
|
121
|
+
outline: 2px solid var(--dc-color-accent, #2563eb);
|
|
122
|
+
outline-offset: -2px;
|
|
123
|
+
}
|
|
124
|
+
.icon {
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
width: 1.25em;
|
|
127
|
+
text-align: center;
|
|
128
|
+
}
|
|
129
|
+
.footer {
|
|
130
|
+
border-top: 1px solid var(--dc-color-border, #e2e2e4);
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
s([
|
|
134
|
+
n({ type: Array })
|
|
135
|
+
], o.prototype, "items", 2);
|
|
136
|
+
s([
|
|
137
|
+
n({ type: Array, attribute: "bottom-items" })
|
|
138
|
+
], o.prototype, "bottomItems", 2);
|
|
139
|
+
s([
|
|
140
|
+
n({ attribute: "active-id" })
|
|
141
|
+
], o.prototype, "activeId", 2);
|
|
142
|
+
s([
|
|
143
|
+
n()
|
|
144
|
+
], o.prototype, "header", 2);
|
|
145
|
+
s([
|
|
146
|
+
n({ type: Boolean, reflect: !0 })
|
|
147
|
+
], o.prototype, "collapsed", 2);
|
|
148
|
+
o = s([
|
|
149
|
+
g("dp-sidebar")
|
|
150
|
+
], o);
|
|
151
|
+
export {
|
|
152
|
+
o as DpSidebar,
|
|
153
|
+
$ as DpSidebarSelectEvent
|
|
154
|
+
};
|
package/dist/toolbar.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { css as p, LitElement as g, nothing as h, html as d } from "lit";
|
|
2
|
+
import { property as s, customElement as v } from "lit/decorators.js";
|
|
3
|
+
var f = Object.defineProperty, b = Object.getOwnPropertyDescriptor, o = (i, r, l, a) => {
|
|
4
|
+
for (var e = a > 1 ? void 0 : a ? b(r, l) : r, n = i.length - 1, c; n >= 0; n--)
|
|
5
|
+
(c = i[n]) && (e = (a ? c(r, l, e) : c(e)) || e);
|
|
6
|
+
return a && e && f(r, l, e), e;
|
|
7
|
+
};
|
|
8
|
+
class u extends Event {
|
|
9
|
+
constructor() {
|
|
10
|
+
super("dp-toolbar-toggle", { bubbles: !0, composed: !0 });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
let t = class extends g {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments), this.heading = "", this.subtitle = "", this.showToggle = !1, this.dragRegion = !1;
|
|
16
|
+
}
|
|
17
|
+
render() {
|
|
18
|
+
return d`
|
|
19
|
+
<div class="start">
|
|
20
|
+
${this.showToggle ? d`<button
|
|
21
|
+
class="toggle"
|
|
22
|
+
aria-label="Toggle sidebar"
|
|
23
|
+
@click=${() => this.dispatchEvent(new u())}
|
|
24
|
+
>
|
|
25
|
+
☰
|
|
26
|
+
</button>` : h}
|
|
27
|
+
<span class="title">${this.subtitle || this.heading}</span>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="drag-handle" part="drag-handle"></div>
|
|
30
|
+
<div class="actions"><slot name="actions"></slot></div>
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
t.styles = p`
|
|
35
|
+
:host {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
height: var(--dp-header-height, 52px);
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
padding: 0 var(--dc-space-4, 16px);
|
|
41
|
+
padding-inline-start: calc(var(--dc-space-4, 16px) + var(--dp-toolbar-inset-start, 0px));
|
|
42
|
+
padding-inline-end: calc(var(--dc-space-4, 16px) + var(--dp-toolbar-inset-end, 0px));
|
|
43
|
+
background: var(--dc-color-surface, #f7f7f8);
|
|
44
|
+
border-bottom: 1px solid var(--dc-color-border, #e2e2e4);
|
|
45
|
+
font-family: var(--dc-font-family, system-ui, sans-serif);
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
48
|
+
.start {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: var(--dc-space-4, 16px);
|
|
52
|
+
min-width: 0;
|
|
53
|
+
}
|
|
54
|
+
.title {
|
|
55
|
+
font-size: var(--dc-font-size-sm, 12px);
|
|
56
|
+
font-weight: var(--dc-font-weight-medium, 500);
|
|
57
|
+
color: var(--dc-color-text, #1a1a1e);
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
text-overflow: ellipsis;
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
}
|
|
62
|
+
.toggle {
|
|
63
|
+
appearance: none;
|
|
64
|
+
background: none;
|
|
65
|
+
border: none;
|
|
66
|
+
padding: 0;
|
|
67
|
+
font-size: var(--dc-font-size-lg, 15px);
|
|
68
|
+
color: var(--dc-color-text-secondary, #55555c);
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
line-height: 1;
|
|
71
|
+
}
|
|
72
|
+
.toggle:hover {
|
|
73
|
+
color: var(--dc-color-text, #1a1a1e);
|
|
74
|
+
}
|
|
75
|
+
.toggle:focus-visible {
|
|
76
|
+
outline: 2px solid var(--dc-color-accent, #2563eb);
|
|
77
|
+
outline-offset: 2px;
|
|
78
|
+
}
|
|
79
|
+
.drag-handle {
|
|
80
|
+
flex: 1;
|
|
81
|
+
align-self: stretch;
|
|
82
|
+
min-width: var(--dc-space-4, 16px);
|
|
83
|
+
}
|
|
84
|
+
.actions {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: var(--dc-space-3, 12px);
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
o([
|
|
91
|
+
s()
|
|
92
|
+
], t.prototype, "heading", 2);
|
|
93
|
+
o([
|
|
94
|
+
s()
|
|
95
|
+
], t.prototype, "subtitle", 2);
|
|
96
|
+
o([
|
|
97
|
+
s({ type: Boolean, attribute: "show-toggle" })
|
|
98
|
+
], t.prototype, "showToggle", 2);
|
|
99
|
+
o([
|
|
100
|
+
s({ type: Boolean, reflect: !0, attribute: "drag-region" })
|
|
101
|
+
], t.prototype, "dragRegion", 2);
|
|
102
|
+
t = o([
|
|
103
|
+
v("dp-toolbar")
|
|
104
|
+
], t);
|
|
105
|
+
export {
|
|
106
|
+
t as DpToolbar,
|
|
107
|
+
u as DpToolbarToggleEvent
|
|
108
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iyulab/desktop-patterns",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"tokens.css"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./page": {
|
|
22
|
+
"types": "./dist/components/page/dp-page.d.ts",
|
|
23
|
+
"import": "./dist/page.js"
|
|
24
|
+
},
|
|
25
|
+
"./tokens.css": "./tokens.css"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "vite build",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "web-test-runner \"src/**/*.test.ts\"",
|
|
31
|
+
"test:watch": "web-test-runner \"src/**/*.test.ts\" --watch",
|
|
32
|
+
"guard": "node scripts/check-forge-tokens.mjs",
|
|
33
|
+
"guard:test": "node --test scripts/*.test.mjs",
|
|
34
|
+
"storybook": "storybook dev -p 6007",
|
|
35
|
+
"build-storybook": "storybook build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@iyulab/desktop-compact": "^0.1.0",
|
|
39
|
+
"lit": "^3.2.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@open-wc/testing": "^4.0.0",
|
|
43
|
+
"@storybook/addon-essentials": "^8.3.0",
|
|
44
|
+
"@storybook/web-components": "^8.3.0",
|
|
45
|
+
"@storybook/web-components-vite": "^8.3.0",
|
|
46
|
+
"@types/mocha": "^10.0.10",
|
|
47
|
+
"@web/dev-server-esbuild": "^1.0.2",
|
|
48
|
+
"@web/test-runner": "^0.19.0",
|
|
49
|
+
"storybook": "^8.3.0",
|
|
50
|
+
"typescript": "^5.6.3",
|
|
51
|
+
"vite": "^5.4.10",
|
|
52
|
+
"vite-plugin-dts": "^4.2.4"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/tokens.css
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Structural tokens for @iyulab/desktop-patterns.
|
|
3
|
+
*
|
|
4
|
+
* This file adds ONLY the dimensions this layer introduces that
|
|
5
|
+
* @iyulab/desktop-compact has no concept of (sidebar/header sizing). Color,
|
|
6
|
+
* spacing-scale, radius, and typography tokens are NOT duplicated here —
|
|
7
|
+
* import @iyulab/desktop-compact/tokens.css alongside this file; every
|
|
8
|
+
* desktop-patterns component consumes --dc-* directly.
|
|
9
|
+
*/
|
|
10
|
+
:root {
|
|
11
|
+
--dp-sidebar-width: 220px;
|
|
12
|
+
--dp-sidebar-width-collapsed: 52px;
|
|
13
|
+
--dp-header-height: 52px;
|
|
14
|
+
}
|