drab 2.0.0 → 2.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/dist/components/Chord.svelte +2 -0
- package/dist/components/Chord.svelte.d.ts +9 -8
- package/dist/components/ContextMenu.svelte +30 -14
- package/dist/components/ContextMenu.svelte.d.ts +2 -0
- package/dist/components/CopyButton.svelte +9 -2
- package/dist/components/CopyButton.svelte.d.ts +2 -0
- package/dist/components/DataTable.svelte +15 -3
- package/dist/components/DataTable.svelte.d.ts +2 -0
- package/dist/components/Editor.svelte +15 -2
- package/dist/components/Editor.svelte.d.ts +3 -1
- package/dist/components/FullscreenButton.svelte +18 -7
- package/dist/components/FullscreenButton.svelte.d.ts +4 -2
- package/dist/components/Popover.svelte +155 -0
- package/dist/components/Popover.svelte.d.ts +69 -0
- package/dist/components/ShareButton.svelte +10 -3
- package/dist/components/ShareButton.svelte.d.ts +4 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/util/messages.d.ts +1 -0
- package/dist/util/messages.js +1 -0
- package/package.json +6 -4
@@ -1,4 +1,12 @@
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
2
|
+
export interface ChordNote {
|
3
|
+
/** recommended finger to use */
|
4
|
+
finger: number | string;
|
5
|
+
/** string number */
|
6
|
+
string: number;
|
7
|
+
/** fret number */
|
8
|
+
fret: number;
|
9
|
+
}
|
2
10
|
declare const __propDef: {
|
3
11
|
props: {
|
4
12
|
class?: string | undefined;
|
@@ -6,14 +14,7 @@ declare const __propDef: {
|
|
6
14
|
/** total number of strings for the instrument */ strings?: number | undefined;
|
7
15
|
/** name of chord */ name?: string | undefined;
|
8
16
|
/** total size of chord square */ size?: number | undefined;
|
9
|
-
/** list of the positioning of the notes required for the chord */ notes?:
|
10
|
-
/** recommended finger to use */
|
11
|
-
finger: number | string;
|
12
|
-
/** string number */
|
13
|
-
string: number;
|
14
|
-
/** fret number */
|
15
|
-
fret: number;
|
16
|
-
}[] | undefined;
|
17
|
+
/** list of the positioning of the notes required for the chord */ notes?: ChordNote[] | undefined;
|
17
18
|
};
|
18
19
|
events: {
|
19
20
|
[evt: string]: CustomEvent<any>;
|
@@ -7,6 +7,7 @@ Displays when the parent element is right clicked.
|
|
7
7
|
|
8
8
|
@props
|
9
9
|
|
10
|
+
- `classNoscript` - noscript class
|
10
11
|
- `class`
|
11
12
|
- `display` - controls `display` css property
|
12
13
|
- `id`
|
@@ -43,29 +44,36 @@ let className = "";
|
|
43
44
|
export { className as class };
|
44
45
|
export let id = "";
|
45
46
|
export let display = false;
|
47
|
+
export let classNoscript = "";
|
46
48
|
let contextMenu;
|
47
|
-
let
|
49
|
+
let coordinates = { x: 0, y: 0 };
|
48
50
|
const hide = () => display = false;
|
51
|
+
const onKeyDown = (e) => {
|
52
|
+
if (e.key === "Escape") {
|
53
|
+
display = false;
|
54
|
+
}
|
55
|
+
};
|
49
56
|
onMount(() => {
|
50
|
-
const
|
51
|
-
if (
|
52
|
-
|
57
|
+
const parentElement = contextMenu.parentElement;
|
58
|
+
if (parentElement) {
|
59
|
+
parentElement.addEventListener("contextmenu", async (e) => {
|
53
60
|
if (contextMenu) {
|
54
61
|
e.preventDefault();
|
55
62
|
const scrollY = window.scrollY;
|
56
|
-
|
57
|
-
|
63
|
+
const scrollX = window.scrollX;
|
64
|
+
coordinates.x = e.clientX + scrollX;
|
65
|
+
coordinates.y = e.clientY + scrollY;
|
58
66
|
display = true;
|
59
67
|
await tick();
|
60
68
|
const offsetWidth = contextMenu.offsetWidth + 24;
|
61
69
|
const offsetHeight = contextMenu.offsetHeight + 6;
|
62
70
|
const innerWidth = window.innerWidth;
|
63
71
|
const innerHeight = window.innerHeight;
|
64
|
-
if (
|
65
|
-
|
72
|
+
if (coordinates.x + offsetWidth > scrollX + innerWidth) {
|
73
|
+
coordinates.x = scrollX + innerWidth - offsetWidth;
|
66
74
|
}
|
67
|
-
if (
|
68
|
-
|
75
|
+
if (coordinates.y + offsetHeight > scrollY + innerHeight) {
|
76
|
+
coordinates.y = scrollY + innerHeight - offsetHeight;
|
69
77
|
}
|
70
78
|
}
|
71
79
|
});
|
@@ -73,21 +81,29 @@ onMount(() => {
|
|
73
81
|
});
|
74
82
|
</script>
|
75
83
|
|
76
|
-
<svelte:document on:click={hide} />
|
84
|
+
<svelte:document on:click={hide} on:keydown={onKeyDown} />
|
77
85
|
|
78
86
|
<div
|
79
87
|
class={className}
|
80
88
|
{id}
|
81
89
|
bind:this={contextMenu}
|
82
|
-
style="
|
83
|
-
|
84
|
-
|
90
|
+
style:z-index={display ? "10" : "-10"}
|
91
|
+
style:opacity={display ? "100%" : "0%"}
|
92
|
+
style:top="{coordinates.y}px"
|
93
|
+
style:left="{coordinates.x}px"
|
85
94
|
>
|
86
95
|
<slot>Context Menu</slot>
|
87
96
|
</div>
|
88
97
|
|
98
|
+
<noscript>
|
99
|
+
<div class={classNoscript}>
|
100
|
+
<slot />
|
101
|
+
</div>
|
102
|
+
</noscript>
|
103
|
+
|
89
104
|
<style>
|
90
105
|
div {
|
91
106
|
position: absolute;
|
107
|
+
z-index: 1;
|
92
108
|
}
|
93
109
|
</style>
|
@@ -4,6 +4,7 @@ declare const __propDef: {
|
|
4
4
|
class?: string | undefined;
|
5
5
|
id?: string | undefined;
|
6
6
|
/** controls `display` css property */ display?: boolean | undefined;
|
7
|
+
/** noscript class */ classNoscript?: string | undefined;
|
7
8
|
};
|
8
9
|
events: {
|
9
10
|
[evt: string]: CustomEvent<any>;
|
@@ -22,6 +23,7 @@ export type ContextMenuSlots = typeof __propDef.slots;
|
|
22
23
|
*
|
23
24
|
* @props
|
24
25
|
*
|
26
|
+
* - `classNoscript` - noscript class
|
25
27
|
* - `class`
|
26
28
|
* - `display` - controls `display` css property
|
27
29
|
* - `id`
|
@@ -7,6 +7,7 @@ Uses the navigator api to copy text to the clipboard.
|
|
7
7
|
|
8
8
|
@props
|
9
9
|
|
10
|
+
- `classNoscript` - noscript class
|
10
11
|
- `class`
|
11
12
|
- `id`
|
12
13
|
- `text` - text to copy
|
@@ -30,11 +31,14 @@ Uses the navigator api to copy text to the clipboard.
|
|
30
31
|
```
|
31
32
|
-->
|
32
33
|
|
33
|
-
<script>
|
34
|
+
<script>import { onMount } from "svelte";
|
35
|
+
let className = "";
|
34
36
|
export { className as class };
|
35
37
|
export let id = "";
|
36
38
|
export let title = "Copy";
|
37
39
|
export let text;
|
40
|
+
export let classNoscript = "";
|
41
|
+
let clientJs = false;
|
38
42
|
let complete = false;
|
39
43
|
const copyText = async () => {
|
40
44
|
try {
|
@@ -45,12 +49,15 @@ const copyText = async () => {
|
|
45
49
|
console.error(error);
|
46
50
|
}
|
47
51
|
};
|
52
|
+
onMount(() => clientJs = true);
|
48
53
|
</script>
|
49
54
|
|
50
|
-
<button on:click={copyText} class={className} {id} {title}>
|
55
|
+
<button disabled={!clientJs} on:click={copyText} class={className} {id} {title}>
|
51
56
|
{#if complete}
|
52
57
|
<slot name="complete">Copied</slot>
|
53
58
|
{:else}
|
54
59
|
<slot>Copy</slot>
|
55
60
|
{/if}
|
56
61
|
</button>
|
62
|
+
|
63
|
+
<noscript><span class={classNoscript}>{text}</span></noscript>
|
@@ -5,6 +5,7 @@ declare const __propDef: {
|
|
5
5
|
id?: string | undefined;
|
6
6
|
title?: string | undefined;
|
7
7
|
/** text to copy */ text: string;
|
8
|
+
/** noscript class */ classNoscript?: string | undefined;
|
8
9
|
};
|
9
10
|
events: {
|
10
11
|
[evt: string]: CustomEvent<any>;
|
@@ -24,6 +25,7 @@ export type CopyButtonSlots = typeof __propDef.slots;
|
|
24
25
|
*
|
25
26
|
* @props
|
26
27
|
*
|
28
|
+
* - `classNoscript` - noscript class
|
27
29
|
* - `class`
|
28
30
|
* - `id`
|
29
31
|
* - `text` - text to copy
|
@@ -10,6 +10,7 @@ Data table to display an array of JS objects. Click a column header to sort.
|
|
10
10
|
- `ascending` - default sort order
|
11
11
|
- `classButton` - button class
|
12
12
|
- `classFooter` - footer class
|
13
|
+
- `classNoscript` - noscript class
|
13
14
|
- `classPageControls` - class of `div` that wraps the "Previous" and "Next" buttons
|
14
15
|
- `classPageNumber` - class of `div` wrapping page numbers
|
15
16
|
- `classTable` - table class
|
@@ -57,7 +58,9 @@ Data table to display an array of JS objects. Click a column header to sort.
|
|
57
58
|
|
58
59
|
<script context="module"></script>
|
59
60
|
|
60
|
-
<script>
|
61
|
+
<script>import { messageNoScript } from "../util/messages";
|
62
|
+
import { onMount } from "svelte";
|
63
|
+
export let data;
|
61
64
|
export let columns = [];
|
62
65
|
if (!columns.length && data[0]) {
|
63
66
|
columns = Object.keys(data[0]);
|
@@ -80,6 +83,8 @@ export let classPageNumber = "";
|
|
80
83
|
export let classPageControls = "";
|
81
84
|
export let paginate = 0;
|
82
85
|
export let currentPage = 1;
|
86
|
+
export let classNoscript = "";
|
87
|
+
let clientJs = false;
|
83
88
|
$:
|
84
89
|
numberOfPages = Math.floor(data.length / paginate) + 1;
|
85
90
|
const sort = (column, toggleAscending = true) => {
|
@@ -117,6 +122,7 @@ const sort = (column, toggleAscending = true) => {
|
|
117
122
|
sortBy = column;
|
118
123
|
};
|
119
124
|
sort(sortBy, false);
|
125
|
+
onMount(() => clientJs = true);
|
120
126
|
</script>
|
121
127
|
|
122
128
|
<table class={classTable} id={idTable}>
|
@@ -155,18 +161,24 @@ sort(sortBy, false);
|
|
155
161
|
<div class={classPageControls}>
|
156
162
|
<button
|
157
163
|
class={classButton}
|
158
|
-
disabled={currentPage < 2}
|
164
|
+
disabled={!clientJs || currentPage < 2}
|
159
165
|
on:click={() => currentPage--}
|
160
166
|
>
|
161
167
|
<slot name="previous">Previous</slot>
|
162
168
|
</button>
|
163
169
|
<button
|
164
170
|
class={classButton}
|
165
|
-
disabled={currentPage >= numberOfPages}
|
171
|
+
disabled={!clientJs || currentPage >= numberOfPages}
|
166
172
|
on:click={() => currentPage++}
|
167
173
|
>
|
168
174
|
<slot name="next">Next</slot>
|
169
175
|
</button>
|
170
176
|
</div>
|
171
177
|
</div>
|
178
|
+
|
179
|
+
<noscript>
|
180
|
+
<div class={classNoscript}>
|
181
|
+
{messageNoScript}
|
182
|
+
</div>
|
183
|
+
</noscript>
|
172
184
|
{/if}
|
@@ -24,6 +24,7 @@ declare const __propDef: {
|
|
24
24
|
/** class of `div` that wraps the "Previous" and "Next" buttons */ classPageControls?: string | undefined;
|
25
25
|
/** number of rows to show on each page, defaults to `0` - no pagination */ paginate?: number | undefined;
|
26
26
|
/** current page, defaults to `1` */ currentPage?: number | undefined;
|
27
|
+
/** noscript class */ classNoscript?: string | undefined;
|
27
28
|
};
|
28
29
|
events: {
|
29
30
|
[evt: string]: CustomEvent<any>;
|
@@ -46,6 +47,7 @@ export type DataTableSlots = typeof __propDef.slots;
|
|
46
47
|
* - `ascending` - default sort order
|
47
48
|
* - `classButton` - button class
|
48
49
|
* - `classFooter` - footer class
|
50
|
+
* - `classNoscript` - noscript class
|
49
51
|
* - `classPageControls` - class of `div` that wraps the "Previous" and "Next" buttons
|
50
52
|
* - `classPageNumber` - class of `div` wrapping page numbers
|
51
53
|
* - `classTable` - table class
|
@@ -9,6 +9,7 @@ Text editor with controls to add elements and keyboard shortcuts.
|
|
9
9
|
|
10
10
|
- `classButton` - `class` of all the `button` elements
|
11
11
|
- `classControls` - `class` of the `div` that wraps the controls
|
12
|
+
- `classNoscript` - noscript class
|
12
13
|
- `classTextarea` - `class` of the `textarea` element
|
13
14
|
- `contentElements` - an array of content elements for the controls
|
14
15
|
- `idControls` - `id` of the `div` that wraps the controls
|
@@ -55,7 +56,9 @@ Text editor with controls to add elements and keyboard shortcuts.
|
|
55
56
|
|
56
57
|
<script context="module"></script>
|
57
58
|
|
58
|
-
<script>
|
59
|
+
<script>import { onMount } from "svelte";
|
60
|
+
import { messageNoScript } from "../util/messages";
|
61
|
+
export let contentElements = [];
|
59
62
|
export let valueTextarea = "";
|
60
63
|
export let placeholderTextarea = "";
|
61
64
|
export let classTextarea = "";
|
@@ -73,6 +76,8 @@ export let keyPairs = {
|
|
73
76
|
'"': '"',
|
74
77
|
"`": "`"
|
75
78
|
};
|
79
|
+
export let classNoscript = "";
|
80
|
+
let clientJs = false;
|
76
81
|
let textArea;
|
77
82
|
contentElements.forEach((el) => {
|
78
83
|
if (el.display === "wrap")
|
@@ -330,6 +335,7 @@ const correctFollowing = (currentLineNumber, decrement = false) => {
|
|
330
335
|
}
|
331
336
|
valueTextarea = lines.join("\n");
|
332
337
|
};
|
338
|
+
onMount(() => clientJs = true);
|
333
339
|
</script>
|
334
340
|
|
335
341
|
<textarea
|
@@ -348,13 +354,14 @@ const correctFollowing = (currentLineNumber, decrement = false) => {
|
|
348
354
|
}}
|
349
355
|
on:input
|
350
356
|
/>
|
357
|
+
|
351
358
|
<div id={idControls} class={classControls}>
|
352
359
|
{#each contentElements as el}
|
353
360
|
<button
|
354
361
|
class={el.class ? `${classButton} ${el.class}` : classButton}
|
355
362
|
on:click={() => addContent(el)}
|
356
363
|
title={el.name}
|
357
|
-
|
364
|
+
disabled={!clientJs}
|
358
365
|
>
|
359
366
|
{#if typeof el.icon !== "string"}
|
360
367
|
<svelte:component this={el.icon} />
|
@@ -364,3 +371,9 @@ const correctFollowing = (currentLineNumber, decrement = false) => {
|
|
364
371
|
</button>
|
365
372
|
{/each}
|
366
373
|
</div>
|
374
|
+
|
375
|
+
<noscript>
|
376
|
+
<div class={classNoscript}>
|
377
|
+
{messageNoScript}
|
378
|
+
</div>
|
379
|
+
</noscript>
|
@@ -18,7 +18,7 @@ export interface EditorContentElement {
|
|
18
18
|
/** class to apply to the specific button */
|
19
19
|
class?: string;
|
20
20
|
}
|
21
|
-
import type
|
21
|
+
import { type ComponentType } from "svelte";
|
22
22
|
declare const __propDef: {
|
23
23
|
props: {
|
24
24
|
/** an array of content elements for the controls */ contentElements?: EditorContentElement[] | undefined;
|
@@ -34,6 +34,7 @@ declare const __propDef: {
|
|
34
34
|
/** keys that will auto-close if typed, value is their closing character */ keyPairs?: {
|
35
35
|
[key: string]: string;
|
36
36
|
} | undefined;
|
37
|
+
/** noscript class */ classNoscript?: string | undefined;
|
37
38
|
};
|
38
39
|
events: {
|
39
40
|
input: Event;
|
@@ -54,6 +55,7 @@ export type EditorSlots = typeof __propDef.slots;
|
|
54
55
|
*
|
55
56
|
* - `classButton` - `class` of all the `button` elements
|
56
57
|
* - `classControls` - `class` of the `div` that wraps the controls
|
58
|
+
* - `classNoscript` - noscript class
|
57
59
|
* - `classTextarea` - `class` of the `textarea` element
|
58
60
|
* - `contentElements` - an array of content elements for the controls
|
59
61
|
* - `idControls` - `id` of the `div` that wraps the controls
|
@@ -7,6 +7,7 @@ Make the document or a specific element fullscreen.
|
|
7
7
|
|
8
8
|
@props
|
9
9
|
|
10
|
+
- `classNoscript` - noscript class
|
10
11
|
- `class`
|
11
12
|
- `confirmMessage` - message to display in the `confirm` popup, set this to empty string `""` to disable `confirm`
|
12
13
|
- `id`
|
@@ -17,8 +18,8 @@ Make the document or a specific element fullscreen.
|
|
17
18
|
|
18
19
|
| name | purpose | default value |
|
19
20
|
| ---------- | ---------------------------------------------- | -------------------- |
|
21
|
+
| `default` | content to display when fullscreen is disabled | `Enabled Fullscreen` |
|
20
22
|
| `enabled` | content to display when fullscreen is enabled | `Exit Fullscreen` |
|
21
|
-
| `disabled` | content to display when fullscreen is disabled | `Enabled Fullscreen` |
|
22
23
|
|
23
24
|
@example
|
24
25
|
|
@@ -42,17 +43,16 @@ Make the document or a specific element fullscreen.
|
|
42
43
|
-->
|
43
44
|
|
44
45
|
<script>import { onMount } from "svelte";
|
46
|
+
import { messageNoScript } from "../util/messages";
|
45
47
|
let className = "";
|
46
48
|
export { className as class };
|
47
49
|
export let id = "";
|
48
50
|
export let title = "Fullscreen";
|
49
51
|
export let targetElement = null;
|
50
52
|
export let confirmMessage = "";
|
53
|
+
export let classNoscript = "";
|
54
|
+
let clientJs = false;
|
51
55
|
let fullscreen = false;
|
52
|
-
onMount(() => {
|
53
|
-
if (!targetElement)
|
54
|
-
targetElement = document.documentElement;
|
55
|
-
});
|
56
56
|
const onClick = () => {
|
57
57
|
if (fullscreen) {
|
58
58
|
document.exitFullscreen();
|
@@ -68,14 +68,25 @@ const onClick = () => {
|
|
68
68
|
}
|
69
69
|
}
|
70
70
|
};
|
71
|
+
onMount(() => {
|
72
|
+
clientJs = true;
|
73
|
+
if (!targetElement)
|
74
|
+
targetElement = document.documentElement;
|
75
|
+
});
|
71
76
|
</script>
|
72
77
|
|
73
78
|
<svelte:window on:fullscreenchange={() => (fullscreen = !fullscreen)} />
|
74
79
|
|
75
|
-
<button on:click={onClick} class={className} {id} {title}>
|
80
|
+
<button disabled={!clientJs} on:click={onClick} class={className} {id} {title}>
|
76
81
|
{#if fullscreen}
|
77
82
|
<slot name="enabled">Exit Fullscreen</slot>
|
78
83
|
{:else}
|
79
|
-
<slot
|
84
|
+
<slot>Enable Fullscreen</slot>
|
80
85
|
{/if}
|
81
86
|
</button>
|
87
|
+
|
88
|
+
<noscript>
|
89
|
+
<div class={classNoscript}>
|
90
|
+
{messageNoScript}
|
91
|
+
</div>
|
92
|
+
</noscript>
|
@@ -6,13 +6,14 @@ declare const __propDef: {
|
|
6
6
|
title?: string | undefined;
|
7
7
|
/** element to make fullscreen (defaults to `document.documentElement` upon mount) */ targetElement?: HTMLElement | null | undefined;
|
8
8
|
/** message to display in the `confirm` popup, set this to empty string `""` to disable `confirm` */ confirmMessage?: string | undefined;
|
9
|
+
/** noscript class */ classNoscript?: string | undefined;
|
9
10
|
};
|
10
11
|
events: {
|
11
12
|
[evt: string]: CustomEvent<any>;
|
12
13
|
};
|
13
14
|
slots: {
|
14
15
|
enabled: {};
|
15
|
-
|
16
|
+
default: {};
|
16
17
|
};
|
17
18
|
};
|
18
19
|
export type FullscreenButtonProps = typeof __propDef.props;
|
@@ -25,6 +26,7 @@ export type FullscreenButtonSlots = typeof __propDef.slots;
|
|
25
26
|
*
|
26
27
|
* @props
|
27
28
|
*
|
29
|
+
* - `classNoscript` - noscript class
|
28
30
|
* - `class`
|
29
31
|
* - `confirmMessage` - message to display in the `confirm` popup, set this to empty string `""` to disable `confirm`
|
30
32
|
* - `id`
|
@@ -35,8 +37,8 @@ export type FullscreenButtonSlots = typeof __propDef.slots;
|
|
35
37
|
*
|
36
38
|
* | name | purpose | default value |
|
37
39
|
* | ---------- | ---------------------------------------------- | -------------------- |
|
40
|
+
* | `default` | content to display when fullscreen is disabled | `Enabled Fullscreen` |
|
38
41
|
* | `enabled` | content to display when fullscreen is enabled | `Exit Fullscreen` |
|
39
|
-
* | `disabled` | content to display when fullscreen is disabled | `Enabled Fullscreen` |
|
40
42
|
*
|
41
43
|
* @example
|
42
44
|
*
|
@@ -0,0 +1,155 @@
|
|
1
|
+
<!--
|
2
|
+
@component
|
3
|
+
|
4
|
+
### Popover
|
5
|
+
|
6
|
+
Displays a popover relatively positioned to the button.
|
7
|
+
|
8
|
+
@props
|
9
|
+
|
10
|
+
- `classButton` - button class
|
11
|
+
- `classPopover` - popover class
|
12
|
+
- `class`
|
13
|
+
- `display` - if `eventType="click"`, controls the display
|
14
|
+
- `eventType` - controls if hovering or clicking the button displays the popover
|
15
|
+
- `idButton` - button id
|
16
|
+
- `idPopover` - popover id
|
17
|
+
- `id`
|
18
|
+
- `position` - where the popover is displayed in relation to the button
|
19
|
+
|
20
|
+
@slots
|
21
|
+
|
22
|
+
| name | purpose | default value |
|
23
|
+
| ---------- | ------------------------------- | ------------- |
|
24
|
+
| `default` | default | Popover |
|
25
|
+
| `button` | button contents | Open |
|
26
|
+
|
27
|
+
@example
|
28
|
+
|
29
|
+
```svelte
|
30
|
+
<script>
|
31
|
+
import { Popover } from "drab";
|
32
|
+
</script>
|
33
|
+
|
34
|
+
<Popover>
|
35
|
+
<span slot="button">Hover</span>
|
36
|
+
<div>
|
37
|
+
<div>Popover</div>
|
38
|
+
<button>Button</button>
|
39
|
+
<button>Button</button>
|
40
|
+
<button>Button</button>
|
41
|
+
</div>
|
42
|
+
</Popover>
|
43
|
+
```
|
44
|
+
-->
|
45
|
+
|
46
|
+
<script>import { onMount, tick } from "svelte";
|
47
|
+
let className = "";
|
48
|
+
export { className as class };
|
49
|
+
export let id = "";
|
50
|
+
export let classButton = "";
|
51
|
+
export let classPopover = "";
|
52
|
+
export let idButton = "";
|
53
|
+
export let idPopover = "";
|
54
|
+
export let display = false;
|
55
|
+
export let position = "bottom";
|
56
|
+
export let eventType = "hover";
|
57
|
+
let clientEventType = "hover";
|
58
|
+
let popover;
|
59
|
+
let button;
|
60
|
+
let coordinates = { x: 0, y: 0 };
|
61
|
+
const correctPosition = async () => {
|
62
|
+
if (position === "top" || position === "bottom") {
|
63
|
+
coordinates.x = button.offsetWidth / 2 - popover.offsetWidth / 2;
|
64
|
+
if (position === "top") {
|
65
|
+
coordinates.y = -popover.offsetHeight;
|
66
|
+
} else {
|
67
|
+
coordinates.y = button.offsetHeight;
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
coordinates.y = button.offsetHeight / 2 - popover.offsetHeight / 2;
|
71
|
+
if (position === "left") {
|
72
|
+
coordinates.x = -popover.offsetWidth;
|
73
|
+
} else {
|
74
|
+
coordinates.x = button.offsetWidth;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
await tick();
|
78
|
+
const rect = popover.getBoundingClientRect();
|
79
|
+
if (rect.x < 0) {
|
80
|
+
coordinates.x += Math.abs(rect.x);
|
81
|
+
} else if (rect.x + popover.offsetWidth > window.innerWidth) {
|
82
|
+
coordinates.x -= rect.x + popover.offsetWidth - window.innerWidth + 16;
|
83
|
+
}
|
84
|
+
if (rect.y < 0) {
|
85
|
+
coordinates.y += Math.abs(rect.y);
|
86
|
+
} else if (rect.y + popover.offsetHeight > window.innerHeight) {
|
87
|
+
coordinates.y -= rect.y + popover.offsetHeight - window.innerHeight;
|
88
|
+
}
|
89
|
+
};
|
90
|
+
const clickOutside = (e) => {
|
91
|
+
if (popover && e.target instanceof HTMLElement) {
|
92
|
+
if (!popover.contains(e.target)) {
|
93
|
+
display = false;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
};
|
97
|
+
const onKeyDown = (e) => {
|
98
|
+
if (e.key === "Escape") {
|
99
|
+
display = false;
|
100
|
+
}
|
101
|
+
};
|
102
|
+
const openPopover = async (e) => {
|
103
|
+
e.stopPropagation();
|
104
|
+
display = true;
|
105
|
+
};
|
106
|
+
onMount(() => {
|
107
|
+
clientEventType = eventType;
|
108
|
+
correctPosition();
|
109
|
+
});
|
110
|
+
</script>
|
111
|
+
|
112
|
+
<svelte:document on:keydown={onKeyDown} on:click={clickOutside} />
|
113
|
+
|
114
|
+
<div class="db-relative {className}" {id}>
|
115
|
+
<button
|
116
|
+
bind:this={button}
|
117
|
+
id={idButton}
|
118
|
+
class={classButton}
|
119
|
+
on:click={openPopover}
|
120
|
+
on:mouseover={correctPosition}
|
121
|
+
on:focus={correctPosition}
|
122
|
+
>
|
123
|
+
<slot name="button">Open</slot>
|
124
|
+
</button>
|
125
|
+
<div
|
126
|
+
bind:this={popover}
|
127
|
+
id={idPopover}
|
128
|
+
class="db-popover {classPopover}"
|
129
|
+
class:db-type-click={clientEventType === "click" && display}
|
130
|
+
class:db-type-hover={clientEventType === "hover"}
|
131
|
+
style:top="{coordinates.y}px"
|
132
|
+
style:left="{coordinates.x}px"
|
133
|
+
>
|
134
|
+
<slot>Popover</slot>
|
135
|
+
</div>
|
136
|
+
</div>
|
137
|
+
|
138
|
+
<style>
|
139
|
+
.db-relative {
|
140
|
+
position: relative;
|
141
|
+
}
|
142
|
+
.db-popover {
|
143
|
+
position: absolute;
|
144
|
+
opacity: 0;
|
145
|
+
z-index: -10;
|
146
|
+
}
|
147
|
+
button:hover + .db-type-hover,
|
148
|
+
button:focus + .db-type-hover,
|
149
|
+
.db-type-hover:hover,
|
150
|
+
.db-type-hover:focus-within,
|
151
|
+
.db-type-click {
|
152
|
+
opacity: 1;
|
153
|
+
z-index: 10;
|
154
|
+
}
|
155
|
+
</style>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
2
|
+
declare const __propDef: {
|
3
|
+
props: {
|
4
|
+
class?: string | undefined;
|
5
|
+
id?: string | undefined;
|
6
|
+
/** button class */ classButton?: string | undefined;
|
7
|
+
/** popover class */ classPopover?: string | undefined;
|
8
|
+
/** button id */ idButton?: string | undefined;
|
9
|
+
/** popover id */ idPopover?: string | undefined;
|
10
|
+
/** if `eventType="click"`, controls the display */ display?: boolean | undefined;
|
11
|
+
/** where the popover is displayed in relation to the button */ position?: "top" | "bottom" | "left" | "right" | undefined;
|
12
|
+
/** controls if hovering or clicking the button displays the popover */ eventType?: ("click" | "hover") | undefined;
|
13
|
+
};
|
14
|
+
events: {
|
15
|
+
[evt: string]: CustomEvent<any>;
|
16
|
+
};
|
17
|
+
slots: {
|
18
|
+
button: {};
|
19
|
+
default: {};
|
20
|
+
};
|
21
|
+
};
|
22
|
+
export type PopoverProps = typeof __propDef.props;
|
23
|
+
export type PopoverEvents = typeof __propDef.events;
|
24
|
+
export type PopoverSlots = typeof __propDef.slots;
|
25
|
+
/**
|
26
|
+
* ### Popover
|
27
|
+
*
|
28
|
+
* Displays a popover relatively positioned to the button.
|
29
|
+
*
|
30
|
+
* @props
|
31
|
+
*
|
32
|
+
* - `classButton` - button class
|
33
|
+
* - `classPopover` - popover class
|
34
|
+
* - `class`
|
35
|
+
* - `display` - if `eventType="click"`, controls the display
|
36
|
+
* - `eventType` - controls if hovering or clicking the button displays the popover
|
37
|
+
* - `idButton` - button id
|
38
|
+
* - `idPopover` - popover id
|
39
|
+
* - `id`
|
40
|
+
* - `position` - where the popover is displayed in relation to the button
|
41
|
+
*
|
42
|
+
* @slots
|
43
|
+
*
|
44
|
+
* | name | purpose | default value |
|
45
|
+
* | ---------- | ------------------------------- | ------------- |
|
46
|
+
* | `default` | default | Popover |
|
47
|
+
* | `button` | button contents | Open |
|
48
|
+
*
|
49
|
+
* @example
|
50
|
+
*
|
51
|
+
* ```svelte
|
52
|
+
* <script>
|
53
|
+
* import { Popover } from "drab";
|
54
|
+
* </script>
|
55
|
+
*
|
56
|
+
* <Popover>
|
57
|
+
* <span slot="button">Hover</span>
|
58
|
+
* <div>
|
59
|
+
* <div>Popover</div>
|
60
|
+
* <button>Button</button>
|
61
|
+
* <button>Button</button>
|
62
|
+
* <button>Button</button>
|
63
|
+
* </div>
|
64
|
+
* </Popover>
|
65
|
+
* ```
|
66
|
+
*/
|
67
|
+
export default class Popover extends SvelteComponent<PopoverProps, PopoverEvents, PopoverSlots> {
|
68
|
+
}
|
69
|
+
export {};
|
@@ -7,10 +7,11 @@ Uses the navigator api to share or copy a url link depending on browser support.
|
|
7
7
|
|
8
8
|
@props
|
9
9
|
|
10
|
+
- `classNoscript` - noscript class
|
10
11
|
- `class`
|
11
12
|
- `id`
|
12
13
|
- `text` - prefixed text in share message
|
13
|
-
- `title` - title of share message and button attribute
|
14
|
+
- `title` - title of share message and button attribute, defaults to end of url
|
14
15
|
- `url` - url to be shared
|
15
16
|
|
16
17
|
@slots
|
@@ -35,12 +36,15 @@ Uses the navigator api to share or copy a url link depending on browser support.
|
|
35
36
|
```
|
36
37
|
-->
|
37
38
|
|
38
|
-
<script>
|
39
|
+
<script>import { onMount } from "svelte";
|
40
|
+
let className = "";
|
39
41
|
export { className as class };
|
40
42
|
export let id = "";
|
41
43
|
export let text = "";
|
42
44
|
export let url;
|
43
45
|
export let title = url.split("/").splice(-1)[0];
|
46
|
+
export let classNoscript = "";
|
47
|
+
let clientJs = false;
|
44
48
|
let complete = false;
|
45
49
|
const onClick = async () => {
|
46
50
|
try {
|
@@ -55,12 +59,15 @@ const onClick = async () => {
|
|
55
59
|
console.log(error);
|
56
60
|
}
|
57
61
|
};
|
62
|
+
onMount(() => clientJs = true);
|
58
63
|
</script>
|
59
64
|
|
60
|
-
<button on:click={onClick} class={className} {id} {title}>
|
65
|
+
<button disabled={!clientJs} on:click={onClick} class={className} {id} {title}>
|
61
66
|
{#if complete}
|
62
67
|
<slot name="complete">Copied</slot>
|
63
68
|
{:else}
|
64
69
|
<slot>Share</slot>
|
65
70
|
{/if}
|
66
71
|
</button>
|
72
|
+
|
73
|
+
<noscript><span class={classNoscript}>{url}</span></noscript>
|
@@ -5,7 +5,8 @@ declare const __propDef: {
|
|
5
5
|
id?: string | undefined;
|
6
6
|
/** prefixed text in share message */ text?: string | undefined;
|
7
7
|
/** url to be shared */ url: string;
|
8
|
-
/** title of share message and button attribute */ title?: string | undefined;
|
8
|
+
/** title of share message and button attribute, defaults to end of url */ title?: string | undefined;
|
9
|
+
/** noscript class */ classNoscript?: string | undefined;
|
9
10
|
};
|
10
11
|
events: {
|
11
12
|
[evt: string]: CustomEvent<any>;
|
@@ -25,10 +26,11 @@ export type ShareButtonSlots = typeof __propDef.slots;
|
|
25
26
|
*
|
26
27
|
* @props
|
27
28
|
*
|
29
|
+
* - `classNoscript` - noscript class
|
28
30
|
* - `class`
|
29
31
|
* - `id`
|
30
32
|
* - `text` - prefixed text in share message
|
31
|
-
* - `title` - title of share message and button attribute
|
33
|
+
* - `title` - title of share message and button attribute, defaults to end of url
|
32
34
|
* - `url` - url to be shared
|
33
35
|
*
|
34
36
|
* @slots
|
package/dist/index.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import Chord from "./components/Chord.svelte";
|
2
|
+
import type { ChordNote } from "./components/Chord.svelte";
|
2
3
|
import ContextMenu from "./components/ContextMenu.svelte";
|
3
4
|
import CopyButton from "./components/CopyButton.svelte";
|
4
5
|
import DataTable from "./components/DataTable.svelte";
|
@@ -6,6 +7,7 @@ import type { DataTableRow } from "./components/DataTable.svelte";
|
|
6
7
|
import Editor from "./components/Editor.svelte";
|
7
8
|
import type { EditorContentElement } from "./components/Editor.svelte";
|
8
9
|
import FullscreenButton from "./components/FullscreenButton.svelte";
|
10
|
+
import Popover from "./components/Popover.svelte";
|
9
11
|
import ShareButton from "./components/ShareButton.svelte";
|
10
12
|
import YouTube from "./components/YouTube.svelte";
|
11
|
-
export { Chord, ContextMenu, CopyButton, DataTable, type DataTableRow, Editor, type EditorContentElement, FullscreenButton, ShareButton, YouTube, };
|
13
|
+
export { Chord, type ChordNote, ContextMenu, CopyButton, DataTable, type DataTableRow, Editor, type EditorContentElement, FullscreenButton, Popover, ShareButton, YouTube, };
|
package/dist/index.js
CHANGED
@@ -4,6 +4,7 @@ import CopyButton from "./components/CopyButton.svelte";
|
|
4
4
|
import DataTable from "./components/DataTable.svelte";
|
5
5
|
import Editor from "./components/Editor.svelte";
|
6
6
|
import FullscreenButton from "./components/FullscreenButton.svelte";
|
7
|
+
import Popover from "./components/Popover.svelte";
|
7
8
|
import ShareButton from "./components/ShareButton.svelte";
|
8
9
|
import YouTube from "./components/YouTube.svelte";
|
9
|
-
export { Chord, ContextMenu, CopyButton, DataTable, Editor, FullscreenButton, ShareButton, YouTube, };
|
10
|
+
export { Chord, ContextMenu, CopyButton, DataTable, Editor, FullscreenButton, Popover, ShareButton, YouTube, };
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare const messageNoScript = "JavaScript is disabled on your device. This feature requires JavaScript for full functionality.";
|
@@ -0,0 +1 @@
|
|
1
|
+
export const messageNoScript = "JavaScript is disabled on your device. This feature requires JavaScript for full functionality.";
|
package/package.json
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
{
|
2
2
|
"name": "drab",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.1.0",
|
4
4
|
"description": "An unstyled Svelte component library",
|
5
5
|
"keywords": [
|
6
6
|
"components",
|
7
7
|
"Svelte",
|
8
8
|
"SvelteKit",
|
9
9
|
"Chord",
|
10
|
+
"ContextMenu",
|
10
11
|
"Copy",
|
11
12
|
"DataTable",
|
12
13
|
"Editor",
|
13
14
|
"Fullscreen",
|
15
|
+
"Popover",
|
14
16
|
"Share",
|
15
17
|
"YouTube"
|
16
18
|
],
|
@@ -48,8 +50,8 @@
|
|
48
50
|
},
|
49
51
|
"devDependencies": {
|
50
52
|
"@sveltejs/adapter-vercel": "^3.0.3",
|
51
|
-
"@sveltejs/kit": "^1.22.
|
52
|
-
"@sveltejs/package": "^2.2.
|
53
|
+
"@sveltejs/kit": "^1.22.5",
|
54
|
+
"@sveltejs/package": "^2.2.1",
|
53
55
|
"@tailwindcss/typography": "^0.5.9",
|
54
56
|
"@types/node": "^20.4.9",
|
55
57
|
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
@@ -61,7 +63,7 @@
|
|
61
63
|
"postcss": "^8.4.27",
|
62
64
|
"prettier": "^3.0.1",
|
63
65
|
"prettier-plugin-svelte": "^3.0.3",
|
64
|
-
"prettier-plugin-tailwindcss": "^0.
|
66
|
+
"prettier-plugin-tailwindcss": "^0.5.1",
|
65
67
|
"publint": "^0.2.0",
|
66
68
|
"svelte-check": "^3.4.6",
|
67
69
|
"tailwindcss": "^3.3.3",
|