@txstate-mws/svelte-components 0.0.67 → 1.0.3
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/README.md +39 -4
- package/{dist/ts/actions/a11y.d.ts → actions/buttonify.d.ts} +0 -0
- package/{dist/actions/a11y.js → actions/buttonify.js} +1 -6
- package/{dist/ts/actions → actions}/glue.d.ts +2 -2
- package/{dist/actions → actions}/glue.js +9 -16
- package/actions/index.d.ts +7 -0
- package/actions/index.js +7 -0
- package/actions/offset.d.ts +15 -0
- package/actions/offset.js +35 -0
- package/{dist/ts/actions → actions}/portal.d.ts +0 -0
- package/actions/portal.js +13 -0
- package/{dist/ts/actions → actions}/resize.d.ts +6 -2
- package/actions/resize.js +45 -0
- package/{dist/ts/actions → actions}/sticky.d.ts +2 -2
- package/{dist/actions → actions}/sticky.js +10 -18
- package/{dist/ts/actions → actions}/stickyfixed.d.ts +7 -7
- package/{dist/actions → actions}/stickyfixed.js +19 -28
- package/{dist/components → components}/CollapsingTable.svelte +13 -14
- package/components/CollapsingTable.svelte.d.ts +59 -0
- package/{dist/ts/components → components}/ConditionalWrapper.svelte +6 -7
- package/components/ConditionalWrapper.svelte.d.ts +23 -0
- package/{dist/components → components}/FocusLock.svelte +21 -19
- package/components/FocusLock.svelte.d.ts +26 -0
- package/components/Modal.svelte +53 -0
- package/components/Modal.svelte.d.ts +27 -0
- package/{dist/components → components}/PopupMenu.svelte +28 -30
- package/components/PopupMenu.svelte.d.ts +44 -0
- package/{dist/ts/components → components}/ScreenReaderOnly.svelte +4 -5
- package/components/ScreenReaderOnly.svelte.d.ts +20 -0
- package/{dist/ts/components → components}/index.d.ts +0 -0
- package/components/index.js +6 -0
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/package.json +47 -68
- package/{dist/ts/types → types}/CollapsingTable.d.ts +0 -0
- package/{dist/ts/tests/Actions/Actions.stories.d.ts → types/CollapsingTable.js} +0 -0
- package/{dist/ts/types → types}/PopupMenu.d.ts +0 -0
- package/{dist/ts/tests/CollapsingTable/CollapsingTable.stories.d.ts → types/PopupMenu.js} +0 -0
- package/types/index.d.ts +2 -0
- package/types/index.js +2 -0
- package/{dist/ts/lib → util}/bodyoffset.d.ts +2 -1
- package/{dist/lib → util}/bodyoffset.js +10 -14
- package/util/index.d.ts +3 -0
- package/util/index.js +3 -0
- package/{dist/ts/lib → util}/repositioned.d.ts +1 -2
- package/{dist/lib → util}/repositioned.js +14 -24
- package/{dist/ts/lib → util}/util.d.ts +0 -0
- package/util/util.js +10 -0
- package/LICENSE +0 -21
- package/dist/actions/a11y.js.map +0 -1
- package/dist/actions/glue.js.map +0 -1
- package/dist/actions/index.js +0 -20
- package/dist/actions/index.js.map +0 -1
- package/dist/actions/offset.js +0 -35
- package/dist/actions/offset.js.map +0 -1
- package/dist/actions/portal.js +0 -23
- package/dist/actions/portal.js.map +0 -1
- package/dist/actions/resize.js +0 -48
- package/dist/actions/resize.js.map +0 -1
- package/dist/actions/sticky.js.map +0 -1
- package/dist/actions/stickyfixed.js.map +0 -1
- package/dist/components/ConditionalWrapper.svelte +0 -38
- package/dist/components/Modal.svelte +0 -44
- package/dist/components/ScreenReaderOnly.svelte +0 -26
- package/dist/components/index.js +0 -19
- package/dist/components/index.js.map +0 -1
- package/dist/index.js +0 -17
- package/dist/index.js.map +0 -1
- package/dist/lib/bodyoffset.js.map +0 -1
- package/dist/lib/deepstore.js +0 -80
- package/dist/lib/deepstore.js.map +0 -1
- package/dist/lib/derivedstore.js +0 -53
- package/dist/lib/derivedstore.js.map +0 -1
- package/dist/lib/index.js +0 -20
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/repositioned.js.map +0 -1
- package/dist/lib/safestore.js +0 -16
- package/dist/lib/safestore.js.map +0 -1
- package/dist/lib/substore.js +0 -46
- package/dist/lib/substore.js.map +0 -1
- package/dist/lib/util.js +0 -16
- package/dist/lib/util.js.map +0 -1
- package/dist/ts/actions/index.d.ts +0 -7
- package/dist/ts/actions/offset.d.ts +0 -15
- package/dist/ts/components/CollapsingTable.svelte +0 -147
- package/dist/ts/components/FocusLock.svelte +0 -100
- package/dist/ts/components/Modal.svelte +0 -45
- package/dist/ts/components/PopupMenu.svelte +0 -278
- package/dist/ts/index.d.ts +0 -4
- package/dist/ts/lib/deepstore.d.ts +0 -42
- package/dist/ts/lib/derivedstore.d.ts +0 -16
- package/dist/ts/lib/index.d.ts +0 -7
- package/dist/ts/lib/safestore.d.ts +0 -4
- package/dist/ts/lib/substore.d.ts +0 -23
- package/dist/ts/tests/Actions/Offset.svelte +0 -34
- package/dist/ts/tests/Actions/Resize.svelte +0 -31
- package/dist/ts/tests/Actions/Sticky.svelte +0 -65
- package/dist/ts/tests/CollapsingTable/CollapsingTable.test.d.ts +0 -1
- package/dist/ts/tests/CollapsingTable/CollapsingTableTest.svelte +0 -36
- package/dist/ts/tests/Modal/Modal.stories.d.ts +0 -1
- package/dist/ts/tests/Modal/Modal.test.d.ts +0 -1
- package/dist/ts/tests/Modal/ModalTest.svelte +0 -58
- package/dist/ts/tests/PopupMenu/PopupMenu.stories.d.ts +0 -1
- package/dist/ts/tests/PopupMenu/PopupMenu.test.d.ts +0 -1
- package/dist/ts/tests/PopupMenu/PopupMenuBody.svelte +0 -34
- package/dist/ts/tests/PopupMenu/PopupMenuButtonIsParent.svelte +0 -36
- package/dist/ts/tests/PopupMenu/PopupMenuComplex.svelte +0 -34
- package/dist/ts/tests/PopupMenu/PopupMenuSimple.svelte +0 -30
- package/dist/ts/tests/stores/deepstore.test.d.ts +0 -1
- package/dist/ts/types/index.d.ts +0 -2
- package/dist/types/CollapsingTable.js +0 -3
- package/dist/types/CollapsingTable.js.map +0 -1
- package/dist/types/PopupMenu.js +0 -3
- package/dist/types/PopupMenu.js.map +0 -1
- package/dist/types/index.js +0 -15
- package/dist/types/index.js.map +0 -1
- package/docs/CollapsingTable.md +0 -80
- package/docs/actions.md +0 -10
- package/esm/index.js +0 -1
- package/esm/package.json +0 -3
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
export let lockbackdrop = false
|
|
3
|
-
export let hidefocus = true
|
|
4
|
-
export let hidefocuslabel: string|undefined = undefined
|
|
5
|
-
export let returnfocusto: HTMLElement|undefined = undefined
|
|
6
|
-
export let initialfocus: string|undefined = undefined
|
|
7
|
-
import FocusLock from './FocusLock.svelte'
|
|
8
|
-
import { createEventDispatcher, onMount } from 'svelte'
|
|
9
|
-
import { portal } from '../actions';
|
|
10
|
-
const dispatch = createEventDispatcher()
|
|
11
|
-
const endmodal = () => {
|
|
12
|
-
dispatch('dismiss')
|
|
13
|
-
}
|
|
14
|
-
onMount(() => {
|
|
15
|
-
document.body.style.overflow = 'hidden'
|
|
16
|
-
return () => {
|
|
17
|
-
document.body.style.overflow = ''
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<div use:portal class="modal-backdrop" on:click={() => lockbackdrop || endmodal()}>
|
|
23
|
-
<FocusLock class="modal-container" escapable={!lockbackdrop} on:escape={endmodal} {hidefocus} {hidefocuslabel} {returnfocusto} {initialfocus} on:escape={() => lockbackdrop || endmodal()}>
|
|
24
|
-
<slot></slot>
|
|
25
|
-
</FocusLock>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<style>
|
|
29
|
-
.modal-backdrop {
|
|
30
|
-
position: fixed;
|
|
31
|
-
top: 0;
|
|
32
|
-
left: 0;
|
|
33
|
-
width: 100%;
|
|
34
|
-
height: 100%;
|
|
35
|
-
background-color: var(--modal-bg, rgba(0, 0, 0, 0.7));
|
|
36
|
-
overflow: auto;
|
|
37
|
-
z-index: 100;
|
|
38
|
-
}
|
|
39
|
-
.modal-backdrop :global(.modal-container) {
|
|
40
|
-
position: absolute;
|
|
41
|
-
left: 50%;
|
|
42
|
-
top: 50%;
|
|
43
|
-
transform: translate(-50%, -50%);
|
|
44
|
-
}
|
|
45
|
-
</style>
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { GlueAlignOpts, GlueAlignStore } from '../actions'
|
|
3
|
-
import { glue, portal } from '../actions'
|
|
4
|
-
import { createEventDispatcher, onDestroy, tick } from 'svelte'
|
|
5
|
-
import { randomid } from 'txstate-utils'
|
|
6
|
-
import type { PopupMenuItem } from '../types'
|
|
7
|
-
import { DeepStore, SettableSubject } from '../lib'
|
|
8
|
-
import ScreenReaderOnly from './ScreenReaderOnly.svelte'
|
|
9
|
-
const dispatch = createEventDispatcher()
|
|
10
|
-
|
|
11
|
-
export let menushown = false
|
|
12
|
-
export let menuContainerClass = ''
|
|
13
|
-
export let menuClass = ''
|
|
14
|
-
export let menuItemClass = ''
|
|
15
|
-
export let menuItemHilitedClass = ''
|
|
16
|
-
export let menuItemSelectedClass = ''
|
|
17
|
-
export let items: PopupMenuItem[] = []
|
|
18
|
-
export let buttonelement: HTMLElement
|
|
19
|
-
export let align: GlueAlignOpts = 'auto'
|
|
20
|
-
export let cover = false
|
|
21
|
-
export let showSelected = true
|
|
22
|
-
export let width:string|undefined = undefined
|
|
23
|
-
export let computedalign: SettableSubject<GlueAlignStore> = new DeepStore<GlueAlignStore>({ valign: 'bottom', halign: 'left' })
|
|
24
|
-
export let usePortal: HTMLElement|true|undefined = undefined
|
|
25
|
-
export let emptyText: string|undefined = undefined
|
|
26
|
-
export let hilited: number|undefined = undefined
|
|
27
|
-
export let selected: PopupMenuItem|undefined = undefined
|
|
28
|
-
|
|
29
|
-
let menuelement: HTMLElement|undefined
|
|
30
|
-
let itemelements: HTMLElement[] = []
|
|
31
|
-
const menuid = randomid()
|
|
32
|
-
let firstactive = 0
|
|
33
|
-
let lastactive = items.length - 1
|
|
34
|
-
|
|
35
|
-
function hiddenItem (item: PopupMenuItem) {
|
|
36
|
-
return !!item && !showSelected && item.value === selected?.value
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function reactToItems (..._: any[]) {
|
|
40
|
-
firstactive = items.findIndex(itm => !itm.disabled && !hiddenItem(itm))
|
|
41
|
-
lastactive = items.length - [...items].reverse().findIndex(itm => !itm.disabled && !hiddenItem(itm)) - 1
|
|
42
|
-
if (hilited && items[hilited]?.disabled) hilited = firstactive
|
|
43
|
-
}
|
|
44
|
-
$: reactToItems(items, selected)
|
|
45
|
-
|
|
46
|
-
async function reactToMenuShown (_: boolean) {
|
|
47
|
-
if (!buttonelement) {
|
|
48
|
-
hilited = undefined
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
await tick()
|
|
52
|
-
if (!menushown) {
|
|
53
|
-
hilited = undefined
|
|
54
|
-
buttonelement.removeAttribute('aria-controls')
|
|
55
|
-
buttonelement.setAttribute('aria-expanded', 'false')
|
|
56
|
-
} else {
|
|
57
|
-
buttonelement.setAttribute('aria-controls', menuid)
|
|
58
|
-
buttonelement.setAttribute('aria-expanded', 'true')
|
|
59
|
-
}
|
|
60
|
-
buttonelement.focus()
|
|
61
|
-
}
|
|
62
|
-
$: reactToMenuShown(menushown)
|
|
63
|
-
|
|
64
|
-
function move (idx: number) {
|
|
65
|
-
if (!menushown) return
|
|
66
|
-
if (items[idx]?.disabled) return
|
|
67
|
-
hilited = Math.max(firstactive, Math.min(lastactive, idx))
|
|
68
|
-
itemelements[hilited].scrollIntoView({ block: 'center' })
|
|
69
|
-
buttonelement.setAttribute('aria-activedescendant', `${menuid}-${hilited}`)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function onkeydown (e: KeyboardEvent) {
|
|
73
|
-
if (e.key === 'ArrowDown') {
|
|
74
|
-
e.preventDefault()
|
|
75
|
-
if (menushown) {
|
|
76
|
-
let i = (hilited ?? firstactive - 1) + 1
|
|
77
|
-
while(items[i]?.disabled || hiddenItem(items[i])) i++
|
|
78
|
-
move(i)
|
|
79
|
-
} else {
|
|
80
|
-
menushown = true
|
|
81
|
-
move(firstactive)
|
|
82
|
-
}
|
|
83
|
-
} else if (e.key === 'ArrowUp') {
|
|
84
|
-
e.preventDefault()
|
|
85
|
-
if (menushown) {
|
|
86
|
-
let i = (hilited ?? lastactive + 1) - 1
|
|
87
|
-
while(items[i]?.disabled || hiddenItem(items[i])) i--
|
|
88
|
-
move(i)
|
|
89
|
-
} else {
|
|
90
|
-
menushown = true
|
|
91
|
-
move(lastactive)
|
|
92
|
-
}
|
|
93
|
-
} else if (e.key === 'Enter') {
|
|
94
|
-
e.preventDefault()
|
|
95
|
-
if (menushown) {
|
|
96
|
-
menushown = false
|
|
97
|
-
if (typeof hilited !== 'undefined') {
|
|
98
|
-
selected = items[hilited]
|
|
99
|
-
dispatch('change', items[hilited].value)
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
menushown = true
|
|
103
|
-
move(firstactive)
|
|
104
|
-
}
|
|
105
|
-
} else if (e.key === ' ') {
|
|
106
|
-
// buttonelement might be a text input if this popup is searchable,
|
|
107
|
-
// so we want to allow spaces to be entered without changing the menu situation
|
|
108
|
-
if (menushown) {
|
|
109
|
-
if (typeof hilited !== 'undefined') {
|
|
110
|
-
e.preventDefault()
|
|
111
|
-
menushown = false
|
|
112
|
-
selected = items[hilited]
|
|
113
|
-
dispatch('change', items[hilited].value)
|
|
114
|
-
} else {
|
|
115
|
-
if (buttonelement.tagName !== 'INPUT') {
|
|
116
|
-
e.preventDefault()
|
|
117
|
-
menushown = false
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
if (buttonelement.tagName !== 'INPUT') {
|
|
122
|
-
e.preventDefault()
|
|
123
|
-
menushown = true
|
|
124
|
-
move(firstactive)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
} else if (menushown && e.key === 'Escape') {
|
|
128
|
-
e.preventDefault()
|
|
129
|
-
e.stopPropagation()
|
|
130
|
-
menushown = false
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function onbuttonclick (e: MouseEvent) {
|
|
135
|
-
e.preventDefault()
|
|
136
|
-
menushown = !menushown
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function onblur (e: FocusEvent) {
|
|
140
|
-
// tabindex=-1 on our menu elements means e.relatedTarget will be set
|
|
141
|
-
if (!(e.relatedTarget instanceof HTMLElement && menuelement?.contains(e.relatedTarget))) menushown = false
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function cleanup (element: HTMLElement) {
|
|
145
|
-
if (element) {
|
|
146
|
-
element.removeEventListener('click', onbuttonclick)
|
|
147
|
-
element.removeEventListener('keydown', onkeydown)
|
|
148
|
-
element.removeEventListener('blur', onblur)
|
|
149
|
-
element.removeAttribute('aria-haspopup')
|
|
150
|
-
element.removeAttribute('aria-expanded')
|
|
151
|
-
element.removeAttribute('aria-controls')
|
|
152
|
-
element.removeAttribute('aria-activedescendant')
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
onDestroy(() => cleanup(buttonelement))
|
|
157
|
-
|
|
158
|
-
// if buttonelement changes we need to handle listeners and aria
|
|
159
|
-
let lastbuttonelement: HTMLElement
|
|
160
|
-
function reactToButtonElement (buttonelement: HTMLElement) {
|
|
161
|
-
cleanup(lastbuttonelement)
|
|
162
|
-
lastbuttonelement = buttonelement
|
|
163
|
-
if (buttonelement) {
|
|
164
|
-
buttonelement.setAttribute('aria-haspopup', 'listbox')
|
|
165
|
-
buttonelement.addEventListener('click', onbuttonclick)
|
|
166
|
-
buttonelement.addEventListener('keydown', onkeydown)
|
|
167
|
-
buttonelement.addEventListener('blur', onblur)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
$: reactToButtonElement(buttonelement)
|
|
171
|
-
|
|
172
|
-
const onclick = (item: PopupMenuItem) => (e: MouseEvent) => {
|
|
173
|
-
e.stopPropagation()
|
|
174
|
-
e.preventDefault()
|
|
175
|
-
if (item.disabled) return
|
|
176
|
-
menushown = false
|
|
177
|
-
selected = item
|
|
178
|
-
dispatch('change', item.value)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
$: hasSelected = showSelected && !!items.find(itm => itm.value === selected?.value)
|
|
182
|
-
</script>
|
|
183
|
-
|
|
184
|
-
{#if menushown}
|
|
185
|
-
<div use:portal={usePortal === true ? document.body : (usePortal || null)} use:glue={{ target: buttonelement, align, cover, store: computedalign }} class={menuContainerClass}>
|
|
186
|
-
<ul bind:this={menuelement} id={menuid} role='listbox' style={width ? `width: ${width}` : ''} class={menuClass} class:hasSelected class:defaultmenu={!menuClass && !menuContainerClass} on:keydown={onkeydown}>
|
|
187
|
-
{#each items as item, i (item.value)}
|
|
188
|
-
{#if showSelected || !selected || item.value !== selected.value}
|
|
189
|
-
<li
|
|
190
|
-
id={`${menuid}-${i}`}
|
|
191
|
-
bind:this={itemelements[i]}
|
|
192
|
-
class={`${menuItemClass} ${i === hilited ? menuItemHilitedClass || '' : ''} ${selected && selected.value === item.value ? menuItemSelectedClass || '' : ''}`}
|
|
193
|
-
class:disabled={!!item.disabled}
|
|
194
|
-
class:hilited={!menuItemHilitedClass && i === hilited}
|
|
195
|
-
class:selected={showSelected && !menuItemSelectedClass && selected && selected.value === item.value}
|
|
196
|
-
on:click={onclick(item)}
|
|
197
|
-
role="option"
|
|
198
|
-
tabindex=-1
|
|
199
|
-
aria-disabled={item.disabled}
|
|
200
|
-
><slot {item} label={item.label || item.value} hilited={i === hilited} selected={selected && selected.value === item.value}>{item.label || item.value}</slot></li>
|
|
201
|
-
{/if}
|
|
202
|
-
{/each}
|
|
203
|
-
{#if items.length === 0}
|
|
204
|
-
<li role="option" class={`${menuItemClass} disabled`} aria-live="assertive">
|
|
205
|
-
<slot name="noresults">
|
|
206
|
-
{#if !emptyText}
|
|
207
|
-
<span aria-hidden="true">{'¯\\_(ツ)_/¯'}</span><ScreenReaderOnly>{emptyText || 'empty popup menu'}</ScreenReaderOnly>
|
|
208
|
-
{:else}
|
|
209
|
-
{emptyText}
|
|
210
|
-
{/if}
|
|
211
|
-
</slot>
|
|
212
|
-
</li>
|
|
213
|
-
{/if}
|
|
214
|
-
</ul>
|
|
215
|
-
</div>
|
|
216
|
-
{/if}
|
|
217
|
-
|
|
218
|
-
<style>
|
|
219
|
-
div {
|
|
220
|
-
position: absolute !important;
|
|
221
|
-
}
|
|
222
|
-
ul {
|
|
223
|
-
list-style: none;
|
|
224
|
-
}
|
|
225
|
-
ul.defaultmenu {
|
|
226
|
-
margin: 0;
|
|
227
|
-
padding: 0.4em;
|
|
228
|
-
background: white;
|
|
229
|
-
border: 1px solid slategray;
|
|
230
|
-
border-radius: 3px;
|
|
231
|
-
min-width: 10em;
|
|
232
|
-
max-height: 20em;
|
|
233
|
-
overflow-y: auto;
|
|
234
|
-
}
|
|
235
|
-
ul.defaultmenu li.disabled {
|
|
236
|
-
color: rgba(0,0,0,0.6);
|
|
237
|
-
}
|
|
238
|
-
ul.defaultmenu::-webkit-scrollbar {
|
|
239
|
-
appearance: none;
|
|
240
|
-
width: 7px;
|
|
241
|
-
}
|
|
242
|
-
ul.defaultmenu::-webkit-scrollbar-thumb {
|
|
243
|
-
border-radius: 4px;
|
|
244
|
-
background-color: rgba(0,0,0,.5);
|
|
245
|
-
box-shadow: 0 0 1px rgba(255,255,255,.5);
|
|
246
|
-
}
|
|
247
|
-
ul.defaultmenu::-webkit-scrollbar-track {
|
|
248
|
-
background-color: rgba(0,0,0,.1);
|
|
249
|
-
}
|
|
250
|
-
li {
|
|
251
|
-
cursor: pointer;
|
|
252
|
-
}
|
|
253
|
-
li.hilited {
|
|
254
|
-
background: lightblue;
|
|
255
|
-
}
|
|
256
|
-
li.disabled {
|
|
257
|
-
cursor: auto;
|
|
258
|
-
}
|
|
259
|
-
li.selected {
|
|
260
|
-
position: relative;
|
|
261
|
-
}
|
|
262
|
-
ul.hasSelected li {
|
|
263
|
-
padding-left: 1.4em;
|
|
264
|
-
}
|
|
265
|
-
li.selected:after {
|
|
266
|
-
content: ' ';
|
|
267
|
-
position: absolute;
|
|
268
|
-
left: 0.5em;
|
|
269
|
-
top: calc(50% - 0.11em);
|
|
270
|
-
transform: translateY(-50%) rotate(38deg);
|
|
271
|
-
display: block;
|
|
272
|
-
height: 0.786em;
|
|
273
|
-
width: 0.4286em;
|
|
274
|
-
border-bottom: 0.2em solid;
|
|
275
|
-
border-right: 0.2em solid;
|
|
276
|
-
box-sizing: border-box;
|
|
277
|
-
}
|
|
278
|
-
</style>
|
package/dist/ts/index.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Writable } from 'svelte/store';
|
|
2
|
-
export interface UsableSubject<T> {
|
|
3
|
-
subscribe: (observer: (value: T) => void) => () => void;
|
|
4
|
-
}
|
|
5
|
-
export interface WritableSubject<T> extends UsableSubject<T> {
|
|
6
|
-
update: (updater: (value: T) => T) => void;
|
|
7
|
-
}
|
|
8
|
-
export interface SettableSubject<T> extends WritableSubject<T> {
|
|
9
|
-
set: (value: T) => void;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* An alternative to svelte's "writable" that also checks deep equality (fast-deep-equal) before
|
|
13
|
-
* notifying subscribers. A writable will notify subscribers every time it is
|
|
14
|
-
* updated, even if nothing has changed.
|
|
15
|
-
*
|
|
16
|
-
* Note that this strategy is weak against mutable state updates:
|
|
17
|
-
* store.update(v => { v.someprop = 'newvalue'; return v })
|
|
18
|
-
*
|
|
19
|
-
* This line would NOT notify subscribers because the state will be compared against
|
|
20
|
-
* itself and always found to be equal. If you are making updates in a mutable fashion,
|
|
21
|
-
* use a SafeStore instead.
|
|
22
|
-
*
|
|
23
|
-
* You can also pass in a writable as your initial state. This will subscribe to the writable
|
|
24
|
-
* but add the deep equality checks.
|
|
25
|
-
*
|
|
26
|
-
* If you pass in a writable while in a component, be sure to call .complete() in your
|
|
27
|
-
* onDestroy to free memory.
|
|
28
|
-
*/
|
|
29
|
-
export declare class DeepStore<T> implements Writable<T> {
|
|
30
|
-
protected value: T;
|
|
31
|
-
protected subscribers: Map<string, (s: T) => void>;
|
|
32
|
-
protected cleanups: (() => void)[];
|
|
33
|
-
private valueStore?;
|
|
34
|
-
private pause;
|
|
35
|
-
constructor(value: T | Writable<T>);
|
|
36
|
-
clone(value: T): T;
|
|
37
|
-
set(value: T): void;
|
|
38
|
-
update(updater: (value: T) => T): void;
|
|
39
|
-
subscribe(run: (s: T) => any): () => void;
|
|
40
|
-
protected cleanup(fn: () => void): void;
|
|
41
|
-
complete(): void;
|
|
42
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { DeepStore, UsableSubject } from './deepstore';
|
|
2
|
-
/**
|
|
3
|
-
* Watch one or more parent stores for changes. Each time, run a function to derive
|
|
4
|
-
* a new state from the parent state(s). Subscribers will only be notified if the
|
|
5
|
-
* derived state has changed (uses fast-deep-equal).
|
|
6
|
-
*
|
|
7
|
-
* If only one parent store, it's possible to use a dot-prop string as the getter.
|
|
8
|
-
*
|
|
9
|
-
* If you create one of these in a component, be sure to call .complete() in onDestroy
|
|
10
|
-
* to free up memory.
|
|
11
|
-
*/
|
|
12
|
-
export declare class DerivedStore<DerivedType, ParentType = any> extends DeepStore<DerivedType> {
|
|
13
|
-
constructor(store: UsableSubject<ParentType>, getter: (value: ParentType) => DerivedType);
|
|
14
|
-
constructor(store: UsableSubject<ParentType>, getter: string);
|
|
15
|
-
constructor(store: UsableSubject<any>[], getter: (value: any[]) => DerivedType);
|
|
16
|
-
}
|
package/dist/ts/lib/index.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { DeepStore, WritableSubject } from './deepstore';
|
|
2
|
-
/**
|
|
3
|
-
* Create a store that represents a part of a larger store. Updates to the parent store will propagate
|
|
4
|
-
* down to the SubStore as appropriate, and updates to the SubStore will propagate
|
|
5
|
-
* back up to the parent store. This requires both a getter and setter function to handle each
|
|
6
|
-
* direction. The setter is given the new SubStore state and the existing parent store state and
|
|
7
|
-
* should return a new state for the parent store.
|
|
8
|
-
*
|
|
9
|
-
* Alternatively, a dot-prop string can be provided and both the getter and setter will be automatically
|
|
10
|
-
* generated. For example, a parent store containing state { deep: { value: 'here' }, hello: 'world' }
|
|
11
|
-
* could be used with the getter string "deep.value". The SubStore's initial state would be "here", and
|
|
12
|
-
* updating it to "there" would update the parent store state to { deep: { value: 'there' }, hello: 'world' }
|
|
13
|
-
*
|
|
14
|
-
* If you create one of these in a component, be sure to call .complete() in onDestroy to free up memory.
|
|
15
|
-
*/
|
|
16
|
-
export declare class SubStore<SubType, ParentType = any> extends DeepStore<SubType> {
|
|
17
|
-
protected parentStore: WritableSubject<ParentType>;
|
|
18
|
-
protected setter: (value: SubType, state: ParentType) => ParentType;
|
|
19
|
-
constructor(store: WritableSubject<ParentType>, getter: string);
|
|
20
|
-
constructor(store: WritableSubject<ParentType>, getter: (value: ParentType) => SubType, setter: (value: SubType, state: ParentType) => ParentType);
|
|
21
|
-
set(value: SubType): void;
|
|
22
|
-
clone(state: SubType): any;
|
|
23
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { writable } from 'svelte/store'
|
|
3
|
-
import type { ElementOffsets } from '../../lib/repositioned'
|
|
4
|
-
import { offset } from '../../actions/offset'
|
|
5
|
-
export let debounce = false
|
|
6
|
-
let myoffset = writable<ElementOffsets>({})
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<div class='resizable'>resize this div</div>
|
|
10
|
-
<div use:offset={{ store: myoffset, debounce }} class="offset">
|
|
11
|
-
This div's offset...<br>
|
|
12
|
-
Left: {$myoffset.left}<br>
|
|
13
|
-
Top: {$myoffset.top}<br>
|
|
14
|
-
Right: {$myoffset.right}<br>
|
|
15
|
-
Bottom: {$myoffset.bottom}
|
|
16
|
-
</div>
|
|
17
|
-
debounce: {debounce}
|
|
18
|
-
|
|
19
|
-
<style>
|
|
20
|
-
div {
|
|
21
|
-
max-width: 300px;
|
|
22
|
-
}
|
|
23
|
-
.resizable {
|
|
24
|
-
resize: both;
|
|
25
|
-
overflow: auto;
|
|
26
|
-
min-height: 100px;
|
|
27
|
-
background: lightblue;
|
|
28
|
-
border: 1px solid black;
|
|
29
|
-
}
|
|
30
|
-
.offset {
|
|
31
|
-
border: 1px solid blue;
|
|
32
|
-
text-align: center;
|
|
33
|
-
}
|
|
34
|
-
</style>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { writable } from 'svelte/store'
|
|
3
|
-
import type { ElementSize } from '../../actions/resize'
|
|
4
|
-
import { resize } from '../../actions/resize'
|
|
5
|
-
export let debounce = false
|
|
6
|
-
let mysize = writable<ElementSize>({})
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<div use:resize={{ store: mysize, debounce }} class='resizable'>resize this div</div>
|
|
10
|
-
<div class="display">
|
|
11
|
-
Above div's size...<br>
|
|
12
|
-
Width: {$mysize.offsetWidth}<br>
|
|
13
|
-
Height: {$mysize.offsetHeight}
|
|
14
|
-
</div>
|
|
15
|
-
debounce: {debounce}
|
|
16
|
-
|
|
17
|
-
<style>
|
|
18
|
-
div {
|
|
19
|
-
max-width: 300px;
|
|
20
|
-
}
|
|
21
|
-
.resizable {
|
|
22
|
-
resize: both;
|
|
23
|
-
overflow: auto;
|
|
24
|
-
min-height: 100px;
|
|
25
|
-
background: lightblue;
|
|
26
|
-
border: 1px solid black;
|
|
27
|
-
}
|
|
28
|
-
.display {
|
|
29
|
-
text-align: center;
|
|
30
|
-
}
|
|
31
|
-
</style>
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { sticky, stickyfixed } from '../../actions'
|
|
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>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import CollapsingTable from '../../components/CollapsingTable.svelte'
|
|
3
|
-
import { CollapsingTableColumn } from '../../types'
|
|
4
|
-
export let stickyheader = false
|
|
5
|
-
const items = [
|
|
6
|
-
{ id: 1, name: 'John Smith', age: 42, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 },
|
|
7
|
-
{ id: 3, name: 'Mary Sue', age: 23, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 },
|
|
8
|
-
{ id: 6, name: 'Billy Bob', age: 12, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 }
|
|
9
|
-
]
|
|
10
|
-
const config: CollapsingTableColumn[] = [
|
|
11
|
-
{ key: 'id' },
|
|
12
|
-
{ key: 'name', neverhide: true },
|
|
13
|
-
{ key: 'age' },
|
|
14
|
-
{ key: 'one' },
|
|
15
|
-
{ key: 'two' },
|
|
16
|
-
{ key: 'three' },
|
|
17
|
-
{ key: 'four', bodyCellClass: 'four' },
|
|
18
|
-
{ key: 'five' },
|
|
19
|
-
{ key: 'six' }
|
|
20
|
-
]
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<div class="before"></div>
|
|
24
|
-
<CollapsingTable {items} {config} {stickyheader} let:key let:value>
|
|
25
|
-
{#if key === 'five'}
|
|
26
|
-
<span class='test'>{value}</span>
|
|
27
|
-
{:else}
|
|
28
|
-
{value}
|
|
29
|
-
{/if}
|
|
30
|
-
</CollapsingTable>
|
|
31
|
-
<div class="after"></div>
|
|
32
|
-
|
|
33
|
-
<style>
|
|
34
|
-
.before { height: 40px; }
|
|
35
|
-
.after { height: 1000px; }
|
|
36
|
-
</style>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|