@c2n/sheet 0.0.7
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 +31 -0
- package/dist/sheet.js +166 -0
- package/package.json +73 -0
- package/react.d.ts +24 -0
- package/react.js +3 -0
- package/types/src/sheet.d.ts +129 -0
- package/types/src/sheet.d.ts.map +1 -0
- package/vue.d.ts +39 -0
- package/vue.js +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Nguyen Thai Vinh
|
|
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,31 @@
|
|
|
1
|
+
# @c2n/sheet
|
|
2
|
+
|
|
3
|
+
Sheet built with Lit: a dialog pinned to an edge of the screen, for content that complements the page rather than interrupting it.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @c2n/sheet
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script type="module">
|
|
11
|
+
import '@c2n/sheet'
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<button onclick="document.getElementById('filters').show()">Filters</button>
|
|
15
|
+
|
|
16
|
+
<c2-sheet id="filters">
|
|
17
|
+
<span slot="title">Filters</span>
|
|
18
|
+
<p>Anything that belongs beside the page rather than over it.</p>
|
|
19
|
+
<button slot="footer" onclick="this.closest('c2-sheet').close('applied')">Apply</button>
|
|
20
|
+
</c2-sheet>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **Edges**: `side="right"` (default), `left`, `top` or `bottom`. The panel spans its edge and slides in from off-screen; `--c2-sheet--size` is the width of a left/right sheet and the height of a top/bottom one, and the other axis fills the screen.
|
|
24
|
+
- **Dialog behaviour**: built on the native `<dialog>` opened with `showModal()`, so focus is trapped and restored, the page behind is inert and covered by a backdrop, and Escape closes. `hide-close`, `no-backdrop-close`, `no-escape` and `no-scroll-lock` each opt out of one piece.
|
|
25
|
+
- **Structure**: `title` slot (it labels the sheet; `label` names one without a visible heading), the default slot for the body, `footer` for actions. Only the body scrolls, so the header and footer stay put in a full-height panel.
|
|
26
|
+
- **Events**: `open` after showing, `close` with `detail.returnValue`, and the native cancelable `cancel` on Escape.
|
|
27
|
+
- **Nesting**: a sheet can hold another overlay. The page scroll lock is shared through `@c2n/core`, and each overlay only reacts to its own dialog's events, so closing an inner confirm leaves the sheet standing and the page locked.
|
|
28
|
+
|
|
29
|
+
Theme it with `--c2-sheet--size`, `--c2-sheet--border-radius` (the two corners facing the page), `--c2-sheet--background`, `--c2-sheet--color`, `--c2-sheet--box-shadow`, `--c2-sheet--transition-duration` and the `__header`, `__body`, `__footer`, `__close` and `__backdrop` groups — the same names [`@c2n/modal`](../modal) uses, so a dialog and a sheet can be themed together. The full list is in `custom-elements.json` and on the docs site.
|
|
30
|
+
|
|
31
|
+
Use [`@c2n/modal`](../modal) when the page must stop for a decision, and [`@c2n/side-nav`](../side-nav) when the panel is navigation that is part of the layout rather than a transient overlay.
|
package/dist/sheet.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { LitElement, html, nothing, unsafeCSS } from "lit";
|
|
2
|
+
import { isServer } from "lit-html/is-server.js";
|
|
3
|
+
import { property, query, state } from "lit/decorators.js";
|
|
4
|
+
import { customElement } from "@c2n/core/element-helper.js";
|
|
5
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
6
|
+
import { lockPageScroll, redispatchEvent } from "@c2n/core/dom-helper.js";
|
|
7
|
+
//#region src/sheet.scss?inline
|
|
8
|
+
var sheet_default = "/* ex : var((width: 24px), width, c2-checkbox) returns var(--c2-checkbox-width, 24px) */\n:host {\n display: contents;\n}\n\n.c2-sheet {\n box-sizing: border-box;\n position: fixed;\n max-width: 100vw;\n max-height: 100dvh;\n padding: 0;\n border: var(--c2-sheet--border,none);\n background: var(--c2-sheet--background,#ffffff);\n color: var(--c2-sheet--color,#18181b);\n box-shadow: var(--c2-sheet--box-shadow,0 24px 60px rgba(0, 0, 0, 0.25));\n overflow: hidden;\n transform: var(--_c2-sheet-enter);\n transition: transform var(--c2-sheet--transition-duration,280ms) cubic-bezier(0.2, 0, 0, 1), display var(--c2-sheet--transition-duration,280ms) allow-discrete, overlay var(--c2-sheet--transition-duration,280ms) allow-discrete;\n}\n.c2-sheet[open] {\n transform: none;\n}\n.c2-sheet::backdrop {\n background: var(--c2-sheet__backdrop--background,rgba(9, 9, 11, 0.45));\n backdrop-filter: var(--c2-sheet__backdrop--backdrop-filter);\n opacity: 0;\n transition: opacity var(--c2-sheet--transition-duration,280ms) cubic-bezier(0.2, 0, 0, 1), display var(--c2-sheet--transition-duration,280ms) allow-discrete, overlay var(--c2-sheet--transition-duration,280ms) allow-discrete;\n}\n.c2-sheet[open]::backdrop {\n opacity: 1;\n}\n\n:host([side=right]) .c2-sheet {\n inset: 0 0 0 auto;\n width: var(--c2-sheet--size,380px);\n height: 100dvh;\n --_c2-sheet-enter: translateX(100%);\n border-top-left-radius: var(--c2-sheet--border-radius,0px);\n border-bottom-left-radius: var(--c2-sheet--border-radius,0px);\n}\n\n:host([side=left]) .c2-sheet {\n inset: 0 auto 0 0;\n width: var(--c2-sheet--size,380px);\n height: 100dvh;\n --_c2-sheet-enter: translateX(-100%);\n border-top-right-radius: var(--c2-sheet--border-radius,0px);\n border-bottom-right-radius: var(--c2-sheet--border-radius,0px);\n}\n\n:host([side=top]) .c2-sheet {\n inset: 0 0 auto 0;\n width: 100vw;\n height: var(--c2-sheet--size,380px);\n --_c2-sheet-enter: translateY(-100%);\n border-bottom-left-radius: var(--c2-sheet--border-radius,0px);\n border-bottom-right-radius: var(--c2-sheet--border-radius,0px);\n}\n\n:host([side=bottom]) .c2-sheet {\n inset: auto 0 0 0;\n width: 100vw;\n height: var(--c2-sheet--size,380px);\n --_c2-sheet-enter: translateY(100%);\n border-top-left-radius: var(--c2-sheet--border-radius,0px);\n border-top-right-radius: var(--c2-sheet--border-radius,0px);\n}\n\n@starting-style {\n .c2-sheet[open] {\n transform: var(--_c2-sheet-enter);\n }\n .c2-sheet[open]::backdrop {\n opacity: 0;\n }\n}\n.c2-sheet__panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n\n.c2-sheet__header {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n flex: none;\n padding-top: var(--c2-sheet__header--padding-top,20px);\n padding-right: var(--c2-sheet__header--padding-right,20px);\n padding-bottom: var(--c2-sheet__header--padding-bottom,0px);\n padding-left: var(--c2-sheet__header--padding-left,24px);\n border-bottom: var(--c2-sheet__header--border-bottom);\n}\n.c2-sheet__header[hidden] {\n display: none;\n}\n\n.c2-sheet__title {\n flex: 1;\n min-width: 0;\n font-size: var(--c2-sheet__header--font-size,17px);\n font-weight: var(--c2-sheet__header--font-weight,600);\n line-height: var(--c2-sheet__header--line-height,1.35);\n min-height: var(--c2-sheet__close--size,32px);\n display: flex;\n align-items: center;\n}\n.c2-sheet__title ::slotted(*) {\n margin: 0;\n font: inherit;\n}\n\n.c2-sheet__close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n box-sizing: border-box;\n width: var(--c2-sheet__close--size,32px);\n height: var(--c2-sheet__close--size,32px);\n margin: 0;\n padding: 0;\n border: none;\n border-radius: var(--c2-sheet__close--border-radius,8px);\n background: transparent;\n color: var(--c2-sheet__close--color,#71717a);\n cursor: pointer;\n transition: background 250ms cubic-bezier(0.2, 0, 0, 1), color 250ms cubic-bezier(0.2, 0, 0, 1);\n}\n.c2-sheet__close svg,\n.c2-sheet__close ::slotted(*) {\n width: var(--c2-sheet__close--icon-size,18px);\n height: var(--c2-sheet__close--icon-size,18px);\n}\n.c2-sheet__close:hover {\n background: var(--c2-sheet__close__hover--background,#f4f4f5);\n color: var(--c2-sheet__close__hover--color,#18181b);\n}\n.c2-sheet__close:focus-visible {\n outline: var(--c2-sheet__close__focus--outline,2px solid rgba(2, 101, 220, 0.4));\n outline-offset: 1px;\n}\n\n.c2-sheet__body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding-top: var(--c2-sheet__body--padding-top,12px);\n padding-right: var(--c2-sheet__body--padding-right,24px);\n padding-bottom: var(--c2-sheet__body--padding-bottom,20px);\n padding-left: var(--c2-sheet__body--padding-left,24px);\n font-size: var(--c2-sheet__body--font-size,14px);\n line-height: var(--c2-sheet__body--line-height,1.6);\n color: var(--c2-sheet__body--color);\n}\n\n.c2-sheet__footer {\n display: flex;\n align-items: center;\n flex: none;\n gap: var(--c2-sheet__footer--gap,8px);\n justify-content: var(--c2-sheet__footer--justify-content,flex-end);\n padding-top: var(--c2-sheet__footer--padding-top,12px);\n padding-right: var(--c2-sheet__footer--padding-right,24px);\n padding-bottom: var(--c2-sheet__footer--padding-bottom,20px);\n padding-left: var(--c2-sheet__footer--padding-left,24px);\n border-top: var(--c2-sheet__footer--border-top);\n}\n.c2-sheet__footer[hidden] {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .c2-sheet {\n --_c2-sheet-enter: none;\n transition: display var(--c2-sheet--transition-duration,280ms) allow-discrete, overlay var(--c2-sheet--transition-duration,280ms) allow-discrete;\n }\n}";
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
|
|
11
|
+
function __decorate(decorators, target, key, desc) {
|
|
12
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
13
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
14
|
+
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;
|
|
15
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/sheet.ts
|
|
19
|
+
var Sheet = class Sheet extends LitElement {
|
|
20
|
+
constructor(..._args) {
|
|
21
|
+
super(..._args);
|
|
22
|
+
this.open = false;
|
|
23
|
+
this.side = "right";
|
|
24
|
+
this.label = void 0;
|
|
25
|
+
this.noBackdropClose = false;
|
|
26
|
+
this.noEscape = false;
|
|
27
|
+
this.hideClose = false;
|
|
28
|
+
this.noScrollLock = false;
|
|
29
|
+
this.returnValue = "";
|
|
30
|
+
this.hasTitle = false;
|
|
31
|
+
this.hasFooter = false;
|
|
32
|
+
this.handleDialogClose = (event) => {
|
|
33
|
+
if (event.target !== this.dialog) return;
|
|
34
|
+
this.returnValue = this.dialog.returnValue;
|
|
35
|
+
this.unlockScroll();
|
|
36
|
+
this.open = false;
|
|
37
|
+
this.dispatchEvent(new CustomEvent("close", {
|
|
38
|
+
detail: { returnValue: this.returnValue },
|
|
39
|
+
bubbles: true,
|
|
40
|
+
composed: true
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
this.handleDialogCancel = (event) => {
|
|
44
|
+
if (event.target !== this.dialog) return;
|
|
45
|
+
if (this.noEscape) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!redispatchEvent(this, event)) event.preventDefault();
|
|
50
|
+
};
|
|
51
|
+
this.handleDialogClick = (event) => {
|
|
52
|
+
if (event.target === this.dialog && !this.noBackdropClose) this.close();
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
static {
|
|
56
|
+
this.styles = unsafeCSS(sheet_default);
|
|
57
|
+
}
|
|
58
|
+
disconnectedCallback() {
|
|
59
|
+
super.disconnectedCallback();
|
|
60
|
+
this.unlockScroll();
|
|
61
|
+
}
|
|
62
|
+
/** Opens the sheet (modal). */
|
|
63
|
+
show() {
|
|
64
|
+
this.open = true;
|
|
65
|
+
}
|
|
66
|
+
/** Closes the sheet with an optional `returnValue`. */
|
|
67
|
+
close(returnValue = "") {
|
|
68
|
+
this.returnValue = returnValue;
|
|
69
|
+
if (this.dialog?.open) this.dialog.close(returnValue);
|
|
70
|
+
else this.open = false;
|
|
71
|
+
}
|
|
72
|
+
lockScroll() {
|
|
73
|
+
if (this.noScrollLock || this.releaseScroll || isServer) return;
|
|
74
|
+
this.releaseScroll = lockPageScroll();
|
|
75
|
+
}
|
|
76
|
+
unlockScroll() {
|
|
77
|
+
this.releaseScroll?.();
|
|
78
|
+
this.releaseScroll = void 0;
|
|
79
|
+
}
|
|
80
|
+
handleSlotChange(event) {
|
|
81
|
+
this.updateSlot(event.target);
|
|
82
|
+
}
|
|
83
|
+
updateSlot(slot) {
|
|
84
|
+
const filled = slot.assignedNodes({ flatten: true }).some((n) => n.nodeType === Node.ELEMENT_NODE || (n.textContent ?? "").trim() !== "");
|
|
85
|
+
if (slot.name === "title") this.hasTitle = filled;
|
|
86
|
+
else if (slot.name === "footer") this.hasFooter = filled;
|
|
87
|
+
}
|
|
88
|
+
firstUpdated() {
|
|
89
|
+
for (const slot of this.renderRoot.querySelectorAll("slot")) this.updateSlot(slot);
|
|
90
|
+
}
|
|
91
|
+
updated(changed) {
|
|
92
|
+
if (changed.has("open") && !isServer && this.dialog) {
|
|
93
|
+
if (this.open && !this.dialog.open) {
|
|
94
|
+
this.dialog.showModal();
|
|
95
|
+
this.lockScroll();
|
|
96
|
+
this.dispatchEvent(new Event("open", {
|
|
97
|
+
bubbles: true,
|
|
98
|
+
composed: true
|
|
99
|
+
}));
|
|
100
|
+
} else if (!this.open && this.dialog.open) this.dialog.close(this.returnValue);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
render() {
|
|
104
|
+
return html`
|
|
105
|
+
<dialog
|
|
106
|
+
class="c2-sheet"
|
|
107
|
+
part="panel"
|
|
108
|
+
aria-labelledby=${this.hasTitle ? "title" : nothing}
|
|
109
|
+
aria-label=${!this.hasTitle && this.label ? this.label : nothing}
|
|
110
|
+
@close=${this.handleDialogClose}
|
|
111
|
+
@cancel=${this.handleDialogCancel}
|
|
112
|
+
@click=${this.handleDialogClick}
|
|
113
|
+
>
|
|
114
|
+
<div class=${classMap({
|
|
115
|
+
"c2-sheet__panel": true,
|
|
116
|
+
"has-title": this.hasTitle,
|
|
117
|
+
"has-footer": this.hasFooter
|
|
118
|
+
})}>
|
|
119
|
+
<header class="c2-sheet__header" part="header" ?hidden=${!this.hasTitle && this.hideClose}>
|
|
120
|
+
<div class="c2-sheet__title" id="title"><slot name="title" @slotchange=${this.handleSlotChange}></slot></div>
|
|
121
|
+
${this.hideClose ? nothing : html`<button class="c2-sheet__close" part="close" type="button" aria-label="Close" @click=${() => this.close()}>
|
|
122
|
+
<slot name="close-icon">
|
|
123
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
124
|
+
<path d="M18 6 6 18M6 6l12 12"></path>
|
|
125
|
+
</svg>
|
|
126
|
+
</slot>
|
|
127
|
+
</button>`}
|
|
128
|
+
</header>
|
|
129
|
+
<div class="c2-sheet__body" part="body"><slot></slot></div>
|
|
130
|
+
<footer class="c2-sheet__footer" part="footer" ?hidden=${!this.hasFooter}>
|
|
131
|
+
<slot name="footer" @slotchange=${this.handleSlotChange}></slot>
|
|
132
|
+
</footer>
|
|
133
|
+
</div>
|
|
134
|
+
</dialog>
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
__decorate([property({
|
|
139
|
+
type: Boolean,
|
|
140
|
+
reflect: true
|
|
141
|
+
})], Sheet.prototype, "open", void 0);
|
|
142
|
+
__decorate([property({ reflect: true })], Sheet.prototype, "side", void 0);
|
|
143
|
+
__decorate([property()], Sheet.prototype, "label", void 0);
|
|
144
|
+
__decorate([property({
|
|
145
|
+
type: Boolean,
|
|
146
|
+
attribute: "no-backdrop-close"
|
|
147
|
+
})], Sheet.prototype, "noBackdropClose", void 0);
|
|
148
|
+
__decorate([property({
|
|
149
|
+
type: Boolean,
|
|
150
|
+
attribute: "no-escape"
|
|
151
|
+
})], Sheet.prototype, "noEscape", void 0);
|
|
152
|
+
__decorate([property({
|
|
153
|
+
type: Boolean,
|
|
154
|
+
reflect: true,
|
|
155
|
+
attribute: "hide-close"
|
|
156
|
+
})], Sheet.prototype, "hideClose", void 0);
|
|
157
|
+
__decorate([property({
|
|
158
|
+
type: Boolean,
|
|
159
|
+
attribute: "no-scroll-lock"
|
|
160
|
+
})], Sheet.prototype, "noScrollLock", void 0);
|
|
161
|
+
__decorate([state()], Sheet.prototype, "hasTitle", void 0);
|
|
162
|
+
__decorate([state()], Sheet.prototype, "hasFooter", void 0);
|
|
163
|
+
__decorate([query("dialog")], Sheet.prototype, "dialog", void 0);
|
|
164
|
+
Sheet = __decorate([customElement("c2-sheet")], Sheet);
|
|
165
|
+
//#endregion
|
|
166
|
+
export { Sheet };
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@c2n/sheet",
|
|
3
|
+
"version": "0.0.7",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/sheet.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./types/src/sheet.d.ts",
|
|
9
|
+
"default": "./dist/sheet.js"
|
|
10
|
+
},
|
|
11
|
+
"./react": {
|
|
12
|
+
"types": "./react.d.ts",
|
|
13
|
+
"default": "./react.js"
|
|
14
|
+
},
|
|
15
|
+
"./vue": {
|
|
16
|
+
"types": "./vue.d.ts",
|
|
17
|
+
"default": "./vue.js"
|
|
18
|
+
},
|
|
19
|
+
"./custom-elements.json": "./custom-elements.json"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"types",
|
|
24
|
+
"react.d.ts",
|
|
25
|
+
"react.js",
|
|
26
|
+
"vue.d.ts",
|
|
27
|
+
"vue.js"
|
|
28
|
+
],
|
|
29
|
+
"keywords": [
|
|
30
|
+
"sheet",
|
|
31
|
+
"web component",
|
|
32
|
+
"lit"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"author": "code2nguyen@gmail.com",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"registry": "https://registry.npmjs.org",
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/code2nguyen/web-components.git"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"dev": "vite",
|
|
46
|
+
"build": "wireit",
|
|
47
|
+
"build:only": "vite build",
|
|
48
|
+
"type-check": "wireit"
|
|
49
|
+
},
|
|
50
|
+
"wireit": {
|
|
51
|
+
"type-check": {
|
|
52
|
+
"dependencies": [
|
|
53
|
+
"../../core:build"
|
|
54
|
+
],
|
|
55
|
+
"command": "tsc -p tsconfig.lib.json --composite false"
|
|
56
|
+
},
|
|
57
|
+
"build": {
|
|
58
|
+
"dependencies": [
|
|
59
|
+
"type-check"
|
|
60
|
+
],
|
|
61
|
+
"command": "vite build"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@c2n/core": "0.0.7",
|
|
66
|
+
"lit": "3.3.3"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@c2n/config": "*"
|
|
70
|
+
},
|
|
71
|
+
"customElements": "custom-elements.json",
|
|
72
|
+
"gitHead": "c8db398a27f7cd417d665fdf5da455fee2d4e910"
|
|
73
|
+
}
|
package/react.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// GENERATED by @c2n/framework-types. Do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// JSX types for the custom elements of @c2n/sheet. Import once, anywhere in the program:
|
|
4
|
+
//
|
|
5
|
+
// import '@c2n/sheet/react'
|
|
6
|
+
//
|
|
7
|
+
// Register the elements at module scope before React renders, or React writes an object prop as an
|
|
8
|
+
// attribute and it stringifies.
|
|
9
|
+
|
|
10
|
+
import type { DetailedHTMLProps, HTMLAttributes } from 'react'
|
|
11
|
+
import type { Sheet } from '@c2n/sheet'
|
|
12
|
+
|
|
13
|
+
/** Standard React host-element attributes plus the element's own public properties. */
|
|
14
|
+
type C2Props<T> = DetailedHTMLProps<HTMLAttributes<T>, T> & Partial<Omit<T, keyof HTMLElement>>
|
|
15
|
+
|
|
16
|
+
declare module 'react' {
|
|
17
|
+
namespace JSX {
|
|
18
|
+
interface IntrinsicElements {
|
|
19
|
+
'c2-sheet': C2Props<Sheet>
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {}
|
package/react.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { LitElement, type PropertyValues } from 'lit';
|
|
2
|
+
import type { TypedAddEventListener, TypedRemoveEventListener } from '@c2n/core/event-helper.js';
|
|
3
|
+
export type SheetSide = 'right' | 'left' | 'top' | 'bottom';
|
|
4
|
+
/** Events fired by {@link Sheet}, keyed for `addEventListener`. */
|
|
5
|
+
export interface SheetEventMap {
|
|
6
|
+
open: Event;
|
|
7
|
+
close: CustomEvent<{
|
|
8
|
+
returnValue: string;
|
|
9
|
+
}>;
|
|
10
|
+
cancel: Event;
|
|
11
|
+
}
|
|
12
|
+
export interface Sheet {
|
|
13
|
+
addEventListener: TypedAddEventListener<Sheet, SheetEventMap>;
|
|
14
|
+
removeEventListener: TypedRemoveEventListener<Sheet, SheetEventMap>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Dialog pinned to an edge of the screen, for content that complements the page rather than interrupting it: filters,
|
|
18
|
+
* details, a form beside the record it edits. Built on the native `<dialog>` like `c2-modal`, so focus is trapped and
|
|
19
|
+
* restored, the page behind is inert and covered by a backdrop, and Escape closes — but the panel spans its edge and
|
|
20
|
+
* slides in from it instead of being centred.
|
|
21
|
+
*
|
|
22
|
+
* `side` picks the edge (`right` by default). `--c2-sheet--size` is the width of a left/right sheet and the height of
|
|
23
|
+
* a top/bottom one; the opposite axis always fills the screen. Open it with the `open` attribute or `show()`, close it
|
|
24
|
+
* with `close(returnValue)`, the built-in close button, a click on the backdrop or Escape (each can be turned off).
|
|
25
|
+
* Content is split into a `title` slot, the body (default slot) and a `footer` slot for actions, and the body scrolls
|
|
26
|
+
* on its own so the header and footer stay put in a full-height panel.
|
|
27
|
+
*
|
|
28
|
+
* Use `c2-modal` for a decision that blocks the page, and `c2-side-nav` for navigation that is part of the layout
|
|
29
|
+
* rather than a transient overlay.
|
|
30
|
+
*
|
|
31
|
+
* @tag c2-sheet
|
|
32
|
+
*
|
|
33
|
+
* @slot - Body content.
|
|
34
|
+
* @slot title - Heading shown in the header; the sheet is labelled by it.
|
|
35
|
+
* @slot footer - Actions row (a flex row, see the `footer--*` variables).
|
|
36
|
+
* @slot close-icon - Replaces the default × icon of the close button.
|
|
37
|
+
*
|
|
38
|
+
* @event {Event} open - Fired after the sheet has been shown.
|
|
39
|
+
* @event {CustomEvent<{ returnValue: string }>} close - Fired after the sheet has closed; `detail.returnValue` is what `close()` received (`''` for Escape / backdrop / the × button).
|
|
40
|
+
* @event {Event} cancel - Native, cancelable: fired on Escape before closing.
|
|
41
|
+
*
|
|
42
|
+
* @cssproperty {pixel} [--c2-sheet--size=380px] - Width of a `left`/`right` sheet, height of a `top`/`bottom` one. The other axis fills the screen.
|
|
43
|
+
* @cssproperty {background} [--c2-sheet--background=#ffffff]
|
|
44
|
+
* @cssproperty {color} [--c2-sheet--color=#18181b]
|
|
45
|
+
* @cssproperty {border} [--c2-sheet--border=none]
|
|
46
|
+
* @cssproperty {border-radius} [--c2-sheet--border-radius=0px] - Rounds the two corners facing the page; the edge stays square.
|
|
47
|
+
* @cssproperty {box-shadow} [--c2-sheet--box-shadow=0 24px 60px rgba(0, 0, 0, 0.25)]
|
|
48
|
+
* @cssproperty {time} [--c2-sheet--transition-duration=280ms] - Slide in and out; `0ms` disables it.
|
|
49
|
+
*
|
|
50
|
+
* @cssproperty {padding} [--c2-sheet__header--padding-top=20px]
|
|
51
|
+
* @cssproperty {padding} [--c2-sheet__header--padding-right=20px]
|
|
52
|
+
* @cssproperty {padding} [--c2-sheet__header--padding-bottom=0px]
|
|
53
|
+
* @cssproperty {padding} [--c2-sheet__header--padding-left=24px]
|
|
54
|
+
* @cssproperty {font-size} [--c2-sheet__header--font-size=17px]
|
|
55
|
+
* @cssproperty {font-weight} [--c2-sheet__header--font-weight=600]
|
|
56
|
+
* @cssproperty {line-height} [--c2-sheet__header--line-height=1.35]
|
|
57
|
+
* @cssproperty {border} --c2-sheet__header--border-bottom - Divider under the header; raise `header--padding-bottom` with it.
|
|
58
|
+
*
|
|
59
|
+
* @cssproperty {padding} [--c2-sheet__body--padding-top=12px]
|
|
60
|
+
* @cssproperty {padding} [--c2-sheet__body--padding-right=24px]
|
|
61
|
+
* @cssproperty {padding} [--c2-sheet__body--padding-bottom=20px]
|
|
62
|
+
* @cssproperty {padding} [--c2-sheet__body--padding-left=24px]
|
|
63
|
+
* @cssproperty {font-size} [--c2-sheet__body--font-size=14px]
|
|
64
|
+
* @cssproperty {line-height} [--c2-sheet__body--line-height=1.6]
|
|
65
|
+
* @cssproperty {color} --c2-sheet__body--color - Defaults to the sheet colour.
|
|
66
|
+
*
|
|
67
|
+
* @cssproperty {padding} [--c2-sheet__footer--padding-top=12px]
|
|
68
|
+
* @cssproperty {padding} [--c2-sheet__footer--padding-right=24px]
|
|
69
|
+
* @cssproperty {padding} [--c2-sheet__footer--padding-bottom=20px]
|
|
70
|
+
* @cssproperty {padding} [--c2-sheet__footer--padding-left=24px]
|
|
71
|
+
* @cssproperty {pixel} [--c2-sheet__footer--gap=8px]
|
|
72
|
+
* @cssproperty {justify-content} [--c2-sheet__footer--justify-content=flex-end]
|
|
73
|
+
* @cssproperty {border} --c2-sheet__footer--border-top - Divider above the footer; raise `footer--padding-top` with it.
|
|
74
|
+
*
|
|
75
|
+
* @cssproperty {pixel} [--c2-sheet__close--size=32px]
|
|
76
|
+
* @cssproperty {pixel} [--c2-sheet__close--icon-size=18px]
|
|
77
|
+
* @cssproperty {border-radius} [--c2-sheet__close--border-radius=8px]
|
|
78
|
+
* @cssproperty {color} [--c2-sheet__close--color=#71717a]
|
|
79
|
+
* @cssproperty {background} [--c2-sheet__close__hover--background=#f4f4f5]
|
|
80
|
+
* @cssproperty {color} [--c2-sheet__close__hover--color=#18181b]
|
|
81
|
+
* @cssproperty {outline} [--c2-sheet__close__focus--outline=2px solid rgba(2, 101, 220, 0.4)]
|
|
82
|
+
*
|
|
83
|
+
* @cssproperty {background} [--c2-sheet__backdrop--background=rgba(9, 9, 11, 0.45)]
|
|
84
|
+
* @cssproperty {backdrop-filter} --c2-sheet__backdrop--backdrop-filter - e.g. `blur(4px)`.
|
|
85
|
+
*/
|
|
86
|
+
export declare class Sheet extends LitElement {
|
|
87
|
+
static styles: import("lit").CSSResult;
|
|
88
|
+
/** Open state. Setting it shows or closes the sheet. */
|
|
89
|
+
open: boolean;
|
|
90
|
+
/** Edge the sheet is pinned to and slides in from. */
|
|
91
|
+
side: SheetSide;
|
|
92
|
+
/** Accessible name when there is no `title` slot. */
|
|
93
|
+
label: string | undefined;
|
|
94
|
+
/** Keep the sheet open when the backdrop is clicked. */
|
|
95
|
+
noBackdropClose: boolean;
|
|
96
|
+
/** Ignore Escape. */
|
|
97
|
+
noEscape: boolean;
|
|
98
|
+
/** Hide the built-in × button. */
|
|
99
|
+
hideClose: boolean;
|
|
100
|
+
/** Leave the page scrollable while the sheet is open. */
|
|
101
|
+
noScrollLock: boolean;
|
|
102
|
+
/** Value passed to the last `close()` call, mirrors `HTMLDialogElement.returnValue`. */
|
|
103
|
+
returnValue: string;
|
|
104
|
+
private hasTitle;
|
|
105
|
+
private hasFooter;
|
|
106
|
+
private dialog;
|
|
107
|
+
private releaseScroll;
|
|
108
|
+
disconnectedCallback(): void;
|
|
109
|
+
/** Opens the sheet (modal). */
|
|
110
|
+
show(): void;
|
|
111
|
+
/** Closes the sheet with an optional `returnValue`. */
|
|
112
|
+
close(returnValue?: string): void;
|
|
113
|
+
private lockScroll;
|
|
114
|
+
private unlockScroll;
|
|
115
|
+
private handleDialogClose;
|
|
116
|
+
private handleDialogCancel;
|
|
117
|
+
private handleDialogClick;
|
|
118
|
+
private handleSlotChange;
|
|
119
|
+
private updateSlot;
|
|
120
|
+
firstUpdated(): void;
|
|
121
|
+
updated(changed: PropertyValues<this>): void;
|
|
122
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
123
|
+
}
|
|
124
|
+
declare global {
|
|
125
|
+
interface HTMLElementTagNameMap {
|
|
126
|
+
'c2-sheet': Sheet;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/sheet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA4B,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAI/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAKhG,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;AAE3D,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,WAAW,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3C,MAAM,EAAE,KAAK,CAAA;CACd;AAED,MAAM,WAAW,KAAK;IACpB,gBAAgB,EAAE,qBAAqB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;IAC7D,mBAAmB,EAAE,wBAAwB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;CACpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,qBACa,KAAM,SAAQ,UAAU;IACnC,OAAgB,MAAM,0BAAoB;IAE1C,wDAAwD;IACZ,IAAI,UAAQ;IAExD,sDAAsD;IACzB,IAAI,EAAE,SAAS,CAAU;IAEtD,qDAAqD;IACzC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAY;IAEjD,wDAAwD;IACK,eAAe,UAAQ;IAEpF,qBAAqB;IACgC,QAAQ,UAAQ;IAErE,kCAAkC;IACmC,SAAS,UAAQ;IAEtF,yDAAyD;IACC,YAAY,UAAQ;IAE9E,wFAAwF;IACxF,WAAW,SAAK;IAEP,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAQ;IAEjB,OAAO,CAAC,MAAM,CAAoB;IAEnD,OAAO,CAAC,aAAa,CAA0B;IAEtC,oBAAoB;IAK7B,+BAA+B;IAC/B,IAAI;IAIJ,uDAAuD;IACvD,KAAK,CAAC,WAAW,SAAK;IAMtB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,iBAAiB,CAOxB;IAED,OAAO,CAAC,kBAAkB,CAOzB;IAED,OAAO,CAAC,iBAAiB,CAGxB;IAED,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAMT,YAAY;IAIZ,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAYrC,MAAM;CAkChB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,KAAK,CAAA;KAClB;CACF"}
|
package/vue.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// GENERATED by @c2n/framework-types. Do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// Vue template types for the custom elements of @c2n/sheet. Import once, anywhere in the program:
|
|
4
|
+
//
|
|
5
|
+
// import '@c2n/sheet/vue'
|
|
6
|
+
//
|
|
7
|
+
// Tell the compiler about the tags as well, or every c2-* tag is resolved as a Vue component and renders
|
|
8
|
+
// nothing: template.compilerOptions.isCustomElement = (tag) => tag.startsWith('c2-') in vite.config.ts.
|
|
9
|
+
|
|
10
|
+
import type { DefineComponent, HTMLAttributes } from 'vue'
|
|
11
|
+
import type { Sheet, SheetEventMap } from '@c2n/sheet'
|
|
12
|
+
|
|
13
|
+
/** The element's own public properties, plus every attribute Vue understands on a host element. */
|
|
14
|
+
type C2Props<T> = Partial<Omit<T, keyof HTMLElement>> & HTMLAttributes
|
|
15
|
+
|
|
16
|
+
declare module 'vue' {
|
|
17
|
+
interface GlobalComponents {
|
|
18
|
+
'c2-sheet': DefineComponent<
|
|
19
|
+
C2Props<Sheet> & {
|
|
20
|
+
'no-backdrop-close'?: unknown
|
|
21
|
+
'no-escape'?: unknown
|
|
22
|
+
'hide-close'?: unknown
|
|
23
|
+
'no-scroll-lock'?: unknown
|
|
24
|
+
onOpen?: (event: SheetEventMap['open']) => void
|
|
25
|
+
onClose?: (event: SheetEventMap['close']) => void
|
|
26
|
+
onCancel?: (event: SheetEventMap['cancel']) => void
|
|
27
|
+
}
|
|
28
|
+
>
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare module '@vue/runtime-dom' {
|
|
33
|
+
interface HTMLAttributes {
|
|
34
|
+
/** Vue's own definition omits it, and slotting a plain element into a component needs it. */
|
|
35
|
+
slot?: string
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export {}
|
package/vue.js
ADDED