@txstate-mws/svelte-components 1.0.4 → 1.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/.eslintrc.cjs +37 -0
- package/docs/CollapsingTable.md +79 -0
- package/docs/ConditionalWrapper.md +35 -0
- package/docs/Modal.md +63 -0
- package/docs/PopupMenu.md +31 -0
- package/docs/ScreenReaderOnly.md +10 -0
- package/docs/actions.md +84 -0
- package/docs/stores.md +203 -0
- package/package.json +15 -37
- package/playwright.config.js +112 -0
- package/src/app.html +14 -0
- package/src/global.d.ts +1 -0
- package/src/lib/actions/buttonify.ts +27 -0
- package/src/lib/actions/glue.ts +96 -0
- package/src/lib/actions/index.ts +7 -0
- package/src/lib/actions/offset.ts +43 -0
- package/src/lib/actions/portal.ts +13 -0
- package/src/lib/actions/resize.ts +72 -0
- package/src/lib/actions/sticky.ts +105 -0
- package/src/lib/actions/stickyfixed.ts +160 -0
- package/src/lib/components/Card.svelte +25 -0
- package/src/lib/components/CardLayout.svelte +188 -0
- package/{components → src/lib/components}/CollapsingTable.svelte +65 -63
- package/{components → src/lib/components}/ConditionalWrapper.svelte +7 -6
- package/src/lib/components/FocusLock.svelte +102 -0
- package/{components → src/lib/components}/Modal.svelte +24 -22
- package/src/lib/components/MultiSelect.svelte +174 -0
- package/src/lib/components/PopupMenu.svelte +285 -0
- package/{components → src/lib/components}/ScreenReaderOnly.svelte +4 -3
- package/src/lib/components/index.ts +9 -0
- package/src/lib/index.ts +4 -0
- package/src/lib/types/CardLayout.ts +14 -0
- package/src/lib/types/CollapsingTable.ts +8 -0
- package/src/lib/types/PopupMenu.ts +5 -0
- package/src/lib/types/index.ts +3 -0
- package/src/lib/util/bodyoffset.ts +77 -0
- package/src/lib/util/index.ts +3 -0
- package/src/lib/util/repositioned.ts +91 -0
- package/src/lib/util/util.ts +36 -0
- package/src/routes/__layout.svelte +125 -0
- package/src/routes/actions/index.svelte +1 -0
- package/src/routes/actions/offset.svelte +4 -0
- package/src/routes/actions/offsetdebounce.svelte +4 -0
- package/src/routes/actions/resize.svelte +4 -0
- package/src/routes/actions/resizedebounce.svelte +4 -0
- package/src/routes/actions/sticky.svelte +4 -0
- package/src/routes/cards/index.svelte +4 -0
- package/src/routes/cards/preserve.svelte +4 -0
- package/src/routes/collapsingtable/index.svelte +4 -0
- package/src/routes/collapsingtable/stickyheader.svelte +4 -0
- package/src/routes/index.svelte +2 -0
- package/src/routes/modal.svelte +4 -0
- package/src/routes/multiselect.svelte +4 -0
- package/src/routes/popupmenu/body.svelte +4 -0
- package/src/routes/popupmenu/complex.svelte +4 -0
- package/src/routes/popupmenu/empty.svelte +5 -0
- package/src/routes/popupmenu/index.svelte +4 -0
- package/src/routes/popupmenu/parent.svelte +4 -0
- package/src/routes/popupmenu/scrollable.svelte +27 -0
- package/src/routes/popupmenu/showselected.svelte +4 -0
- package/src/test/Cards.svelte +64 -0
- package/src/test/CollapsingTableTest.svelte +36 -0
- package/src/test/ModalTest.svelte +58 -0
- package/src/test/MultiSelectTest.svelte +26 -0
- package/src/test/Offset.svelte +32 -0
- package/src/test/PopupMenuBody.svelte +34 -0
- package/src/test/PopupMenuButtonIsParent.svelte +36 -0
- package/src/test/PopupMenuComplex.svelte +34 -0
- package/src/test/PopupMenuSimple.svelte +36 -0
- package/src/test/Resize.svelte +29 -0
- package/src/test/Sticky.svelte +65 -0
- package/static/layout.css +263 -0
- package/svelte.config.js +15 -0
- package/tests/.eslintrc.cjs +19 -0
- package/tests/CardLayout.test.js +41 -0
- package/tests/CollapsingTable.test.js +37 -0
- package/tests/Modal.test.js +18 -0
- package/tests/MultiSelect.test.js +58 -0
- package/tests/PopupMenu.test.js +55 -0
- package/tests/common.js +4 -0
- package/tsconfig.json +31 -0
- package/actions/buttonify.d.ts +0 -8
- package/actions/buttonify.js +0 -26
- package/actions/glue.d.ts +0 -16
- package/actions/glue.js +0 -82
- package/actions/index.d.ts +0 -7
- package/actions/index.js +0 -7
- package/actions/offset.d.ts +0 -15
- package/actions/offset.js +0 -35
- package/actions/portal.d.ts +0 -4
- package/actions/portal.js +0 -13
- package/actions/resize.d.ts +0 -20
- package/actions/resize.js +0 -45
- package/actions/sticky.d.ts +0 -33
- package/actions/sticky.js +0 -85
- package/actions/stickyfixed.d.ts +0 -25
- package/actions/stickyfixed.js +0 -157
- package/components/CollapsingTable.svelte.d.ts +0 -59
- package/components/ConditionalWrapper.svelte.d.ts +0 -23
- package/components/FocusLock.svelte +0 -107
- package/components/FocusLock.svelte.d.ts +0 -26
- package/components/Modal.svelte.d.ts +0 -27
- package/components/PopupMenu.svelte +0 -279
- package/components/PopupMenu.svelte.d.ts +0 -44
- package/components/ScreenReaderOnly.svelte.d.ts +0 -20
- package/components/index.d.ts +0 -6
- package/components/index.js +0 -6
- package/index.d.ts +0 -4
- package/index.js +0 -4
- package/types/CollapsingTable.d.ts +0 -8
- package/types/CollapsingTable.js +0 -1
- package/types/PopupMenu.d.ts +0 -5
- package/types/PopupMenu.js +0 -1
- package/types/index.d.ts +0 -2
- package/types/index.js +0 -2
- package/util/bodyoffset.d.ts +0 -14
- package/util/bodyoffset.js +0 -72
- package/util/index.d.ts +0 -3
- package/util/index.js +0 -3
- package/util/repositioned.d.ts +0 -12
- package/util/repositioned.js +0 -81
- package/util/util.d.ts +0 -2
- package/util/util.js +0 -10
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { buttonify, PopupMenu } from '$lib'
|
|
3
|
+
let button: HTMLElement
|
|
4
|
+
|
|
5
|
+
export let items = [
|
|
6
|
+
{ value: '0', label: 'Sunday', disabled: true },
|
|
7
|
+
{ value: '1', label: 'Monday' },
|
|
8
|
+
{ value: '2', label: 'Tuesday' },
|
|
9
|
+
{ value: '3', label: 'Wednesday' },
|
|
10
|
+
{ value: '4', label: 'Thursday', disabled: true },
|
|
11
|
+
{ value: '5', label: 'Friday' },
|
|
12
|
+
{ value: '6', label: 'Saturday', disabled: true }
|
|
13
|
+
]
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div class="topspacer"></div>
|
|
17
|
+
<div class="container">
|
|
18
|
+
<div class="ui gold button" use:buttonify bind:this={button}>
|
|
19
|
+
Popup Menu
|
|
20
|
+
<PopupMenu buttonelement={button} {items}></PopupMenu>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
.topspacer {
|
|
26
|
+
height: 20px;
|
|
27
|
+
}
|
|
28
|
+
.container {
|
|
29
|
+
margin-left: 12px;
|
|
30
|
+
}
|
|
31
|
+
.button {
|
|
32
|
+
position: relative;
|
|
33
|
+
margin-left: 12px;
|
|
34
|
+
width: 210px;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import PopupMenu from '$lib/components/PopupMenu.svelte'
|
|
3
|
+
let button: HTMLElement
|
|
4
|
+
|
|
5
|
+
export let items: { value: string, label: string, disabled?: boolean }[] = [
|
|
6
|
+
{ value: '0', label: 'Sunday', disabled: true },
|
|
7
|
+
{ value: '1', label: 'Monday' },
|
|
8
|
+
{ value: '2', label: 'Tuesday' },
|
|
9
|
+
{ value: '3', label: 'Wednesday' },
|
|
10
|
+
{ value: '4', label: 'Thursday', disabled: true },
|
|
11
|
+
{ value: '5', label: 'Friday' },
|
|
12
|
+
{ value: '6', label: 'Saturday', disabled: true }
|
|
13
|
+
]
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div class="topspacer"></div>
|
|
17
|
+
<div class="container">
|
|
18
|
+
<div class="container">
|
|
19
|
+
<button data-testid="button" class="ui gold button" bind:this={button}>Popup Menu</button>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="topspacer"></div>
|
|
22
|
+
<div class="container">
|
|
23
|
+
<PopupMenu usePortal buttonelement={button} {items}></PopupMenu>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<style>
|
|
28
|
+
.topspacer {
|
|
29
|
+
height: 20px;
|
|
30
|
+
}
|
|
31
|
+
.container {
|
|
32
|
+
position: relative;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { hashify } from 'txstate-utils'
|
|
3
|
+
import PopupMenu from '$lib/components/PopupMenu.svelte'
|
|
4
|
+
|
|
5
|
+
export let showSelected = false
|
|
6
|
+
export let items = [
|
|
7
|
+
{ value: '0', label: 'Sunday', disabled: true },
|
|
8
|
+
{ value: '1', label: 'Monday' },
|
|
9
|
+
{ value: '2', label: 'Tuesday' },
|
|
10
|
+
{ value: '3', label: 'Wednesday' },
|
|
11
|
+
{ value: '4', label: 'Thursday', disabled: true },
|
|
12
|
+
{ value: '5', label: 'Friday' },
|
|
13
|
+
{ value: '6', label: 'Saturday', disabled: true }
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
let button: HTMLElement
|
|
17
|
+
let value: string
|
|
18
|
+
$: itemsByValue = hashify(items, 'value')
|
|
19
|
+
$: selected = itemsByValue[value]
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="topspacer"></div>
|
|
23
|
+
<div class="container">
|
|
24
|
+
<button id="test-button" class="ui gold button" bind:this={button}>Popup Menu</button>
|
|
25
|
+
<div>selected: {#if selected}{selected.value}, {selected.label}{:else}none{/if}</div>
|
|
26
|
+
<PopupMenu bind:value buttonelement={button} {items} {showSelected}></PopupMenu>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<style>
|
|
30
|
+
.topspacer {
|
|
31
|
+
height: 20px;
|
|
32
|
+
}
|
|
33
|
+
.container {
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { resize, ResizeStore } from '$lib'
|
|
3
|
+
export let debounce = false
|
|
4
|
+
const mysize = new ResizeStore()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div use:resize={{ store: mysize, debounce }} class='resizable'>resize this div</div>
|
|
8
|
+
<div class="display">
|
|
9
|
+
Above div's size...<br>
|
|
10
|
+
Width: {$mysize.offsetWidth}<br>
|
|
11
|
+
Height: {$mysize.offsetHeight}
|
|
12
|
+
</div>
|
|
13
|
+
debounce: {debounce}
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
div {
|
|
17
|
+
max-width: 300px;
|
|
18
|
+
}
|
|
19
|
+
.resizable {
|
|
20
|
+
resize: both;
|
|
21
|
+
overflow: auto;
|
|
22
|
+
min-height: 100px;
|
|
23
|
+
background: lightblue;
|
|
24
|
+
border: 1px solid black;
|
|
25
|
+
}
|
|
26
|
+
.display {
|
|
27
|
+
text-align: center;
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { sticky, stickyfixed } from '$lib'
|
|
3
|
+
let target: HTMLElement
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div class='above'>above</div>
|
|
7
|
+
<table>
|
|
8
|
+
<thead>
|
|
9
|
+
<tr use:sticky><th>Name</th><th>Bedtime</th></tr>
|
|
10
|
+
</thead>
|
|
11
|
+
<tbody>
|
|
12
|
+
<tr><td>Bobby</td><td>10pm</td></tr>
|
|
13
|
+
<tr><td>Sue</td><td>3am</td></tr>
|
|
14
|
+
<tr><td>Billy</td><td>11pm</td></tr>
|
|
15
|
+
<tr><td>Mary</td><td>7pm</td></tr>
|
|
16
|
+
<tr><td>Kevin</td><td>9:30pm</td></tr>
|
|
17
|
+
<tr><td>Jess</td><td>12am</td></tr>
|
|
18
|
+
<tr><td>Randy</td><td>1am</td></tr>
|
|
19
|
+
<tr><td>Daniel</td><td>11pm</td></tr>
|
|
20
|
+
<tr><td>Elizabetd</td><td>8pm</td></tr>
|
|
21
|
+
<tr><td>Catderine</td><td>4pm</td></tr>
|
|
22
|
+
<tr><td>Mandy</td><td>8:30pm</td></tr>
|
|
23
|
+
<tr><td>Chris</td><td>9pm</td></tr>
|
|
24
|
+
<tr><td>Sean</td><td>10:45pm</td></tr>
|
|
25
|
+
<tr><td>Jack</td><td>2am</td></tr>
|
|
26
|
+
<tr><td>Morgan</td><td>3pm</td></tr>
|
|
27
|
+
<tr><td>Chuck</td><td>8pm</td></tr>
|
|
28
|
+
</tbody>
|
|
29
|
+
</table>
|
|
30
|
+
<div class="extendedcontainer" bind:this={target}>
|
|
31
|
+
<table>
|
|
32
|
+
<thead use:stickyfixed={{ target }}>
|
|
33
|
+
<tr><th>Person</th><th>Calories</th><th>Fat</th><th>Protein</th></tr>
|
|
34
|
+
</thead>
|
|
35
|
+
<tbody>
|
|
36
|
+
<tr><td>Mirna</td><td>1</td><td>28g</td><td>29g</td></tr>
|
|
37
|
+
<tr><td>Fernando</td><td>38</td><td>2g</td><td>48g</td></tr>
|
|
38
|
+
<tr><td>Lisette</td><td>18</td><td>9g</td><td>23g</td></tr>
|
|
39
|
+
<tr><td>Ahmad</td><td>42</td><td>26g</td><td>49g</td></tr>
|
|
40
|
+
<tr><td>Laquanda</td><td>27</td><td>27g</td><td>49g</td></tr>
|
|
41
|
+
</tbody>
|
|
42
|
+
</table>
|
|
43
|
+
sticky header should continue to the bottom of this container
|
|
44
|
+
</div>
|
|
45
|
+
<div class='below'>below</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.above { height: 400px; }
|
|
49
|
+
.below { height: 1000px; }
|
|
50
|
+
.extendedcontainer { padding-bottom: 50px; border: 1px solid black; }
|
|
51
|
+
table {
|
|
52
|
+
position: relative;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
}
|
|
55
|
+
table th {
|
|
56
|
+
background: lightgray;
|
|
57
|
+
border: 2px solid black;
|
|
58
|
+
}
|
|
59
|
+
th:first-child, td:first-child {
|
|
60
|
+
width: 20em;
|
|
61
|
+
}
|
|
62
|
+
th:last-child, td:last-child {
|
|
63
|
+
width: 8em;
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--menu-width: 12rem;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.pure-img-responsive {
|
|
6
|
+
max-width: 100%;
|
|
7
|
+
height: auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
Add transition to containers so they can push in and out.
|
|
12
|
+
*/
|
|
13
|
+
#layout,
|
|
14
|
+
#menu,
|
|
15
|
+
.menu-link {
|
|
16
|
+
-webkit-transition: all 0.2s ease-out;
|
|
17
|
+
-moz-transition: all 0.2s ease-out;
|
|
18
|
+
-ms-transition: all 0.2s ease-out;
|
|
19
|
+
-o-transition: all 0.2s ease-out;
|
|
20
|
+
transition: all 0.2s ease-out;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
This is the parent `<div>` that contains the menu and the content area.
|
|
25
|
+
*/
|
|
26
|
+
#layout {
|
|
27
|
+
position: relative;
|
|
28
|
+
left: 0;
|
|
29
|
+
padding-left: 0;
|
|
30
|
+
}
|
|
31
|
+
#layout.active #menu {
|
|
32
|
+
left: var(--menu-width);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#layout.active .menu-link {
|
|
36
|
+
left: var(--menu-width);
|
|
37
|
+
}
|
|
38
|
+
/*
|
|
39
|
+
The content `<div>` is where all your content goes.
|
|
40
|
+
*/
|
|
41
|
+
.content {
|
|
42
|
+
margin: 2em auto;
|
|
43
|
+
padding: 0 2em;
|
|
44
|
+
max-width: 1200px;
|
|
45
|
+
margin-bottom: 50px;
|
|
46
|
+
line-height: 1.6em;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.header {
|
|
50
|
+
margin: 0;
|
|
51
|
+
color: #333;
|
|
52
|
+
text-align: center;
|
|
53
|
+
padding: 2.5em 2em 0;
|
|
54
|
+
border-bottom: 1px solid #eee;
|
|
55
|
+
}
|
|
56
|
+
.header h1 {
|
|
57
|
+
margin: 0.2em 0;
|
|
58
|
+
font-size: 3em;
|
|
59
|
+
font-weight: 300;
|
|
60
|
+
}
|
|
61
|
+
.header h2 {
|
|
62
|
+
font-weight: 300;
|
|
63
|
+
color: #ccc;
|
|
64
|
+
padding: 0;
|
|
65
|
+
margin-top: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.content-subhead {
|
|
69
|
+
margin: 50px 0 20px 0;
|
|
70
|
+
font-weight: 300;
|
|
71
|
+
color: #888;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
|
|
78
|
+
appears on the left side of the page.
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
#menu {
|
|
82
|
+
margin-left: calc(-1 * var(--menu-width));
|
|
83
|
+
width: var(--menu-width);
|
|
84
|
+
position: fixed;
|
|
85
|
+
top: 0;
|
|
86
|
+
left: 0;
|
|
87
|
+
bottom: 0;
|
|
88
|
+
z-index: 1000; /* so the menu or its navicon stays above all content */
|
|
89
|
+
background: #191818;
|
|
90
|
+
overflow-y: auto;
|
|
91
|
+
}
|
|
92
|
+
/*
|
|
93
|
+
All anchors inside the menu should be styled like this.
|
|
94
|
+
*/
|
|
95
|
+
#menu a {
|
|
96
|
+
color: #999;
|
|
97
|
+
border: none;
|
|
98
|
+
padding: 0.6em;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
Remove all background/borders, since we are applying them to #menu.
|
|
103
|
+
*/
|
|
104
|
+
#menu .pure-menu,
|
|
105
|
+
#menu .pure-menu ul {
|
|
106
|
+
border: none;
|
|
107
|
+
background: transparent;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/*
|
|
111
|
+
Add that light border to separate items into groups.
|
|
112
|
+
*/
|
|
113
|
+
#menu .pure-menu ul,
|
|
114
|
+
#menu .pure-menu .menu-item-divided {
|
|
115
|
+
border-top: 1px solid #666;
|
|
116
|
+
}
|
|
117
|
+
/*
|
|
118
|
+
Change color of the anchor links on hover/focus.
|
|
119
|
+
*/
|
|
120
|
+
#menu .pure-menu li a:hover,
|
|
121
|
+
#menu .pure-menu li a:focus {
|
|
122
|
+
background: #333;
|
|
123
|
+
}
|
|
124
|
+
#menu .pure-menu li.pure-menu-selected a:hover,
|
|
125
|
+
#menu .pure-menu li.pure-menu-selected a:focus,
|
|
126
|
+
#menu .pure-menu li.pure-menu-subselected a:hover,
|
|
127
|
+
#menu .pure-menu li.pure-menu-subselected a:focus {
|
|
128
|
+
background: inherit;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
#menu .pure-menu-parent {
|
|
133
|
+
border-top: 1px solid #666;
|
|
134
|
+
}
|
|
135
|
+
#menu .pure-menu-parent a {
|
|
136
|
+
color: #fff;
|
|
137
|
+
}
|
|
138
|
+
/*
|
|
139
|
+
This styles the selected menu item `<li>`.
|
|
140
|
+
*/
|
|
141
|
+
#menu .pure-menu-selected {
|
|
142
|
+
background: #1f8dd6;
|
|
143
|
+
}
|
|
144
|
+
/*
|
|
145
|
+
This styles a link within a selected menu item `<li>`.
|
|
146
|
+
*/
|
|
147
|
+
#menu .pure-menu-selected a {
|
|
148
|
+
color: #fff;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#menu .pure-menu-parent.pure-menu-subselected {
|
|
152
|
+
background: #8bb6d3;
|
|
153
|
+
}
|
|
154
|
+
#menu .pure-menu-parent.pure-menu-subselected a {
|
|
155
|
+
color: black;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
This styles the menu heading.
|
|
160
|
+
*/
|
|
161
|
+
#menu .pure-menu-heading {
|
|
162
|
+
font-size: 110%;
|
|
163
|
+
color: #fff;
|
|
164
|
+
margin: 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
The button to open/close the Menu is custom-made and not part of Pure. Here's
|
|
171
|
+
how it works:
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
`.menu-link` represents the responsive menu toggle that shows/hides on
|
|
176
|
+
small screens.
|
|
177
|
+
*/
|
|
178
|
+
.menu-link {
|
|
179
|
+
position: fixed;
|
|
180
|
+
display: block; /* show this only on small screens */
|
|
181
|
+
top: 0;
|
|
182
|
+
left: 0; /* "#menu width" */
|
|
183
|
+
background: #000;
|
|
184
|
+
background: rgba(0,0,0,0.7);
|
|
185
|
+
font-size: 10px; /* change this value to increase/decrease button size */
|
|
186
|
+
z-index: 10;
|
|
187
|
+
width: 3em;
|
|
188
|
+
height: 2em;
|
|
189
|
+
padding: 2.1em 1.6em;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.menu-link:hover,
|
|
193
|
+
.menu-link:focus {
|
|
194
|
+
background: #000;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.menu-link span {
|
|
198
|
+
display: block;
|
|
199
|
+
position: absolute;
|
|
200
|
+
top: 50%;
|
|
201
|
+
left: 50%;
|
|
202
|
+
transform: translate(-50%, -50%);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.menu-link span,
|
|
206
|
+
.menu-link span:before,
|
|
207
|
+
.menu-link span:after {
|
|
208
|
+
background-color: #fff;
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
width: 2em;
|
|
211
|
+
height: 0.2em;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.menu-link span:before,
|
|
215
|
+
.menu-link span:after {
|
|
216
|
+
position: absolute;
|
|
217
|
+
margin-top: -0.6em;
|
|
218
|
+
content: " ";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.menu-link span:after {
|
|
222
|
+
margin-top: 0.6em;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
/* -- Responsive Styles (Media Queries) ------------------------------------- */
|
|
227
|
+
|
|
228
|
+
/*
|
|
229
|
+
Hides the menu at `48em`, but modify this based on your app's needs.
|
|
230
|
+
*/
|
|
231
|
+
@media (min-width: 48em) {
|
|
232
|
+
|
|
233
|
+
.header,
|
|
234
|
+
.content {
|
|
235
|
+
padding-left: 2em;
|
|
236
|
+
padding-right: 2em;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#layout {
|
|
240
|
+
padding-left: var(--menu-width); /* left col width "#menu" */
|
|
241
|
+
left: 0;
|
|
242
|
+
}
|
|
243
|
+
#menu {
|
|
244
|
+
left: var(--menu-width);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.menu-link {
|
|
248
|
+
display: none;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@media (max-width: 48em) {
|
|
253
|
+
/* Only apply this when the window is small. Otherwise, the following
|
|
254
|
+
case results in extra padding on the left:
|
|
255
|
+
* Make the window small.
|
|
256
|
+
* Tap the menu to trigger the active state.
|
|
257
|
+
* Make the window large again.
|
|
258
|
+
*/
|
|
259
|
+
#layout.active {
|
|
260
|
+
position: relative;
|
|
261
|
+
left: var(--menu-width);
|
|
262
|
+
}
|
|
263
|
+
}
|
package/svelte.config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import adapter from '@sveltejs/adapter-auto';
|
|
2
|
+
import preprocess from 'svelte-preprocess';
|
|
3
|
+
|
|
4
|
+
/** @type {import('@sveltejs/kit').Config} */
|
|
5
|
+
const config = {
|
|
6
|
+
// Consult https://github.com/sveltejs/svelte-preprocess
|
|
7
|
+
// for more information about preprocessors
|
|
8
|
+
preprocess: preprocess(),
|
|
9
|
+
|
|
10
|
+
kit: {
|
|
11
|
+
adapter: adapter()
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default config;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
parser: undefined,
|
|
4
|
+
extends: 'standard',
|
|
5
|
+
plugins: [],
|
|
6
|
+
ignorePatterns: [],
|
|
7
|
+
overrides: [],
|
|
8
|
+
settings: {},
|
|
9
|
+
rules: {
|
|
10
|
+
},
|
|
11
|
+
parserOptions: {
|
|
12
|
+
sourceType: 'module'
|
|
13
|
+
},
|
|
14
|
+
env: {
|
|
15
|
+
browser: true,
|
|
16
|
+
es2017: true,
|
|
17
|
+
node: true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
import { goto } from './common.js'
|
|
3
|
+
|
|
4
|
+
test.describe('Image Layout', () => {
|
|
5
|
+
test.beforeEach(async ({ page }) => {
|
|
6
|
+
await goto(page, '/cards')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test('should show all 9 cards', async ({ page }) => {
|
|
10
|
+
const cards = page.locator('.cardlayout-card')
|
|
11
|
+
await expect(cards).toHaveCount(9)
|
|
12
|
+
})
|
|
13
|
+
test('should place each card further from the top than the last', async ({ page }) => {
|
|
14
|
+
const cards = page.locator('.cardlayout-card')
|
|
15
|
+
await expect(cards).toHaveCount(9)
|
|
16
|
+
|
|
17
|
+
let lastoffset = 0
|
|
18
|
+
for (let i = 0; i < 9; i++) {
|
|
19
|
+
const top = (await cards.nth(i).boundingBox()).y
|
|
20
|
+
expect(top).toBeGreaterThanOrEqual(lastoffset)
|
|
21
|
+
lastoffset = top
|
|
22
|
+
}
|
|
23
|
+
expect(lastoffset).toBeGreaterThan(0)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
test.describe('Preserve Order Layout', () => {
|
|
27
|
+
test.beforeEach(async ({ page }) => {
|
|
28
|
+
await goto(page, '/cards/preserve')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('should preserve card order when instructed', async ({ page }) => {
|
|
32
|
+
const cards = page.locator('.cardlayout-card')
|
|
33
|
+
await expect(cards).toHaveCount(9)
|
|
34
|
+
let lastleft = 0
|
|
35
|
+
for (let i = 0; i < 9; i++) {
|
|
36
|
+
const left = (await cards.nth(i).boundingBox()).x
|
|
37
|
+
expect(left).toBeGreaterThanOrEqual(lastleft)
|
|
38
|
+
lastleft = left
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
import { goto } from './common.js'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await goto(page, '/collapsingtable')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('has two rows in tbody', async ({ page }) => {
|
|
9
|
+
await expect(page.locator('text=John Smith')).toHaveCount(1)
|
|
10
|
+
await expect(page.locator('text=Mary Sue')).toHaveCount(1)
|
|
11
|
+
})
|
|
12
|
+
test('hides the numerated columns on a small screen', async ({ page }) => {
|
|
13
|
+
await page.setViewportSize({ width: 400, height: 1024 })
|
|
14
|
+
await expect(page.locator('text="one"')).toHaveCount(0)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('menu toggles when button is clicked', async ({ page }) => {
|
|
18
|
+
await page.setViewportSize({ width: 400, height: 1024 })
|
|
19
|
+
const button = page.locator('th').last()
|
|
20
|
+
const menuitemtwo = page.locator('text="two"')
|
|
21
|
+
await expect(menuitemtwo).toHaveCount(0)
|
|
22
|
+
button.click()
|
|
23
|
+
await expect(menuitemtwo).toHaveCount(1)
|
|
24
|
+
button.click()
|
|
25
|
+
await expect(menuitemtwo).toHaveCount(0)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('able to activate a new row', async ({ page }) => {
|
|
29
|
+
await page.setViewportSize({ width: 400, height: 1024 })
|
|
30
|
+
const button = page.locator('th').last()
|
|
31
|
+
const menuitemtwo = page.locator('text="two"')
|
|
32
|
+
await expect(menuitemtwo).toHaveCount(0)
|
|
33
|
+
button.click()
|
|
34
|
+
await expect(menuitemtwo).toHaveCount(1)
|
|
35
|
+
menuitemtwo.click()
|
|
36
|
+
await expect(page.locator('text="2"')).toHaveCount(3)
|
|
37
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
import { goto } from './common.js'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await goto(page, '/modal')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('modal is active on first render, escape dismisses, hitting enter on the button brings it back, escaping puts focus on the button', async ({ page }) => {
|
|
9
|
+
const button = page.locator('#test-button')
|
|
10
|
+
const nameInput = page.locator('#firstname')
|
|
11
|
+
await expect(nameInput).toHaveCount(1)
|
|
12
|
+
await nameInput.press('Escape')
|
|
13
|
+
await expect(nameInput).toHaveCount(0)
|
|
14
|
+
await button.press('Enter')
|
|
15
|
+
await expect(nameInput).toHaveCount(1)
|
|
16
|
+
await nameInput.press('Escape')
|
|
17
|
+
await expect(page.locator('#test-button')).toBeFocused()
|
|
18
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test'
|
|
2
|
+
import { goto } from './common.js'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await goto(page, '/multiselect')
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('menus open on focus', async ({ page }) => {
|
|
9
|
+
const firstselect = page.locator('[name="test1"]')
|
|
10
|
+
const secondselect = page.locator('[name="test2"]')
|
|
11
|
+
const appleInSecond = page.locator('text="Apple"')
|
|
12
|
+
const bananaInFirst = page.locator('text="banana"')
|
|
13
|
+
await expect(appleInSecond).toHaveCount(0)
|
|
14
|
+
await expect(bananaInFirst).toHaveCount(0)
|
|
15
|
+
firstselect.focus()
|
|
16
|
+
await expect(bananaInFirst).toHaveCount(1)
|
|
17
|
+
secondselect.focus()
|
|
18
|
+
await expect(bananaInFirst).toHaveCount(0)
|
|
19
|
+
await expect(appleInSecond).toHaveCount(1)
|
|
20
|
+
secondselect.press('Escape')
|
|
21
|
+
await expect(appleInSecond).toHaveCount(0)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('able to add and remove items', async ({ page }) => {
|
|
25
|
+
const firstselect = page.locator('[name="test1"]')
|
|
26
|
+
const secondselect = page.locator('[name="test2"]')
|
|
27
|
+
const bananaInFirst = page.locator('text="banana"')
|
|
28
|
+
const orangeInFirst = page.locator('text="orange"')
|
|
29
|
+
const appleInSecond = page.locator('text="Apple"')
|
|
30
|
+
const bananaInSecond = page.locator('text="Banana"')
|
|
31
|
+
const orangeInSecond = page.locator('text="Orange"')
|
|
32
|
+
await expect(bananaInFirst).toHaveCount(0)
|
|
33
|
+
firstselect.focus()
|
|
34
|
+
await expect(bananaInFirst).toHaveCount(1)
|
|
35
|
+
bananaInFirst.click()
|
|
36
|
+
await expect(orangeInFirst).toHaveCount(0)
|
|
37
|
+
await expect(bananaInFirst).toHaveCount(1)
|
|
38
|
+
bananaInFirst.click()
|
|
39
|
+
await expect(bananaInFirst).toHaveCount(0)
|
|
40
|
+
|
|
41
|
+
await expect(appleInSecond).toHaveCount(0)
|
|
42
|
+
await expect(bananaInSecond).toHaveCount(1)
|
|
43
|
+
secondselect.press('Backspace')
|
|
44
|
+
secondselect.press('Escape')
|
|
45
|
+
await expect(bananaInSecond).toHaveCount(0)
|
|
46
|
+
secondselect.press('ArrowLeft')
|
|
47
|
+
await expect(orangeInSecond).toHaveCount(1)
|
|
48
|
+
await expect(orangeInSecond).toHaveClass(/hilited/)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('typing in the input reduces the options in the menu', async ({ page }) => {
|
|
52
|
+
const firstselect = page.locator('[name="test1"]')
|
|
53
|
+
const bananaInFirst = page.locator('text="banana"')
|
|
54
|
+
const orangeInFirst = page.locator('text="orange"')
|
|
55
|
+
firstselect.type('ora')
|
|
56
|
+
await expect(bananaInFirst).toHaveCount(0)
|
|
57
|
+
await expect(orangeInFirst).toHaveCount(1)
|
|
58
|
+
})
|