@rokkit/core 1.0.0-next.11
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/LICENSE +21 -0
- package/README.md +1 -0
- package/package.json +59 -0
- package/src/Accordion.svelte +80 -0
- package/src/Alerts.svelte +39 -0
- package/src/DropDown.svelte +79 -0
- package/src/DropSearch.svelte +67 -0
- package/src/Icon.svelte +15 -0
- package/src/List-Discard.svelte +48 -0
- package/src/List.svelte +65 -0
- package/src/ListActions.svelte +35 -0
- package/src/NavTabs.svelte +0 -0
- package/src/NestedList.svelte +87 -0
- package/src/Overlay.svelte +4 -0
- package/src/PageNavigator.svelte +94 -0
- package/src/ResponsiveGrid.svelte +73 -0
- package/src/Scrollable.svelte +8 -0
- package/src/Searchable.svelte +19 -0
- package/src/Sidebar.svelte +5 -0
- package/src/Slider.svelte +17 -0
- package/src/SpinList.svelte +48 -0
- package/src/SplitPane.svelte +109 -0
- package/src/SplitView.svelte +44 -0
- package/src/Splitter.svelte +95 -0
- package/src/TabItem.svelte +27 -0
- package/src/TabItems.svelte +34 -0
- package/src/Tabs.svelte +31 -0
- package/src/Tree.svelte +19 -0
- package/src/actions/dismissable.js +24 -0
- package/src/actions/fillable.js +114 -0
- package/src/actions/hierarchy.js +189 -0
- package/src/actions/index.js +7 -0
- package/src/actions/navigable.js +42 -0
- package/src/actions/navigator.js +179 -0
- package/src/actions/pannable.js +50 -0
- package/src/actions/swipeable.js +56 -0
- package/src/actions/themeable.js +23 -0
- package/src/constants.js +149 -0
- package/src/index.js +27 -0
- package/src/items/Collapsible.svelte +51 -0
- package/src/items/Connector.svelte +26 -0
- package/src/items/Link.svelte +17 -0
- package/src/items/Node.svelte +52 -0
- package/src/items/Pill.svelte +19 -0
- package/src/items/Separator.svelte +1 -0
- package/src/items/Summary.svelte +27 -0
- package/src/items/Text.svelte +21 -0
- package/src/items/index.js +8 -0
- package/src/list.js +14 -0
- package/src/mocks/Custom.svelte +7 -0
- package/src/mocks/index.js +10 -0
- package/src/stores/alerts.js +3 -0
- package/src/stores/index.js +6 -0
- package/src/stores/persist.js +63 -0
- package/src/stores/theme.js +34 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
import { defaultFields, defaultStateIcons } from './constants'
|
|
4
|
+
import Icon from './Icon.svelte'
|
|
5
|
+
|
|
6
|
+
const dispatch = createEventDispatcher()
|
|
7
|
+
|
|
8
|
+
let className = ''
|
|
9
|
+
export { className as class }
|
|
10
|
+
|
|
11
|
+
export let items = []
|
|
12
|
+
export let value = items[0]
|
|
13
|
+
export let fields = {}
|
|
14
|
+
export let numbers = false
|
|
15
|
+
|
|
16
|
+
const navigate = defaultStateIcons.navigate
|
|
17
|
+
|
|
18
|
+
let previous
|
|
19
|
+
let next
|
|
20
|
+
|
|
21
|
+
function updateOnChange(value, items) {
|
|
22
|
+
let index = items.findIndex((x) => x == value)
|
|
23
|
+
if (index == -1) value = items[0]
|
|
24
|
+
// } else {
|
|
25
|
+
previous = index > 0 ? items[index - 1] : null
|
|
26
|
+
next = index < items.length - 1 ? items[index + 1] : null
|
|
27
|
+
// }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function handleClick(item) {
|
|
31
|
+
if (item) {
|
|
32
|
+
value = item
|
|
33
|
+
dispatch('select', value)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$: fields = { ...defaultFields, ...fields }
|
|
38
|
+
$: updateOnChange(value, items)
|
|
39
|
+
|
|
40
|
+
// $: value = items.findIndex((x) => x == value) ? value : items[0]
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
44
|
+
<nav-pages class="grid grid-cols-3 select-none {className}" tabindex="0">
|
|
45
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
46
|
+
<span
|
|
47
|
+
class="flex items-center cursor-pointer"
|
|
48
|
+
on:click={() => handleClick(previous)}
|
|
49
|
+
tabIndex={previous ? 0 : -1}
|
|
50
|
+
>
|
|
51
|
+
{#if previous}
|
|
52
|
+
<Icon name={navigate.left} />
|
|
53
|
+
<p>
|
|
54
|
+
{#if previous[fields.text]}
|
|
55
|
+
{previous[fields.text]}
|
|
56
|
+
{/if}
|
|
57
|
+
</p>
|
|
58
|
+
{/if}
|
|
59
|
+
</span>
|
|
60
|
+
<span class="flex items-center justify-center">
|
|
61
|
+
<block class="flex items-center">
|
|
62
|
+
{#each items as item, index}
|
|
63
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
64
|
+
<pg
|
|
65
|
+
class:numbers
|
|
66
|
+
class:dot={!numbers}
|
|
67
|
+
class:is-selected={value == item}
|
|
68
|
+
on:click={() => handleClick(item)}
|
|
69
|
+
tabindex="0"
|
|
70
|
+
class="cursor-pointer"
|
|
71
|
+
>
|
|
72
|
+
{#if numbers}
|
|
73
|
+
{index + 1}
|
|
74
|
+
{/if}
|
|
75
|
+
</pg>
|
|
76
|
+
{/each}
|
|
77
|
+
</block>
|
|
78
|
+
</span>
|
|
79
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
80
|
+
<span
|
|
81
|
+
class="flex items-center cursor-pointer justify-end"
|
|
82
|
+
on:click={() => handleClick(next)}
|
|
83
|
+
tabIndex={next ? 0 : -1}
|
|
84
|
+
>
|
|
85
|
+
{#if next}
|
|
86
|
+
<p class="text-right">
|
|
87
|
+
{#if next[fields.text]}
|
|
88
|
+
{next[fields.text]}
|
|
89
|
+
{/if}
|
|
90
|
+
</p>
|
|
91
|
+
<Icon name={navigate.right} />
|
|
92
|
+
{/if}
|
|
93
|
+
</span>
|
|
94
|
+
</nav-pages>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { swipeable } from './actions/swipeable'
|
|
3
|
+
import { navigable } from './actions/navigable'
|
|
4
|
+
import { fly, fade } from 'svelte/transition'
|
|
5
|
+
import { cubicInOut } from 'svelte/easing'
|
|
6
|
+
|
|
7
|
+
let className = 'three-col'
|
|
8
|
+
export { className as class }
|
|
9
|
+
export let items
|
|
10
|
+
export let small = true
|
|
11
|
+
export let duration = 400
|
|
12
|
+
export let easing = cubicInOut
|
|
13
|
+
export let value
|
|
14
|
+
|
|
15
|
+
let previous = -1
|
|
16
|
+
let activeIndex = 0
|
|
17
|
+
let direction = 1
|
|
18
|
+
let width
|
|
19
|
+
|
|
20
|
+
function handleNext() {
|
|
21
|
+
if (activeIndex < items.length - 1) value = items[activeIndex + 1]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function handlePrevious() {
|
|
25
|
+
if (activeIndex > 0) value = items[activeIndex - 1]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function activeIndexFromPage(value) {
|
|
29
|
+
const index = items.findIndex((item) => item === value)
|
|
30
|
+
return index > -1 ? index : 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
$: activeIndex = activeIndexFromPage(value)
|
|
34
|
+
$: {
|
|
35
|
+
direction = Math.sign(activeIndex - previous)
|
|
36
|
+
previous = activeIndex
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
41
|
+
<container
|
|
42
|
+
use:swipeable={{ enabled: small }}
|
|
43
|
+
on:swipeLeft={handleNext}
|
|
44
|
+
on:swipeRight={handlePrevious}
|
|
45
|
+
use:navigable={{ enabled: small }}
|
|
46
|
+
on:previous={handlePrevious}
|
|
47
|
+
on:next={handleNext}
|
|
48
|
+
tabindex={0}
|
|
49
|
+
class="overflow-hidden {className}"
|
|
50
|
+
bind:clientWidth={width}
|
|
51
|
+
>
|
|
52
|
+
{#each items as item, index}
|
|
53
|
+
{@const segmentClass = 'col-' + (index + 1)}
|
|
54
|
+
{@const props = item.props ?? {}}
|
|
55
|
+
{#if small && index === activeIndex}
|
|
56
|
+
<segment
|
|
57
|
+
class="absolute w-full h-full {segmentClass}"
|
|
58
|
+
out:fade={{
|
|
59
|
+
x: -1 * direction * width,
|
|
60
|
+
duration,
|
|
61
|
+
easing
|
|
62
|
+
}}
|
|
63
|
+
in:fly={{ x: direction * width, duration, easing }}
|
|
64
|
+
>
|
|
65
|
+
<svelte:component this={item.component} {...props} />
|
|
66
|
+
</segment>
|
|
67
|
+
{:else if !small}
|
|
68
|
+
<segment class={segmentClass}>
|
|
69
|
+
<svelte:component this={item.component} {...props} />
|
|
70
|
+
</segment>
|
|
71
|
+
{/if}
|
|
72
|
+
{/each}
|
|
73
|
+
</container>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Scrollable from './Scrollable.svelte'
|
|
3
|
+
|
|
4
|
+
export let search = ''
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="flex flex-col overflow-hidden h-full w-full searchable">
|
|
8
|
+
<div class="flex flex-col flex-shrink-0 flex-grow px-4 py-2 quick-search">
|
|
9
|
+
<input
|
|
10
|
+
type="search"
|
|
11
|
+
bind:value={search}
|
|
12
|
+
class="rounded-full px-3 leading-loose"
|
|
13
|
+
placeholder="search"
|
|
14
|
+
/>
|
|
15
|
+
</div>
|
|
16
|
+
<Scrollable>
|
|
17
|
+
<slot />
|
|
18
|
+
</Scrollable>
|
|
19
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { slide, fade } from 'svelte/transition'
|
|
3
|
+
|
|
4
|
+
let className = 'menu'
|
|
5
|
+
export { className as class }
|
|
6
|
+
export let top
|
|
7
|
+
export let offset = -top
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<scroll
|
|
11
|
+
in:slide={{ duration: 50, y: offset }}
|
|
12
|
+
out:fade={{ duration: 50 }}
|
|
13
|
+
style:top="{top}px"
|
|
14
|
+
class="flex flex-col absolute w-full z-10 overflow-scroll {className}"
|
|
15
|
+
>
|
|
16
|
+
<slot />
|
|
17
|
+
</scroll>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
import { defaultFields } from './constants'
|
|
4
|
+
import { Text } from './items'
|
|
5
|
+
import { navigable } from './actions'
|
|
6
|
+
import { getComponent } from './list'
|
|
7
|
+
|
|
8
|
+
const dispatch = createEventDispatcher()
|
|
9
|
+
|
|
10
|
+
let className = ''
|
|
11
|
+
export { className as class }
|
|
12
|
+
export let items = []
|
|
13
|
+
export let fields = {}
|
|
14
|
+
export let using = {}
|
|
15
|
+
export let value
|
|
16
|
+
let index = -1
|
|
17
|
+
|
|
18
|
+
function moveNext() {
|
|
19
|
+
index = index < items.length - 1 ? index + 1 : 0
|
|
20
|
+
dispatch('select', items[index])
|
|
21
|
+
}
|
|
22
|
+
function moveBack() {
|
|
23
|
+
index = index > 0 ? index - 1 : items.length - 1
|
|
24
|
+
dispatch('select', items[index])
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
$: using = { default: Text, ...using }
|
|
28
|
+
$: fields = { ...defaultFields, ...fields }
|
|
29
|
+
$: value = index >= 0 ? items[index] : null
|
|
30
|
+
$: component = getComponent(value, fields)
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
|
34
|
+
<spin-list class="flex flex-row w-full {className}" tabindex={0}>
|
|
35
|
+
<input
|
|
36
|
+
type="text"
|
|
37
|
+
class="flex flex-grow"
|
|
38
|
+
bind:value
|
|
39
|
+
readonly
|
|
40
|
+
use:navigable
|
|
41
|
+
on:next={moveNext}
|
|
42
|
+
on:previous={moveBack}
|
|
43
|
+
/>
|
|
44
|
+
<!-- <svelte:component this={component} bind:content={value} {fields} on:change /> -->
|
|
45
|
+
<square class="h-full position-absolute right-0">
|
|
46
|
+
<icon class="i-carbon-chevron-sort" />
|
|
47
|
+
</square>
|
|
48
|
+
</spin-list>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
import { pannable } from './actions'
|
|
4
|
+
|
|
5
|
+
const dispatch = createEventDispatcher()
|
|
6
|
+
|
|
7
|
+
export let vertical = false
|
|
8
|
+
export let limits = [50, 30]
|
|
9
|
+
export let pos = 70
|
|
10
|
+
export let styles = ['', '']
|
|
11
|
+
|
|
12
|
+
let refs = {}
|
|
13
|
+
|
|
14
|
+
function clamp(min, max, value) {
|
|
15
|
+
return min > value ? min : max < value ? max : value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function handlePanMove(event) {
|
|
19
|
+
const { top, bottom, left, right } = refs.wrapper.getBoundingClientRect()
|
|
20
|
+
const extents = horizontal ? [left, right] : [top, bottom]
|
|
21
|
+
let px = clamp(
|
|
22
|
+
extents[0],
|
|
23
|
+
extents[1],
|
|
24
|
+
horizontal ? event.detail.x : event.detail.y
|
|
25
|
+
)
|
|
26
|
+
pos = clamp(
|
|
27
|
+
limits[0],
|
|
28
|
+
100 - limits[1],
|
|
29
|
+
(100 * (px - extents[0])) / (extents[1] - extents[0])
|
|
30
|
+
)
|
|
31
|
+
dispatch('change', { pos })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
$: horizontal = !vertical
|
|
35
|
+
$: side = horizontal ? 'left' : 'top'
|
|
36
|
+
$: dimension = horizontal ? 'width' : 'height'
|
|
37
|
+
$: direction = vertical ? 'vertical' : 'horizontal'
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<div class="wrapper {direction}" bind:this={refs.wrapper}>
|
|
41
|
+
<div class={styles[0]} style="{dimension}: {pos}%;">
|
|
42
|
+
<slot name="a" />
|
|
43
|
+
</div>
|
|
44
|
+
<div class={styles[1]} style="{dimension}: {100 - pos}%;">
|
|
45
|
+
<slot name="b" />
|
|
46
|
+
</div>
|
|
47
|
+
<span
|
|
48
|
+
class="wall"
|
|
49
|
+
use:pannable
|
|
50
|
+
on:panmove={handlePanMove}
|
|
51
|
+
style="{side}: calc({pos}% - 8px)"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
.wrapper {
|
|
57
|
+
position: relative;
|
|
58
|
+
display: flex;
|
|
59
|
+
height: 100%;
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
.wrapper div {
|
|
63
|
+
flex: 1 1 auto;
|
|
64
|
+
height: 100%;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.horizontal {
|
|
68
|
+
flex-direction: row;
|
|
69
|
+
}
|
|
70
|
+
.vertical {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
.wall {
|
|
74
|
+
position: absolute;
|
|
75
|
+
z-index: 10;
|
|
76
|
+
}
|
|
77
|
+
.wall::after {
|
|
78
|
+
content: '';
|
|
79
|
+
position: absolute;
|
|
80
|
+
background-color: var(--bg-800);
|
|
81
|
+
}
|
|
82
|
+
.wall:hover {
|
|
83
|
+
cursor: ew-resize;
|
|
84
|
+
}
|
|
85
|
+
.horizontal .wall {
|
|
86
|
+
padding: 0 8px;
|
|
87
|
+
width: 0;
|
|
88
|
+
height: 100%;
|
|
89
|
+
cursor: ew-resize;
|
|
90
|
+
}
|
|
91
|
+
.horizontal .wall::after {
|
|
92
|
+
left: 8px;
|
|
93
|
+
top: 0;
|
|
94
|
+
width: 1px;
|
|
95
|
+
height: 100%;
|
|
96
|
+
}
|
|
97
|
+
.vertical .wall {
|
|
98
|
+
padding: 8px 0;
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 0;
|
|
101
|
+
cursor: ns-resize;
|
|
102
|
+
}
|
|
103
|
+
.vertical .wall::after {
|
|
104
|
+
top: 8px;
|
|
105
|
+
left: 0;
|
|
106
|
+
width: 100%;
|
|
107
|
+
height: 1px;
|
|
108
|
+
}
|
|
109
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Splitter from './Splitter.svelte'
|
|
3
|
+
|
|
4
|
+
export let vertical = false
|
|
5
|
+
export let min = 30
|
|
6
|
+
export let max = 70
|
|
7
|
+
export let pos = 30
|
|
8
|
+
|
|
9
|
+
$: sizes = [pos, 100 - pos]
|
|
10
|
+
|
|
11
|
+
$: direction = { direction: vertical ? 'flex-col' : 'flex-row' }
|
|
12
|
+
$: sizeA = {
|
|
13
|
+
width: vertical ? 100 : sizes[0],
|
|
14
|
+
height: vertical ? sizes[0] : 100
|
|
15
|
+
}
|
|
16
|
+
$: sizeB = {
|
|
17
|
+
width: vertical ? 100 : sizes[1],
|
|
18
|
+
height: vertical ? sizes[1] : 100
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function onSplitterChange(e) {
|
|
22
|
+
pos = e.detail.pos - e.detail.offset
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div class="relative flex w-full h-full" style:--direction={direction}>
|
|
27
|
+
<section style:--sizeA={sizeA} class="flex flex-grow flex-shrink select-none">
|
|
28
|
+
<slot name="a" />
|
|
29
|
+
</section>
|
|
30
|
+
<section style:--sizeB={sizeB} class="flex flex-grow flex-shrink select-none">
|
|
31
|
+
<slot name="b" />
|
|
32
|
+
</section>
|
|
33
|
+
<Splitter {vertical} {min} {max} {pos} on:change={onSplitterChange} />
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
div {
|
|
38
|
+
flex-direction: var(--direction);
|
|
39
|
+
}
|
|
40
|
+
section {
|
|
41
|
+
width: calc(var(--width) * 1%);
|
|
42
|
+
height: calc(var(--height) * 1%);
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
// ensure that parent has position: relative.
|
|
3
|
+
// on reaching limit remove mouse events.
|
|
4
|
+
import { createEventDispatcher } from 'svelte'
|
|
5
|
+
import { pannable } from './actions'
|
|
6
|
+
|
|
7
|
+
const dispatch = createEventDispatcher()
|
|
8
|
+
|
|
9
|
+
export let vertical = false
|
|
10
|
+
export let index
|
|
11
|
+
export let min = 0
|
|
12
|
+
export let max = 100
|
|
13
|
+
export let pos = 50
|
|
14
|
+
export let offset = 0
|
|
15
|
+
|
|
16
|
+
let wall
|
|
17
|
+
|
|
18
|
+
function clamp(min, max, value) {
|
|
19
|
+
return min > value ? min : max < value ? max : value
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function fixLimits() {
|
|
23
|
+
if (min > max) [min, max] = [max, min]
|
|
24
|
+
max = clamp(0, 100, max)
|
|
25
|
+
min = clamp(0, 100, min)
|
|
26
|
+
pos = clamp(min, max, pos)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function handlePanMove(event) {
|
|
30
|
+
const { top, bottom, left, right } =
|
|
31
|
+
wall.parentElement.getBoundingClientRect()
|
|
32
|
+
const extents = horizontal ? [left, right] : [top, bottom]
|
|
33
|
+
let px = clamp(
|
|
34
|
+
extents[0],
|
|
35
|
+
extents[1],
|
|
36
|
+
horizontal ? event.detail.x : event.detail.y
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
pos = clamp(min, max, (100 * (px - extents[0])) / (extents[1] - extents[0]))
|
|
40
|
+
|
|
41
|
+
dispatch('change', { pos, index, offset })
|
|
42
|
+
}
|
|
43
|
+
$: fixLimits()
|
|
44
|
+
$: horizontal = !vertical
|
|
45
|
+
$: side = horizontal ? 'left' : 'top'
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<span
|
|
49
|
+
bind:this={wall}
|
|
50
|
+
class="wall"
|
|
51
|
+
class:vertical
|
|
52
|
+
class:horizontal
|
|
53
|
+
use:pannable
|
|
54
|
+
on:panmove={handlePanMove}
|
|
55
|
+
style="{side}: calc({pos}% - 8px)"
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
<style>
|
|
59
|
+
.wall {
|
|
60
|
+
position: absolute;
|
|
61
|
+
z-index: 10;
|
|
62
|
+
}
|
|
63
|
+
.wall::after {
|
|
64
|
+
content: '';
|
|
65
|
+
position: absolute;
|
|
66
|
+
background-color: #000;
|
|
67
|
+
}
|
|
68
|
+
.wall:hover {
|
|
69
|
+
cursor: ew-resize;
|
|
70
|
+
}
|
|
71
|
+
.horizontal.wall {
|
|
72
|
+
padding: 0 8px;
|
|
73
|
+
width: 0;
|
|
74
|
+
height: 100%;
|
|
75
|
+
cursor: ew-resize;
|
|
76
|
+
}
|
|
77
|
+
.horizontal.wall::after {
|
|
78
|
+
left: 8px;
|
|
79
|
+
top: 0;
|
|
80
|
+
width: 1px;
|
|
81
|
+
height: 100%;
|
|
82
|
+
}
|
|
83
|
+
.vertical.wall {
|
|
84
|
+
padding: 8px 0;
|
|
85
|
+
width: 100%;
|
|
86
|
+
height: 0;
|
|
87
|
+
cursor: ns-resize;
|
|
88
|
+
}
|
|
89
|
+
.vertical.wall::after {
|
|
90
|
+
top: 8px;
|
|
91
|
+
left: 0;
|
|
92
|
+
width: 100%;
|
|
93
|
+
height: 1px;
|
|
94
|
+
}
|
|
95
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
|
|
4
|
+
const dispatch = createEventDispatcher()
|
|
5
|
+
|
|
6
|
+
export let icon = null
|
|
7
|
+
export let label
|
|
8
|
+
export let active = false
|
|
9
|
+
export let allowClose = false
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
13
|
+
<tab class="flex flex-row items-center" class:active on:click>
|
|
14
|
+
{#if icon}
|
|
15
|
+
<icon class={icon} aria-label={icon} />
|
|
16
|
+
{/if}
|
|
17
|
+
{#if label}
|
|
18
|
+
<p class="flex flex-shrink-0 flex-grow justify-center">{label}</p>
|
|
19
|
+
{/if}
|
|
20
|
+
{#if allowClose}
|
|
21
|
+
<icon
|
|
22
|
+
class="remove small"
|
|
23
|
+
aria-label="remove"
|
|
24
|
+
on:click={() => dispatch('remove')}
|
|
25
|
+
/>
|
|
26
|
+
{/if}
|
|
27
|
+
</tab>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { createEventDispatcher } from 'svelte'
|
|
3
|
+
import { defaultFields } from './constants'
|
|
4
|
+
import TabItem from './TabItem.svelte'
|
|
5
|
+
|
|
6
|
+
const dispatch = createEventDispatcher()
|
|
7
|
+
|
|
8
|
+
export let items = []
|
|
9
|
+
export let fields = {}
|
|
10
|
+
export let allowClose = false
|
|
11
|
+
export let value = items[0]
|
|
12
|
+
|
|
13
|
+
function activate(item) {
|
|
14
|
+
value = item
|
|
15
|
+
dispatch('switch', item)
|
|
16
|
+
}
|
|
17
|
+
function closeTab(index) {
|
|
18
|
+
items[index].isClosed = true
|
|
19
|
+
}
|
|
20
|
+
$: fields = { ...defaultFields, ...fields }
|
|
21
|
+
$: filtered = items.filter((item) => !item.isClosed)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
{#each filtered as item, index}
|
|
25
|
+
{@const label = item[fields.text]}
|
|
26
|
+
<TabItem
|
|
27
|
+
icon={item[fields.icon]}
|
|
28
|
+
{label}
|
|
29
|
+
{allowClose}
|
|
30
|
+
active={value == item}
|
|
31
|
+
on:click={() => activate(item)}
|
|
32
|
+
on:close={() => closeTab(index)}
|
|
33
|
+
/>
|
|
34
|
+
{/each}
|
package/src/Tabs.svelte
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import TabItems from './TabItems.svelte'
|
|
3
|
+
import TabItem from './TabItem.svelte'
|
|
4
|
+
|
|
5
|
+
let className = ''
|
|
6
|
+
export { className as class }
|
|
7
|
+
export let items = []
|
|
8
|
+
export let fields = {}
|
|
9
|
+
export let title = null
|
|
10
|
+
export let allowAdd = false
|
|
11
|
+
export let allowClose = false
|
|
12
|
+
export let value = items[0]
|
|
13
|
+
|
|
14
|
+
function addTab() {
|
|
15
|
+
items = [...items, {}]
|
|
16
|
+
value = items[items.length - 1]
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<tab-view class="flex flex-col w-full flex-grow {className}">
|
|
21
|
+
<tabs class="flex flex-row flex-shrink-0 w-full select-none cursor-pointer">
|
|
22
|
+
{#if title}
|
|
23
|
+
<p>{title}</p>
|
|
24
|
+
{/if}
|
|
25
|
+
<TabItems {items} {fields} {allowClose} bind:value on:close />
|
|
26
|
+
{#if allowAdd}
|
|
27
|
+
<TabItem label="+" on:click={addTab} />
|
|
28
|
+
{/if}
|
|
29
|
+
</tabs>
|
|
30
|
+
<content class="flex flex-col flex-grow"><slot /></content>
|
|
31
|
+
</tab-view>
|
package/src/Tree.svelte
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import NestedList from './NestedList.svelte'
|
|
3
|
+
import { Text } from './items'
|
|
4
|
+
import { defaultFields } from './constants'
|
|
5
|
+
|
|
6
|
+
export let items = []
|
|
7
|
+
export let fields = {}
|
|
8
|
+
export let using = { default: Text }
|
|
9
|
+
export let root = 'root'
|
|
10
|
+
export let rtl = false
|
|
11
|
+
|
|
12
|
+
$: fields = { ...defaultFields, ...fields }
|
|
13
|
+
$: items =
|
|
14
|
+
items.length == 1
|
|
15
|
+
? items
|
|
16
|
+
: [{ [fields.text]: root, [fields.children]: items }]
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<NestedList {items} {fields} {using} {rtl} />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const KEYCODE_ESC = 27
|
|
2
|
+
|
|
3
|
+
export function dismissable(node) {
|
|
4
|
+
const handleClick = (event) => {
|
|
5
|
+
if (node && !node.contains(event.target) && !event.defaultPrevented) {
|
|
6
|
+
node.dispatchEvent(new CustomEvent('dismiss', node))
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const keyup = (event) => {
|
|
10
|
+
if (event.keyCode === KEYCODE_ESC) {
|
|
11
|
+
node.dispatchEvent(new CustomEvent('dismiss', node))
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
document.addEventListener('click', handleClick, true)
|
|
16
|
+
document.addEventListener('keyup', keyup, true)
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
destroy() {
|
|
20
|
+
document.removeEventListener('click', handleClick, true)
|
|
21
|
+
document.removeEventListener('keyup', keyup, true)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|