@fiscozen/thumbnail 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,82 @@
1
+ # @fiscozen/thumbnail
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 976684e: `FzThumbnail` — a new package, and the first way the design system can show an
8
+ arbitrary image (LIB-2918).
9
+
10
+ `<img>` is in `forbiddenTags` at every atomic-design layer, and until now there
11
+ was nothing to compose in its place: the only three components that render one are
12
+ `FzAvatar` — round, with hardwired sizes, built for people — and
13
+ `FzRadioCard` / `FzCheckboxCard`, where the image is an illustration inside a
14
+ selectable card. So any surface that had to show a user-uploaded image had neither
15
+ a component nor a legal fallback. In the frontoffice customer chat that is a
16
+ divergence already in production: image attachments render as file cards,
17
+ indistinguishable from a document, and not even distinguishable iconographically
18
+ because the icon kit has no image, photo or camera glyph. `FzThumbnail` extracts
19
+ and generalises the card pattern (`imageUrl` + `imageAlt` + `object-cover`) rather
20
+ than inventing anything.
21
+ - **The caller imposes the dimensions**, so this does not repeat `FzAvatar`'s
22
+ mistake of owning a size — but they are **props** (`width`, `height`,
23
+ `aspectRatio`), not a class. The consuming apps forbid `class` outright at the
24
+ organism, template and page layers and `style` above an atom, so a class-only
25
+ sizing contract would make the component unusable exactly where a page needs it.
26
+ Deciding it inside the component is the only way that capability exists for
27
+ those layers — the same reasoning as `FzNavbar`'s `elevation`. A class from a
28
+ layer that permits one still works. Left unsized, the box takes its container's
29
+ width at the image's natural aspect ratio — visible, but a size nobody chose,
30
+ and the one case where a load failure moves the layout.
31
+ - **`alt` is required by the type**, with an explicit `alt=""` for decorative
32
+ images: a decision visible at the call site rather than an optional prop that
33
+ gets forgotten. A missing `alt` makes a screen reader announce the URL. The name
34
+ also survives a load failure: a native `<img>` whose URL 404s still exposes its
35
+ `alt` to assistive tech, so replacing the element with a placeholder re-applies
36
+ the name as `role="img"` + `aria-label` rather than dropping it — otherwise a
37
+ screen-reader user ends up worse off than a sighted one, who at least sees the
38
+ placeholder icon. A decorative `alt=""` and an empty `src` stay silent; neither
39
+ ever named anything.
40
+ - **An `overlay` slot** for an action — the chat's download button, the composer's
41
+ remove control. The layer is inert and hands pointer events back to its direct
42
+ children, so it does not swallow clicks meant for the thumbnail, and
43
+ `overlayPosition` pins the content to a corner without the call site writing a
44
+ class either.
45
+ - **A load error does not leave a hole in a sized box.** The placeholder —
46
+ `placeholderIcon` on a `grey-100` fill, `file` by default since the kit has no
47
+ image glyph — occupies the same box (an unsized box is only as tall as its
48
+ content, and a placeholder has no intrinsic ratio to supply that height with, so
49
+ there it collapses to the icon), and an `error` event carries the failing `src`
50
+ so a caller can fall back to something else. A new `src` clears the failure and
51
+ retries. `error`
52
+ reports a load failure and only that: an empty `src` shows the same placeholder
53
+ without firing anything, because the `<img>` never mounted, so a caller wanting
54
+ one "nothing is showing" signal checks `!src` alongside `@error`.
55
+ - **An optional scrim** (`grey-500` at 20%, overriding the design's
56
+ `rgba(74, 85, 101, 0.2)` onto the DS palette), drawn over the image only, so an
57
+ overlaid control stays legible on a light photo. Override the colour with
58
+ `--fz-thumbnail-scrim` and the 20% with `--fz-thumbnail-scrim-opacity`.
59
+ - **`imgProps` reaches the `<img>` itself** — `referrerpolicy`, `crossorigin`,
60
+ `decoding`, `fetchpriority`, `srcset`, `sizes`. The component has a single root
61
+ element, so a fallthrough attribute lands on the wrapping box, where
62
+ `referrerpolicy` does nothing; without this prop the image is simply out of
63
+ reach. Keeping `class` and listeners on the box is what a caller sizing or
64
+ clicking a thumbnail wants, so the two go to different places on purpose.
65
+ `src`, `alt`, `loading` and `onError` remain the component's own contract and are
66
+ `Omit`ted from the prop's type, so naming one is a compile error rather than a
67
+ silent no-op — `onError` in particular could not simply be documented as losing,
68
+ since Vue's `mergeProps` chains listeners instead of replacing them.
69
+ Use `:imgProps="{ referrerpolicy: 'no-referrer' }"` for a third-party host.
70
+ - `radius` defaults to `base` — 4px, the designs' value — and `loading` to `lazy`.
71
+
72
+ The scrim is declared in this package's stylesheet rather than as
73
+ `bg-grey-500/20`, and that is not a style preference: the design system's colours
74
+ resolve to `var(--grey-500, …)`, Tailwind cannot decompose a `var()` into
75
+ channels, and an opacity modifier on a token colour therefore generates **no rule
76
+ at all**. Verified against the DS preset with the Tailwind CLI. The 20% is an
77
+ `opacity` declaration rather than a baked `rgba()` for the same kind of reason: an
78
+ `rgba()` would freeze `--grey-500`'s fallback, leaving a retheming consumer with
79
+ the scrim as the one grey that did not move.
80
+
81
+ Unblocks LIB-2912 (`FzpChatAttachmentCard`), whose README documents the file-card
82
+ fallback as temporary; nothing else about that component has to change.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Fiscozen
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,122 @@
1
+ # @fiscozen/thumbnail
2
+
3
+ `FzThumbnail` — an image from a URL, cropped into a box the caller sizes.
4
+
5
+ The design system had no way to show an arbitrary image. `FzAvatar` is round and
6
+ owns its sizes; `FzRadioCard` and `FzCheckboxCard` render an illustration inside a
7
+ selectable card. This generalises that second pattern into a component of its own.
8
+
9
+ ```vue
10
+ <FzThumbnail src="/receipt.jpg" alt="Scontrino di marzo" width="158px" height="108px" />
11
+ ```
12
+
13
+ ## The caller owns the box
14
+
15
+ `FzThumbnail` hardwires no dimension — that is the point, and it is what keeps it
16
+ from repeating `FzAvatar`'s mistake. Give it:
17
+
18
+ - `width` **and** `height`, or
19
+ - one of them plus `aspectRatio`.
20
+
21
+ With no dimension at all the box takes its container's width and the image's
22
+ *natural* aspect ratio. That is visible, not broken — but it is a size neither
23
+ you nor the design chose, and it is the one case where a load failure moves the
24
+ layout (see below). Give it a dimension.
25
+
26
+ **They are props, not classes, on purpose.** The consuming apps forbid `class`
27
+ outright at the organism, template and page layers, and `style` anywhere above an
28
+ atom, so a class-only sizing contract would make the component unusable exactly
29
+ where a page needs it. Deciding it inside the component is the only way that
30
+ capability exists for those layers — the same reasoning as `FzNavbar`'s
31
+ `elevation`. A Tailwind class still works where the layer permits one; pick one
32
+ mechanism or the other rather than both.
33
+
34
+ ## Overlaying an action
35
+
36
+ The `overlay` slot sits above the image in a layer that is itself inert, with
37
+ pointer events handed back to its direct children — so the layer does not swallow
38
+ clicks meant for the thumbnail. `overlayPosition` pins the content 8px in from a
39
+ corner, again as a prop rather than a class, so a page can place an action too.
40
+
41
+ ```vue
42
+ <FzThumbnail :src="attachment.url" alt="" width="100%" height="168px" scrim bordered>
43
+ <template #overlay>
44
+ <FzIconButton
45
+ iconName="arrow-down-to-line"
46
+ ariaLabel="Scarica"
47
+ @click="download(attachment)"
48
+ />
49
+ </template>
50
+ </FzThumbnail>
51
+ ```
52
+
53
+ Content that needs finer placement can still position itself, from a layer that
54
+ permits a class.
55
+
56
+ `scrim` lays `grey-500` at 20% over the image, so an overlaid control stays
57
+ legible on a light photo. Override the colour with `--fz-thumbnail-scrim` and the
58
+ 20% with `--fz-thumbnail-scrim-opacity` — the colour goes through `var(--grey-500)`
59
+ rather than a baked `rgba()`, so retheming the token moves the scrim with every
60
+ other grey.
61
+
62
+ ## A broken URL does not leave a hole in a sized box
63
+
64
+ On a load error the image is replaced by a placeholder — `placeholderIcon` on a
65
+ `grey-100` fill — that occupies the same box, and an `error` event fires with the
66
+ failing `src` so the caller can fall back to something else entirely. Changing
67
+ `src` clears the failure and retries.
68
+
69
+ **That holds as long as the box has a size of its own.** An unsized box is only
70
+ as tall as its content, and the placeholder — unlike an image — has no natural
71
+ ratio to supply one, so it collapses to the icon:
72
+
73
+ | unsized box, 600px container, 400×300 image | |
74
+ |---|---|
75
+ | image loads | 600×450 |
76
+ | image fails | 600×20 |
77
+
78
+ Which is the second reason to pass a dimension. Give the box a `height` or an
79
+ `aspectRatio` and the placeholder fills exactly the space the image did.
80
+
81
+ `error` reports a *load failure* and nothing else. An empty `src` shows the same
82
+ placeholder but fires no event — the image never mounted, so there was nothing to
83
+ fail. If you want one signal for "no image is showing", check `!src` alongside
84
+ `@error`.
85
+
86
+ Note the icon kit has no image, photo or camera glyph, so the default is `file`.
87
+
88
+ ## `alt` is required
89
+
90
+ Not an optional prop that gets forgotten. Pass an explicit `alt=""` for a
91
+ decorative image, which makes that a visible decision at the call site.
92
+
93
+ The name survives a load failure. A native `<img>` whose URL 404s still exposes
94
+ its `alt` to a screen reader — the element is there, only the pixels are missing.
95
+ This component replaces the `<img>` with a placeholder div, so it re-applies the
96
+ name as `role="img"` + `aria-label` rather than letting it vanish. A decorative
97
+ `alt=""` stays silent, and so does an empty `src`: neither named anything.
98
+
99
+ ## Props
100
+
101
+ | Prop | Type | Default | |
102
+ |---|---|---|---|
103
+ | `src` | `string` | — | Image URL. |
104
+ | `alt` | `string` | — | Accessible name. Required; `""` for decorative. |
105
+ | `width` | `string` | — | Any CSS length. |
106
+ | `height` | `string` | — | Any CSS length. |
107
+ | `aspectRatio` | `string` | — | e.g. `'16 / 9'`. Ignored when both dimensions are set. |
108
+ | `radius` | `'none' \| 'sm' \| 'base' \| 'lg' \| 'xl'` | `'base'` | `base` is 4px, the design's value. |
109
+ | `bordered` | `boolean` | `false` | 1px `grey-100` border. |
110
+ | `scrim` | `boolean` | `false` | Translucent overlay over the image only. |
111
+ | `overlayPosition` | `'top-start' \| 'top-end' \| 'bottom-start' \| 'bottom-end' \| 'center'` | `'bottom-end'` | Where the `overlay` slot's content sits, 8px in. |
112
+ | `placeholderIcon` | `string` | `'file'` | Icon shown on load error. |
113
+ | `loading` | `'lazy' \| 'eager'` | `'lazy'` | Native loading hint. |
114
+ | `imgProps` | `Omit<ImgHTMLAttributes, 'src' \| 'alt' \| 'loading' \| 'onError'>` | — | Extra attributes for the `<img>` (`referrerpolicy`, `crossorigin`, `decoding`, `srcset`…). A fallthrough attribute lands on the root box instead, so this is the way to reach the image. The four keys the component owns are excluded from the type, so naming one is a compile error rather than a silent no-op. |
115
+
116
+ | Event | Payload | |
117
+ |---|---|---|
118
+ | `error` | `string` | The `src` that failed to load. |
119
+
120
+ | Slot | |
121
+ |---|---|
122
+ | `overlay` | Rendered above the image and the scrim, in an inert layer. |
@@ -0,0 +1,224 @@
1
+ body, html {
2
+ margin:0; padding: 0;
3
+ height: 100%;
4
+ }
5
+ body {
6
+ font-family: Helvetica Neue, Helvetica, Arial;
7
+ font-size: 14px;
8
+ color:#333;
9
+ }
10
+ .small { font-size: 12px; }
11
+ *, *:after, *:before {
12
+ -webkit-box-sizing:border-box;
13
+ -moz-box-sizing:border-box;
14
+ box-sizing:border-box;
15
+ }
16
+ h1 { font-size: 20px; margin: 0;}
17
+ h2 { font-size: 14px; }
18
+ pre {
19
+ font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20
+ margin: 0;
21
+ padding: 0;
22
+ -moz-tab-size: 2;
23
+ -o-tab-size: 2;
24
+ tab-size: 2;
25
+ }
26
+ a { color:#0074D9; text-decoration:none; }
27
+ a:hover { text-decoration:underline; }
28
+ .strong { font-weight: bold; }
29
+ .space-top1 { padding: 10px 0 0 0; }
30
+ .pad2y { padding: 20px 0; }
31
+ .pad1y { padding: 10px 0; }
32
+ .pad2x { padding: 0 20px; }
33
+ .pad2 { padding: 20px; }
34
+ .pad1 { padding: 10px; }
35
+ .space-left2 { padding-left:55px; }
36
+ .space-right2 { padding-right:20px; }
37
+ .center { text-align:center; }
38
+ .clearfix { display:block; }
39
+ .clearfix:after {
40
+ content:'';
41
+ display:block;
42
+ height:0;
43
+ clear:both;
44
+ visibility:hidden;
45
+ }
46
+ .fl { float: left; }
47
+ @media only screen and (max-width:640px) {
48
+ .col3 { width:100%; max-width:100%; }
49
+ .hide-mobile { display:none!important; }
50
+ }
51
+
52
+ .quiet {
53
+ color: #7f7f7f;
54
+ color: rgba(0,0,0,0.5);
55
+ }
56
+ .quiet a { opacity: 0.7; }
57
+
58
+ .fraction {
59
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60
+ font-size: 10px;
61
+ color: #555;
62
+ background: #E8E8E8;
63
+ padding: 4px 5px;
64
+ border-radius: 3px;
65
+ vertical-align: middle;
66
+ }
67
+
68
+ div.path a:link, div.path a:visited { color: #333; }
69
+ table.coverage {
70
+ border-collapse: collapse;
71
+ margin: 10px 0 0 0;
72
+ padding: 0;
73
+ }
74
+
75
+ table.coverage td {
76
+ margin: 0;
77
+ padding: 0;
78
+ vertical-align: top;
79
+ }
80
+ table.coverage td.line-count {
81
+ text-align: right;
82
+ padding: 0 5px 0 20px;
83
+ }
84
+ table.coverage td.line-coverage {
85
+ text-align: right;
86
+ padding-right: 10px;
87
+ min-width:20px;
88
+ }
89
+
90
+ table.coverage td span.cline-any {
91
+ display: inline-block;
92
+ padding: 0 5px;
93
+ width: 100%;
94
+ }
95
+ .missing-if-branch {
96
+ display: inline-block;
97
+ margin-right: 5px;
98
+ border-radius: 3px;
99
+ position: relative;
100
+ padding: 0 4px;
101
+ background: #333;
102
+ color: yellow;
103
+ }
104
+
105
+ .skip-if-branch {
106
+ display: none;
107
+ margin-right: 10px;
108
+ position: relative;
109
+ padding: 0 4px;
110
+ background: #ccc;
111
+ color: white;
112
+ }
113
+ .missing-if-branch .typ, .skip-if-branch .typ {
114
+ color: inherit !important;
115
+ }
116
+ .coverage-summary {
117
+ border-collapse: collapse;
118
+ width: 100%;
119
+ }
120
+ .coverage-summary tr { border-bottom: 1px solid #bbb; }
121
+ .keyline-all { border: 1px solid #ddd; }
122
+ .coverage-summary td, .coverage-summary th { padding: 10px; }
123
+ .coverage-summary tbody { border: 1px solid #bbb; }
124
+ .coverage-summary td { border-right: 1px solid #bbb; }
125
+ .coverage-summary td:last-child { border-right: none; }
126
+ .coverage-summary th {
127
+ text-align: left;
128
+ font-weight: normal;
129
+ white-space: nowrap;
130
+ }
131
+ .coverage-summary th.file { border-right: none !important; }
132
+ .coverage-summary th.pct { }
133
+ .coverage-summary th.pic,
134
+ .coverage-summary th.abs,
135
+ .coverage-summary td.pct,
136
+ .coverage-summary td.abs { text-align: right; }
137
+ .coverage-summary td.file { white-space: nowrap; }
138
+ .coverage-summary td.pic { min-width: 120px !important; }
139
+ .coverage-summary tfoot td { }
140
+
141
+ .coverage-summary .sorter {
142
+ height: 10px;
143
+ width: 7px;
144
+ display: inline-block;
145
+ margin-left: 0.5em;
146
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147
+ }
148
+ .coverage-summary .sorted .sorter {
149
+ background-position: 0 -20px;
150
+ }
151
+ .coverage-summary .sorted-desc .sorter {
152
+ background-position: 0 -10px;
153
+ }
154
+ .status-line { height: 10px; }
155
+ /* yellow */
156
+ .cbranch-no { background: yellow !important; color: #111; }
157
+ /* dark red */
158
+ .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
159
+ .low .chart { border:1px solid #C21F39 }
160
+ .highlighted,
161
+ .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
162
+ background: #C21F39 !important;
163
+ }
164
+ /* medium red */
165
+ .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
166
+ /* light red */
167
+ .low, .cline-no { background:#FCE1E5 }
168
+ /* light green */
169
+ .high, .cline-yes { background:rgb(230,245,208) }
170
+ /* medium green */
171
+ .cstat-yes { background:rgb(161,215,106) }
172
+ /* dark green */
173
+ .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
174
+ .high .chart { border:1px solid rgb(77,146,33) }
175
+ /* dark yellow (gold) */
176
+ .status-line.medium, .medium .cover-fill { background: #f9cd0b; }
177
+ .medium .chart { border:1px solid #f9cd0b; }
178
+ /* light yellow */
179
+ .medium { background: #fff4c2; }
180
+
181
+ .cstat-skip { background: #ddd; color: #111; }
182
+ .fstat-skip { background: #ddd; color: #111 !important; }
183
+ .cbranch-skip { background: #ddd !important; color: #111; }
184
+
185
+ span.cline-neutral { background: #eaeaea; }
186
+
187
+ .coverage-summary td.empty {
188
+ opacity: .5;
189
+ padding-top: 4px;
190
+ padding-bottom: 4px;
191
+ line-height: 1;
192
+ color: #888;
193
+ }
194
+
195
+ .cover-fill, .cover-empty {
196
+ display:inline-block;
197
+ height: 12px;
198
+ }
199
+ .chart {
200
+ line-height: 0;
201
+ }
202
+ .cover-empty {
203
+ background: white;
204
+ }
205
+ .cover-full {
206
+ border-right: none !important;
207
+ }
208
+ pre.prettyprint {
209
+ border: none !important;
210
+ padding: 0 !important;
211
+ margin: 0 !important;
212
+ }
213
+ .com { color: #999 !important; }
214
+ .ignore-none { color: #999; font-weight: normal; }
215
+
216
+ .wrapper {
217
+ min-height: 100%;
218
+ height: auto !important;
219
+ height: 100%;
220
+ margin: 0 auto -48px;
221
+ }
222
+ .footer, .push {
223
+ height: 48px;
224
+ }
@@ -0,0 +1,87 @@
1
+ /* eslint-disable */
2
+ var jumpToCode = (function init() {
3
+ // Classes of code we would like to highlight in the file view
4
+ var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
5
+
6
+ // Elements to highlight in the file listing view
7
+ var fileListingElements = ['td.pct.low'];
8
+
9
+ // We don't want to select elements that are direct descendants of another match
10
+ var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
11
+
12
+ // Selector that finds elements on the page to which we can jump
13
+ var selector =
14
+ fileListingElements.join(', ') +
15
+ ', ' +
16
+ notSelector +
17
+ missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
18
+
19
+ // The NodeList of matching elements
20
+ var missingCoverageElements = document.querySelectorAll(selector);
21
+
22
+ var currentIndex;
23
+
24
+ function toggleClass(index) {
25
+ missingCoverageElements
26
+ .item(currentIndex)
27
+ .classList.remove('highlighted');
28
+ missingCoverageElements.item(index).classList.add('highlighted');
29
+ }
30
+
31
+ function makeCurrent(index) {
32
+ toggleClass(index);
33
+ currentIndex = index;
34
+ missingCoverageElements.item(index).scrollIntoView({
35
+ behavior: 'smooth',
36
+ block: 'center',
37
+ inline: 'center'
38
+ });
39
+ }
40
+
41
+ function goToPrevious() {
42
+ var nextIndex = 0;
43
+ if (typeof currentIndex !== 'number' || currentIndex === 0) {
44
+ nextIndex = missingCoverageElements.length - 1;
45
+ } else if (missingCoverageElements.length > 1) {
46
+ nextIndex = currentIndex - 1;
47
+ }
48
+
49
+ makeCurrent(nextIndex);
50
+ }
51
+
52
+ function goToNext() {
53
+ var nextIndex = 0;
54
+
55
+ if (
56
+ typeof currentIndex === 'number' &&
57
+ currentIndex < missingCoverageElements.length - 1
58
+ ) {
59
+ nextIndex = currentIndex + 1;
60
+ }
61
+
62
+ makeCurrent(nextIndex);
63
+ }
64
+
65
+ return function jump(event) {
66
+ if (
67
+ document.getElementById('fileSearch') === document.activeElement &&
68
+ document.activeElement != null
69
+ ) {
70
+ // if we're currently focused on the search input, we don't want to navigate
71
+ return;
72
+ }
73
+
74
+ switch (event.which) {
75
+ case 78: // n
76
+ case 74: // j
77
+ goToNext();
78
+ break;
79
+ case 66: // b
80
+ case 75: // k
81
+ case 80: // p
82
+ goToPrevious();
83
+ break;
84
+ }
85
+ };
86
+ })();
87
+ window.addEventListener('keydown', jumpToCode);
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <coverage generated="1788859848137" clover="3.2.0">
3
+ <project timestamp="1788859848137" name="All files">
4
+ <metrics statements="15" coveredstatements="15" conditionals="21" coveredconditionals="21" methods="6" coveredmethods="6" elements="42" coveredelements="42" complexity="0" loc="15" ncloc="15" packages="2" files="4" classes="4"/>
5
+ <package name="dist.src">
6
+ <metrics statements="0" coveredstatements="0" conditionals="0" coveredconditionals="0" methods="0" coveredmethods="0"/>
7
+ <file name="FzThumbnail.vue.d.ts" path="/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/FzThumbnail.vue.d.ts">
8
+ <metrics statements="0" coveredstatements="0" conditionals="0" coveredconditionals="0" methods="0" coveredmethods="0"/>
9
+ </file>
10
+ <file name="types.d.ts" path="/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/types.d.ts">
11
+ <metrics statements="0" coveredstatements="0" conditionals="0" coveredconditionals="0" methods="0" coveredmethods="0"/>
12
+ </file>
13
+ </package>
14
+ <package name="src">
15
+ <metrics statements="15" coveredstatements="15" conditionals="21" coveredconditionals="21" methods="6" coveredmethods="6"/>
16
+ <file name="FzThumbnail.vue" path="/Users/fiscozen/Projects/design_system/packages/thumbnail/src/FzThumbnail.vue">
17
+ <metrics statements="15" coveredstatements="15" conditionals="21" coveredconditionals="21" methods="6" coveredmethods="6"/>
18
+ <line num="35" count="54" type="stmt"/>
19
+ <line num="44" count="54" type="stmt"/>
20
+ <line num="52" count="54" type="stmt"/>
21
+ <line num="56" count="54" type="stmt"/>
22
+ <line num="57" count="56" type="stmt"/>
23
+ <line num="59" count="2" type="stmt"/>
24
+ <line num="63" count="65" type="cond" truecount="2" falsecount="0"/>
25
+ <line num="72" count="54" type="cond" truecount="4" falsecount="0"/>
26
+ <line num="74" count="54" type="stmt"/>
27
+ <line num="82" count="54" type="stmt"/>
28
+ <line num="92" count="54" type="stmt"/>
29
+ <line num="98" count="54" type="stmt"/>
30
+ <line num="99" count="9" type="stmt"/>
31
+ <line num="100" count="9" type="stmt"/>
32
+ <line num="105" count="65" type="stmt"/>
33
+ </file>
34
+ <file name="types.ts" path="/Users/fiscozen/Projects/design_system/packages/thumbnail/src/types.ts">
35
+ <metrics statements="0" coveredstatements="0" conditionals="0" coveredconditionals="0" methods="0" coveredmethods="0"/>
36
+ </file>
37
+ </package>
38
+ </project>
39
+ </coverage>
@@ -0,0 +1,5 @@
1
+ {"/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/FzThumbnail.vue.d.ts": {"path":"/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/FzThumbnail.vue.d.ts","statementMap":{},"fnMap":{},"branchMap":{},"s":{},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{}}}
2
+ ,"/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/types.d.ts": {"path":"/Users/fiscozen/Projects/design_system/packages/thumbnail/dist/src/types.d.ts","statementMap":{},"fnMap":{},"branchMap":{},"s":{},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{}}}
3
+ ,"/Users/fiscozen/Projects/design_system/packages/thumbnail/src/FzThumbnail.vue": {"path":"/Users/fiscozen/Projects/design_system/packages/thumbnail/src/FzThumbnail.vue","statementMap":{"0":{"start":{"line":35,"column":14},"end":{"line":35,"column":null}},"1":{"start":{"line":44,"column":13},"end":{"line":44,"column":null}},"2":{"start":{"line":52,"column":6},"end":{"line":52,"column":24}},"3":{"start":{"line":56,"column":0},"end":{"line":61,"column":null}},"4":{"start":{"line":57,"column":8},"end":{"line":57,"column":null}},"5":{"start":{"line":59,"column":4},"end":{"line":59,"column":null}},"6":{"start":{"line":63,"column":6},"end":{"line":63,"column":61}},"7":{"start":{"line":63,"column":33},"end":{"line":63,"column":61}},"8":{"start":{"line":72,"column":6},"end":{"line":72,"column":91}},"9":{"start":{"line":72,"column":41},"end":{"line":72,"column":91}},"10":{"start":{"line":74,"column":57},"end":{"line":80,"column":null}},"11":{"start":{"line":82,"column":75},"end":{"line":88,"column":null}},"12":{"start":{"line":92,"column":6},"end":{"line":96,"column":2}},"13":{"start":{"line":92,"column":33},"end":{"line":96,"column":2}},"14":{"start":{"line":98,"column":6},"end":{"line":100,"column":null}},"15":{"start":{"line":99,"column":2},"end":{"line":99,"column":null}},"16":{"start":{"line":100,"column":2},"end":{"line":100,"column":null}},"17":{"start":{"line":105,"column":2},"end":{"line":154,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":56,"column":0},"end":{"line":56,"column":null}},"loc":{"start":{"line":57,"column":8},"end":{"line":57,"column":null}},"line":57},"1":{"name":"(anonymous_1)","decl":{"start":{"line":57,"column":14},"end":{"line":57,"column":null}},"loc":{"start":{"line":58,"column":8},"end":{"line":61,"column":null}},"line":58},"2":{"name":"(anonymous_2)","decl":{"start":{"line":63,"column":18},"end":{"line":63,"column":33}},"loc":{"start":{"line":63,"column":33},"end":{"line":63,"column":61}},"line":63},"3":{"name":"(anonymous_3)","decl":{"start":{"line":72,"column":25},"end":{"line":72,"column":41}},"loc":{"start":{"line":72,"column":41},"end":{"line":72,"column":91}},"line":72},"4":{"name":"(anonymous_4)","decl":{"start":{"line":92,"column":17},"end":{"line":92,"column":33}},"loc":{"start":{"line":92,"column":33},"end":{"line":96,"column":2}},"line":92},"5":{"name":"(anonymous_5)","decl":{"start":{"line":98,"column":6},"end":{"line":98,"column":22}},"loc":{"start":{"line":98,"column":22},"end":{"line":100,"column":null}},"line":98}},"branchMap":{"0":{"loc":{"start":{"line":63,"column":33},"end":{"line":63,"column":61}},"type":"binary-expr","locations":[{"start":{"line":63,"column":33},"end":{"line":63,"column":48}},{"start":{"line":63,"column":48},"end":{"line":63,"column":61}}],"line":63},"1":{"loc":{"start":{"line":72,"column":41},"end":{"line":72,"column":91}},"type":"cond-expr","locations":[{"start":{"line":72,"column":69},"end":{"line":72,"column":81}},{"start":{"line":72,"column":81},"end":{"line":72,"column":91}}],"line":72},"2":{"loc":{"start":{"line":72,"column":41},"end":{"line":72,"column":69}},"type":"binary-expr","locations":[{"start":{"line":72,"column":41},"end":{"line":72,"column":57}},{"start":{"line":72,"column":57},"end":{"line":72,"column":69}}],"line":72},"3":{"loc":{"start":{"line":93,"column":6},"end":{"line":93,"column":47}},"type":"cond-expr","locations":[{"start":{"line":93,"column":20},"end":{"line":93,"column":42}},{"start":{"line":93,"column":45},"end":{"line":93,"column":47}}],"line":93},"4":{"loc":{"start":{"line":94,"column":6},"end":{"line":94,"column":50}},"type":"cond-expr","locations":[{"start":{"line":94,"column":21},"end":{"line":94,"column":45}},{"start":{"line":94,"column":48},"end":{"line":94,"column":50}}],"line":94},"5":{"loc":{"start":{"line":95,"column":6},"end":{"line":95,"column":null}},"type":"cond-expr","locations":[{"start":{"line":95,"column":26},"end":{"line":95,"column":60}},{"start":{"line":95,"column":63},"end":{"line":95,"column":null}}],"line":95},"6":{"loc":{"start":{"line":111,"column":12},"end":{"line":134,"column":72}},"type":"cond-expr","locations":[{"start":{"line":111,"column":12},"end":{"line":127,"column":null}},{"start":{"line":127,"column":4},"end":{"line":134,"column":72}}],"line":111},"7":{"loc":{"start":{"line":130,"column":13},"end":{"line":130,"column":null}},"type":"cond-expr","locations":[{"start":{"line":130,"column":29},"end":{"line":130,"column":40}},{"start":{"line":130,"column":40},"end":{"line":130,"column":null}}],"line":130},"8":{"loc":{"start":{"line":138,"column":12},"end":{"line":141,"column":null}},"type":"cond-expr","locations":[{"start":{"line":138,"column":21},"end":{"line":137,"column":null}},{"start":{"line":141,"column":6},"end":{"line":141,"column":null}}],"line":138},"9":{"loc":{"start":{"line":138,"column":12},"end":{"line":138,"column":null}},"type":"binary-expr","locations":[{"start":{"line":138,"column":12},"end":{"line":138,"column":21}},{"start":{"line":138,"column":21},"end":{"line":138,"column":null}}],"line":138},"10":{"loc":{"start":{"line":149,"column":12},"end":{"line":154,"column":null}},"type":"cond-expr","locations":[{"start":{"line":149,"column":19},"end":{"line":154,"column":null}}],"line":149}},"s":{"0":54,"1":54,"2":54,"3":54,"4":56,"5":2,"6":54,"7":65,"8":54,"9":15,"10":54,"11":54,"12":54,"13":54,"14":54,"15":9,"16":9,"17":65},"f":{"0":56,"1":2,"2":65,"3":15,"4":54,"5":9},"b":{"0":[65,59],"1":[8,7],"2":[15,9],"3":[3,51],"4":[3,51],"5":[1,53],"6":[50,15],"7":[8,7],"8":[3,62],"9":[65,4],"10":[10]},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{}}}
4
+ ,"/Users/fiscozen/Projects/design_system/packages/thumbnail/src/types.ts": {"path":"/Users/fiscozen/Projects/design_system/packages/thumbnail/src/types.ts","statementMap":{},"fnMap":{},"branchMap":{},"s":{},"f":{},"b":{},"meta":{"lastBranch":0,"lastFunction":0,"lastStatement":0,"seen":{}}}
5
+ }