@anton-gustafsson/snapshot-core 0.4.3 → 0.4.4
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/dist/snapshot-nav-list.d.ts +13 -1
- package/dist/snapshot-nav-list.js +96 -17
- package/package.json +1 -1
|
@@ -4,8 +4,10 @@ export interface NavItem<T = unknown> {
|
|
|
4
4
|
/** The snapshot id — a plain domain id. Anything else the consumer needs belongs in `data`. */
|
|
5
5
|
id: string;
|
|
6
6
|
label: string;
|
|
7
|
-
/**
|
|
7
|
+
/** Markup — `<svg>`, `<img>`, or any element — rendered as raw HTML in the placeholder frame shown before a card's first capture. Must start with `<`: a bare glyph or emoji is ignored (it read as an icon but rendered as a stray character at whatever the frame's font happened to be); use `placeholderText` for words. */
|
|
8
8
|
icon?: string;
|
|
9
|
+
/** Per-item override of the component-level `placeholderText` — a caption in the frame shown before this card's first capture (e.g. "not visited yet"). Plain text only; pass `''` to show none where the component sets one. */
|
|
10
|
+
placeholderText?: string;
|
|
9
11
|
description?: string;
|
|
10
12
|
/** Arbitrary consumer payload — echoed back verbatim on `nav-select` / `nav-edit`, so no lookup-by-id is needed in the handler. */
|
|
11
13
|
data?: T;
|
|
@@ -40,6 +42,14 @@ export declare class SnapshotNavList extends LitElement {
|
|
|
40
42
|
editButtonPosition: SnapshotNavListEditButtonPosition;
|
|
41
43
|
/** Edit button glyph. Same convention as `NavItem.icon`: a plain-text glyph (e.g. an emoji), or markup — a string starting with `<` renders as raw HTML/SVG, so a consumer can pass its own icon (e.g. `<svg>...</svg>`). */
|
|
42
44
|
editIcon: string;
|
|
45
|
+
/**
|
|
46
|
+
* Caption shown in the frame of a card with no capture yet (e.g. "no snapshot
|
|
47
|
+
* yet"), for every card at once; `NavItem.placeholderText` overrides it per
|
|
48
|
+
* row. Plain text, never markup — it's rendered as text, not HTML. Empty by
|
|
49
|
+
* default, which keeps the icon-and-hatch placeholder; set it and the frame
|
|
50
|
+
* goes see-through with a dashed edge instead.
|
|
51
|
+
*/
|
|
52
|
+
placeholderText: string;
|
|
43
53
|
private thumbs;
|
|
44
54
|
private loadingIds;
|
|
45
55
|
/**
|
|
@@ -69,6 +79,8 @@ export declare class SnapshotNavList extends LitElement {
|
|
|
69
79
|
private edit;
|
|
70
80
|
private isEditable;
|
|
71
81
|
private renderEditButton;
|
|
82
|
+
/** The frame before a card's first capture: an icon, a caption, or both. */
|
|
83
|
+
private renderPlaceholder;
|
|
72
84
|
render(): import("lit-html").TemplateResult<1>;
|
|
73
85
|
}
|
|
74
86
|
/** Detail type of both `nav-select` and `nav-edit` — the clicked item itself. */
|
|
@@ -11,6 +11,22 @@ import { snapshotService as defaultSnapshotService } from './snapshot-service';
|
|
|
11
11
|
function isMarkupIcon(icon) {
|
|
12
12
|
return icon.trimStart().startsWith('<');
|
|
13
13
|
}
|
|
14
|
+
const warnedTextIcons = new Set();
|
|
15
|
+
/**
|
|
16
|
+
* `NavItem.icon` is markup-only, so a plain-text glyph renders as nothing —
|
|
17
|
+
* silently, without this, since the old behavior was to paint it as text.
|
|
18
|
+
* Warns once per distinct value: `items` re-renders on every thumbnail that
|
|
19
|
+
* lands, and a whole list of glyph icons would otherwise flood the console.
|
|
20
|
+
*/
|
|
21
|
+
function markupIconOrWarn(icon) {
|
|
22
|
+
if (isMarkupIcon(icon))
|
|
23
|
+
return icon;
|
|
24
|
+
if (!warnedTextIcons.has(icon)) {
|
|
25
|
+
warnedTextIcons.add(icon);
|
|
26
|
+
console.warn(`<snapshot-nav-list>: NavItem.icon takes markup (e.g. '<svg>...</svg>'), not text — ignoring ${JSON.stringify(icon)}. Use placeholderText for a caption.`);
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
14
30
|
const DEFAULT_EDIT_ICON = '✎';
|
|
15
31
|
/**
|
|
16
32
|
* A grid of preview cards: a contained (never-cropped) screenshot above real
|
|
@@ -31,6 +47,14 @@ export class SnapshotNavList extends LitElement {
|
|
|
31
47
|
this.editButtonPosition = 'overlay';
|
|
32
48
|
/** Edit button glyph. Same convention as `NavItem.icon`: a plain-text glyph (e.g. an emoji), or markup — a string starting with `<` renders as raw HTML/SVG, so a consumer can pass its own icon (e.g. `<svg>...</svg>`). */
|
|
33
49
|
this.editIcon = DEFAULT_EDIT_ICON;
|
|
50
|
+
/**
|
|
51
|
+
* Caption shown in the frame of a card with no capture yet (e.g. "no snapshot
|
|
52
|
+
* yet"), for every card at once; `NavItem.placeholderText` overrides it per
|
|
53
|
+
* row. Plain text, never markup — it's rendered as text, not HTML. Empty by
|
|
54
|
+
* default, which keeps the icon-and-hatch placeholder; set it and the frame
|
|
55
|
+
* goes see-through with a dashed edge instead.
|
|
56
|
+
*/
|
|
57
|
+
this.placeholderText = '';
|
|
34
58
|
this.thumbs = new Map();
|
|
35
59
|
this.loadingIds = new Set();
|
|
36
60
|
/**
|
|
@@ -120,28 +144,75 @@ export class SnapshotNavList extends LitElement {
|
|
|
120
144
|
}
|
|
121
145
|
/* unexposed frame: fine diagonal hatch instead of a generic gradient blob */
|
|
122
146
|
.thumb-placeholder {
|
|
147
|
+
box-sizing: border-box;
|
|
123
148
|
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
124
150
|
align-items: center;
|
|
125
151
|
justify-content: center;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
152
|
+
gap: 0.4rem;
|
|
153
|
+
padding: 0.45rem 0;
|
|
154
|
+
background-color: var(--snapshot-nav-list-placeholder-bg, color-mix(in srgb, currentColor 7%, transparent));
|
|
155
|
+
/* var-driven so a plain 'none' turns the hatch off on its own — a card
|
|
156
|
+
showing real fallback art wants the frame plain behind it. */
|
|
157
|
+
background-image: var(
|
|
158
|
+
--snapshot-nav-list-placeholder-hatch,
|
|
159
|
+
repeating-linear-gradient(
|
|
160
|
+
135deg,
|
|
161
|
+
color-mix(in srgb, currentColor 16%, transparent) 0px,
|
|
162
|
+
color-mix(in srgb, currentColor 16%, transparent) 1.5px,
|
|
163
|
+
transparent 1.5px,
|
|
164
|
+
transparent 7px
|
|
165
|
+
)
|
|
133
166
|
);
|
|
134
167
|
}
|
|
168
|
+
/* A caption carries the "nothing here yet" meaning on its own, so the hatch
|
|
169
|
+
(and the tint under it) would only fight it — the frame goes see-through,
|
|
170
|
+
marked out by a dashed edge instead. */
|
|
171
|
+
.thumb-placeholder.has-text {
|
|
172
|
+
background-color: var(--snapshot-nav-list-placeholder-bg, transparent);
|
|
173
|
+
background-image: none;
|
|
174
|
+
border: 1px dashed var(--snapshot-nav-list-placeholder-border, color-mix(in srgb, currentColor 22%, transparent));
|
|
175
|
+
border-radius: inherit;
|
|
176
|
+
}
|
|
177
|
+
.placeholder-text {
|
|
178
|
+
font-family: var(--snapshot-nav-list-placeholder-font, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
179
|
+
font-size: var(--snapshot-nav-list-placeholder-font-size, 0.75rem);
|
|
180
|
+
letter-spacing: var(--snapshot-nav-list-placeholder-letter-spacing, 0.02em);
|
|
181
|
+
color: var(--snapshot-nav-list-placeholder-color, color-mix(in srgb, currentColor 55%, transparent));
|
|
182
|
+
max-width: 100%;
|
|
183
|
+
padding: 0 0.5rem;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
text-overflow: ellipsis;
|
|
186
|
+
white-space: nowrap;
|
|
187
|
+
text-align: center;
|
|
188
|
+
}
|
|
189
|
+
/* Spans the frame (minus the caption, if any) rather than shrinking to the
|
|
190
|
+
glyph: a percentage width/height on a fallback <img> then has a real box
|
|
191
|
+
to resolve against, while a default-sized icon still sits centered. */
|
|
135
192
|
.icon-lg {
|
|
136
|
-
|
|
137
|
-
|
|
193
|
+
flex: 1 1 auto;
|
|
194
|
+
min-height: 0;
|
|
195
|
+
width: 100%;
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
199
|
+
opacity: var(--snapshot-nav-list-placeholder-icon-opacity, 0.4);
|
|
200
|
+
}
|
|
201
|
+
/* Sized off one var so a card using a real fallback image (rather than a
|
|
202
|
+
small glyph-sized icon) can grow it to fill the frame from outside the
|
|
203
|
+
shadow root. */
|
|
204
|
+
.icon-lg svg,
|
|
205
|
+
.icon-lg img {
|
|
206
|
+
width: var(--snapshot-nav-list-placeholder-icon-size, 1.6rem);
|
|
207
|
+
height: var(--snapshot-nav-list-placeholder-icon-size, 1.6rem);
|
|
208
|
+
display: block;
|
|
138
209
|
}
|
|
139
210
|
.icon-lg svg {
|
|
140
|
-
width: 1.6rem;
|
|
141
|
-
height: 1.6rem;
|
|
142
|
-
display: block;
|
|
143
211
|
fill: currentColor;
|
|
144
212
|
}
|
|
213
|
+
.icon-lg img {
|
|
214
|
+
object-fit: var(--snapshot-nav-list-placeholder-icon-fit, contain);
|
|
215
|
+
}
|
|
145
216
|
.thumb-loading {
|
|
146
217
|
display: flex;
|
|
147
218
|
align-items: center;
|
|
@@ -392,6 +463,15 @@ export class SnapshotNavList extends LitElement {
|
|
|
392
463
|
${isMarkupIcon(icon) ? unsafeHTML(icon) : icon}
|
|
393
464
|
</button>`;
|
|
394
465
|
}
|
|
466
|
+
/** The frame before a card's first capture: an icon, a caption, or both. */
|
|
467
|
+
renderPlaceholder(item) {
|
|
468
|
+
const text = item.placeholderText ?? this.placeholderText;
|
|
469
|
+
const icon = item.icon ? markupIconOrWarn(item.icon) : undefined;
|
|
470
|
+
return html `<div class="thumb thumb-placeholder ${text ? 'has-text' : ''}" part="thumb" aria-hidden="true">
|
|
471
|
+
${icon ? html `<span class="icon-lg" part="placeholder-icon">${unsafeHTML(icon)}</span>` : ''}
|
|
472
|
+
${text ? html `<span class="placeholder-text" part="placeholder-text">${text}</span>` : ''}
|
|
473
|
+
</div>`;
|
|
474
|
+
}
|
|
395
475
|
render() {
|
|
396
476
|
const editInMeta = this.editButtonPosition === 'meta';
|
|
397
477
|
return html `
|
|
@@ -411,11 +491,7 @@ export class SnapshotNavList extends LitElement {
|
|
|
411
491
|
? html `<div class="thumb thumb-loading" part="thumb" aria-hidden="true">
|
|
412
492
|
<span class="spinner" part="spinner"></span>
|
|
413
493
|
</div>`
|
|
414
|
-
:
|
|
415
|
-
<span class="icon-lg"
|
|
416
|
-
>${item.icon ? (isMarkupIcon(item.icon) ? unsafeHTML(item.icon) : item.icon) : ''}</span
|
|
417
|
-
>
|
|
418
|
-
</div>`}
|
|
494
|
+
: this.renderPlaceholder(item)}
|
|
419
495
|
${this.isEditable(item) && !editInMeta ? this.renderEditButton(item) : ''}
|
|
420
496
|
</div>
|
|
421
497
|
<div class="meta" part="meta">
|
|
@@ -452,6 +528,9 @@ __decorate([
|
|
|
452
528
|
__decorate([
|
|
453
529
|
property({ attribute: 'edit-icon' })
|
|
454
530
|
], SnapshotNavList.prototype, "editIcon", void 0);
|
|
531
|
+
__decorate([
|
|
532
|
+
property({ attribute: 'placeholder-text' })
|
|
533
|
+
], SnapshotNavList.prototype, "placeholderText", void 0);
|
|
455
534
|
__decorate([
|
|
456
535
|
state()
|
|
457
536
|
], SnapshotNavList.prototype, "thumbs", void 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anton-gustafsson/snapshot-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "A pluggable snapshot service that turns any DOM element into a stored, shareable image, plus an optional <snapshot-nav-list> web component to display them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|