@axel669/zephyr 0.5.0-alpha.0 → 0.5.5
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/package.json +42 -41
- package/readme.md +8 -1
- package/src/changed.js +10 -10
- package/src/composed/data-table.svelte +152 -178
- package/src/composed/entry-button.svelte +14 -13
- package/src/custom-macros.js +9 -0
- package/src/data-display/table.svelte +5 -1
- package/src/dialogs/alert.svelte +5 -5
- package/src/dialogs/confirm.svelte +4 -3
- package/src/dialogs/prompt.svelte +67 -0
- package/src/{hash.svelte.js → hash.js} +0 -9
- package/src/index.js +4 -4
- package/src/internals.js +12 -0
- package/src/layout/dialog.svelte +1 -0
- package/src/layout/drawer.svelte +3 -11
- package/src/layout/modal.svelte +29 -28
- package/src/layout/paper.svelte +0 -11
- package/src/props.js +24 -24
- package/src/routing/route.svelte +0 -3
- package/src/routing/routing.svelte.js +1 -7
- package/src/wind.js +4 -0
- package/src/wsx.js +1 -1
- package/src/async/load-zone.svelte +0 -22
package/package.json
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@axel669/zephyr",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "src/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"site/start": "wrangler pages dev site --port 45067",
|
|
9
|
-
"site/build": "rollup -c docsite/rollup.config.js",
|
|
10
|
-
"site/watch": "rollup -c docsite/rollup.config.js --watch"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [],
|
|
13
|
-
"author": "",
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"@axel669/windstorm": "0.5.
|
|
17
|
-
"svelte": "^5.
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@axel669/asuid": "^0.2.1",
|
|
21
|
-
"@axel669/ipsen": "0.4.0-beta.7",
|
|
22
|
-
"@axel669/rollup-copy-static": "^0.2.0",
|
|
23
|
-
"@axel669/rollup-html-input": "^0.1.2",
|
|
24
|
-
"@rollup/plugin-node-resolve": "^15.0.2",
|
|
25
|
-
"@rollup/plugin-terser": "^0.4.0",
|
|
26
|
-
"marked": "^12.0.2",
|
|
27
|
-
"prism-svelte": "^0.5.0",
|
|
28
|
-
"prismjs": "^1.29.0",
|
|
29
|
-
"rollup": "^3.20.2",
|
|
30
|
-
"rollup-plugin-delete": "^2.0.0",
|
|
31
|
-
"rollup-plugin-svelte": "^7.2.2"
|
|
32
|
-
},
|
|
33
|
-
"files": [
|
|
34
|
-
"src/"
|
|
35
|
-
],
|
|
36
|
-
"imports": {
|
|
37
|
-
"#lib": "./src/index.js",
|
|
38
|
-
"#comp/*": "./docsite/comp/*.svelte",
|
|
39
|
-
"#state/*": "./docsite/state/*.js"
|
|
40
|
-
|
|
41
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@axel669/zephyr",
|
|
3
|
+
"version": "0.5.5",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"site/start": "wrangler pages dev site --port 45067",
|
|
9
|
+
"site/build": "rollup -c docsite/rollup.config.js",
|
|
10
|
+
"site/watch": "rollup -c docsite/rollup.config.js --watch"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [],
|
|
13
|
+
"author": "",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@axel669/windstorm": "0.5.5",
|
|
17
|
+
"svelte": "^5.30.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@axel669/asuid": "^0.2.1",
|
|
21
|
+
"@axel669/ipsen": "0.4.0-beta.7",
|
|
22
|
+
"@axel669/rollup-copy-static": "^0.2.0",
|
|
23
|
+
"@axel669/rollup-html-input": "^0.1.2",
|
|
24
|
+
"@rollup/plugin-node-resolve": "^15.0.2",
|
|
25
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
26
|
+
"marked": "^12.0.2",
|
|
27
|
+
"prism-svelte": "^0.5.0",
|
|
28
|
+
"prismjs": "^1.29.0",
|
|
29
|
+
"rollup": "^3.20.2",
|
|
30
|
+
"rollup-plugin-delete": "^2.0.0",
|
|
31
|
+
"rollup-plugin-svelte": "^7.2.2"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"src/"
|
|
35
|
+
],
|
|
36
|
+
"imports": {
|
|
37
|
+
"#lib": "./src/index.js",
|
|
38
|
+
"#comp/*": "./docsite/comp/*.svelte",
|
|
39
|
+
"#state/*": "./docsite/state/*.js",
|
|
40
|
+
"#README": "./readme.md"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/readme.md
CHANGED
|
@@ -4,6 +4,12 @@ library, with some additional parts to make it look nice in the markup.
|
|
|
4
4
|
|
|
5
5
|
[Docs Here](https://zephyr.axel669.net)
|
|
6
6
|
|
|
7
|
+
## Todo
|
|
8
|
+
These are things that I plan to do, but didn't want to hold up the 0.5.x major
|
|
9
|
+
changes for svelte 5/runes/improvements.
|
|
10
|
+
- Add filter/sort back into data table
|
|
11
|
+
- Form element
|
|
12
|
+
|
|
7
13
|
## Installation
|
|
8
14
|
Zephyr can be installed through npm (or the variants like yarn, pnpm, etc).
|
|
9
15
|
|
|
@@ -15,7 +21,8 @@ npm install @axel669/zephyr
|
|
|
15
21
|
Components can be imported individually from the library for tree-shaking, or
|
|
16
22
|
the entire lib can imported at once, but I dunno how big that bundle will be.
|
|
17
23
|
Components can also take any windstorm macro as a prop, including custom macros,
|
|
18
|
-
using the same rules as the `wsx` covered in
|
|
24
|
+
using the same rules as the `wsx` covered in
|
|
25
|
+
[Functions](./docsite/docs/functions.md).
|
|
19
26
|
|
|
20
27
|
### Theming
|
|
21
28
|
Windstorm expects a theme to be defined on an ancestor of the html elements
|
package/src/changed.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export const trackChanges = (initial) => {
|
|
2
|
-
let current = initial
|
|
3
|
-
return (next) => {
|
|
4
|
-
if (next !== current) {
|
|
5
|
-
current = next
|
|
6
|
-
return true
|
|
7
|
-
}
|
|
8
|
-
return false
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
export const trackChanges = (initial) => {
|
|
2
|
+
let current = initial
|
|
3
|
+
return (next) => {
|
|
4
|
+
if (next !== current) {
|
|
5
|
+
current = next
|
|
6
|
+
return true
|
|
7
|
+
}
|
|
8
|
+
return false
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -1,200 +1,174 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<script module>
|
|
2
|
+
const itemRange = (info) => {
|
|
3
|
+
const {
|
|
4
|
+
scrollPos,
|
|
5
|
+
scrollMax,
|
|
6
|
+
rowSize,
|
|
7
|
+
length,
|
|
8
|
+
containerHeight,
|
|
9
|
+
} = info
|
|
10
|
+
if (scrollMax === null) {
|
|
11
|
+
return [0, 0]
|
|
8
12
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (filter(row, value) === false) {
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
13
|
+
const displayed = Math.ceil(containerHeight / rowSize) - 1
|
|
14
|
+
const itemPos = Math.floor(
|
|
15
|
+
(scrollPos / scrollMax) * (length - displayed)
|
|
18
16
|
)
|
|
17
|
+
return [
|
|
18
|
+
itemPos - 1,
|
|
19
|
+
itemPos + displayed + 1,
|
|
20
|
+
displayed + 2,
|
|
21
|
+
]
|
|
19
22
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
(_, i) => sorted[page * pageSize + i]
|
|
23
|
+
const emptyRow = Symbol("empty row")
|
|
24
|
+
const nullRow = Symbol("null row")
|
|
25
|
+
|
|
26
|
+
const sliceData = (data, range) => {
|
|
27
|
+
const displayed = data.slice(
|
|
28
|
+
Math.max(range[0], 0),
|
|
29
|
+
range[1]
|
|
28
30
|
)
|
|
31
|
+
if (range[0] === -1) {
|
|
32
|
+
return [emptyRow, ...displayed]
|
|
33
|
+
}
|
|
34
|
+
if (displayed.length < range[2]) {
|
|
35
|
+
return [
|
|
36
|
+
...displayed,
|
|
37
|
+
...Array.from(
|
|
38
|
+
{ length: range[2] - displayed.length },
|
|
39
|
+
() => nullRow
|
|
40
|
+
)
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
return displayed
|
|
29
44
|
}
|
|
30
|
-
const noSort = {
|
|
31
|
-
direction: null,
|
|
32
|
-
func: (a, b) => 0,
|
|
33
|
-
base: null,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const dtContext = Symbol("table key")
|
|
37
45
|
</script>
|
|
38
46
|
|
|
39
47
|
<script>
|
|
40
|
-
import {
|
|
41
|
-
import { writable } from "svelte/store"
|
|
42
|
-
|
|
43
|
-
import Button from "../control/button.svelte"
|
|
44
|
-
import Icon from "../info/icon.svelte"
|
|
45
|
-
import Paper from "../layout/paper.svelte"
|
|
46
|
-
import Table from "../data-display/table.svelte"
|
|
47
|
-
import Text from "../text.svelte"
|
|
48
|
+
import { on } from "svelte/events"
|
|
48
49
|
|
|
49
50
|
import Grid from "../layout/grid.svelte"
|
|
50
51
|
|
|
51
52
|
import wsx from "../wsx.js"
|
|
52
|
-
import { handler$, eventHandler$ } from "../handler$.js"
|
|
53
|
-
|
|
54
|
-
export let color = "@primary"
|
|
55
|
-
export let fillHeader = true
|
|
56
|
-
export let data
|
|
57
|
-
export let pageSize = 10
|
|
58
|
-
export let page = 0
|
|
59
|
-
export let rowHeight = "40px"
|
|
60
|
-
export let scrollable = false
|
|
61
|
-
export let height = null
|
|
62
|
-
|
|
63
|
-
let sorting = noSort
|
|
64
|
-
let filters = new Map()
|
|
65
|
-
let filterFunctions = []
|
|
66
|
-
let jumpTarget = "1"
|
|
67
|
-
|
|
68
|
-
$: filteredData = applyFilters(data, filterFunctions, sorting.func)
|
|
69
|
-
$: rows = sliceData(filteredData, page, pageSize, sorting.func)
|
|
70
|
-
$: rowCount = filteredData?.length ?? 0
|
|
71
|
-
$: pageCount = Math.ceil(rowCount / pageSize)
|
|
72
|
-
$: maxPage = Math.max(pageCount - 1, 0)
|
|
73
|
-
$: jumpTarget = (page + 1).toString()
|
|
74
|
-
|
|
75
|
-
$: if (filteredData === null) {
|
|
76
|
-
console.warn("DataTable: data is not an array")
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const prev = () => page = Math.max(0, page - 1)
|
|
80
|
-
const next = () => page = Math.min(maxPage, page + 1)
|
|
81
|
-
|
|
82
|
-
const updateSort = (func) => {
|
|
83
|
-
if (sorting.base === func) {
|
|
84
|
-
if (sorting.direction === "desc") {
|
|
85
|
-
sorting = noSort
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
sorting = {
|
|
89
|
-
func: (a, b) => -func(a, b),
|
|
90
|
-
base: func,
|
|
91
|
-
direction: "desc"
|
|
92
|
-
}
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
|
-
sorting = {
|
|
96
|
-
func,
|
|
97
|
-
base: func,
|
|
98
|
-
direction: "asc",
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
const updateFilter = (func, value) => {
|
|
102
|
-
if (func === null) {
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
filters.set(func, value)
|
|
106
|
-
filterFunctions = [
|
|
107
|
-
...filters.entries()
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
53
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
54
|
+
const {
|
|
55
|
+
data,
|
|
56
|
+
rowSize = 40,
|
|
57
|
+
headerSize = rowSize,
|
|
58
|
+
cols = "1fr",
|
|
59
|
+
gap = 2,
|
|
60
|
+
colGap = gap,
|
|
61
|
+
rowGap = gap,
|
|
62
|
+
header,
|
|
63
|
+
row,
|
|
117
64
|
color,
|
|
118
|
-
|
|
119
|
-
|
|
65
|
+
fillHeader = false,
|
|
66
|
+
...rest
|
|
67
|
+
} = $props()
|
|
120
68
|
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
|
|
69
|
+
const rowPx = rowSize + rowGap
|
|
70
|
+
const height = $derived(
|
|
71
|
+
rowPx * data.length - rowGap
|
|
124
72
|
)
|
|
73
|
+
const tableHeight = $derived(height + rowPx)
|
|
125
74
|
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
|
|
75
|
+
let scrollPos = $state(0)
|
|
76
|
+
let scrollMax = $state(null)
|
|
77
|
+
let containerHeight = $state(null)
|
|
78
|
+
const scrollHandler = (evt) => {
|
|
79
|
+
scrollPos = container.scrollTop
|
|
129
80
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
81
|
+
const range = $derived(
|
|
82
|
+
itemRange({
|
|
83
|
+
scrollPos,
|
|
84
|
+
scrollMax,
|
|
85
|
+
containerHeight,
|
|
86
|
+
rowSize: rowSize + rowGap,
|
|
87
|
+
length: data.length,
|
|
88
|
+
})
|
|
89
|
+
)
|
|
90
|
+
let container = $state(null)
|
|
91
|
+
|
|
92
|
+
$effect(() => {
|
|
93
|
+
containerHeight = container.clientHeight
|
|
94
|
+
scrollMax = container.scrollHeight - containerHeight
|
|
95
|
+
on(container, "scroll", scrollHandler, { passive: true })
|
|
96
|
+
const observer = new ResizeObserver(
|
|
97
|
+
() => {
|
|
98
|
+
containerHeight = container.clientHeight
|
|
99
|
+
scrollMax = container.scrollHeight - containerHeight
|
|
100
|
+
}
|
|
142
101
|
)
|
|
143
|
-
|
|
144
|
-
|
|
102
|
+
observer.observe(container)
|
|
103
|
+
return () => observer.unobserve(container)
|
|
104
|
+
})
|
|
145
105
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
106
|
+
const displayed = $derived(range[2])
|
|
107
|
+
const displayedRows = $derived(
|
|
108
|
+
sliceData(data, range)
|
|
109
|
+
)
|
|
110
|
+
const tbodyHeight = $derived(displayRows.length * rowSize)
|
|
111
|
+
|
|
112
|
+
const tableWSX = $derived({
|
|
113
|
+
"$fill-header": fillHeader,
|
|
114
|
+
$color: color,
|
|
115
|
+
"gr.cols": cols,
|
|
116
|
+
"gap.col": `${colGap}px`,
|
|
117
|
+
"gap.row": `${rowGap}px`,
|
|
118
|
+
"@header-size": `${headerSize}px`,
|
|
119
|
+
"@row-size": `${rowSize}px`,
|
|
120
|
+
"$sticky-header": true,
|
|
121
|
+
w: "100%",
|
|
122
|
+
h: `${tableHeight}px`,
|
|
123
|
+
over: "visible",
|
|
124
|
+
con: "paint",
|
|
125
|
+
})
|
|
126
|
+
const tbodyWSX = $derived({
|
|
127
|
+
disp: "grid",
|
|
128
|
+
"gr.rows": "subgrid",
|
|
129
|
+
"gr.cols": "subgrid",
|
|
130
|
+
row: `span ${displayed}`,
|
|
131
|
+
tf: `translateY(${range[0] * rowPx}px)`,
|
|
132
|
+
})
|
|
133
|
+
const footerWSX = $derived({
|
|
134
|
+
h: "40px",
|
|
135
|
+
bg: "@background-element",
|
|
136
|
+
$color: color,
|
|
137
|
+
"b.y": "2px solid @ripple-base-color",
|
|
138
|
+
disp: "flex",
|
|
139
|
+
"fl-center": true,
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const show = $derived({
|
|
143
|
+
start: Math.max(1, range[0] + 2),
|
|
144
|
+
end: Math.min(data.length, range[1] - 1),
|
|
145
|
+
total: data.length,
|
|
146
|
+
})
|
|
158
147
|
</script>
|
|
159
148
|
|
|
160
|
-
<
|
|
161
|
-
<ws-
|
|
162
|
-
<
|
|
163
|
-
<
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Page
|
|
187
|
-
<input ws-x="[b 1px solid @text-color-normal] [w 36px] [r 4px]
|
|
188
|
-
[h 24px] [bg.c transaprent] [t.a center] [m.l 4px] [m.r 4px]"
|
|
189
|
-
type="text" bind:value={jumpTarget}
|
|
190
|
-
on:keypress={jump} on:blur={jump} />
|
|
191
|
-
/ {pageCount}
|
|
192
|
-
</Text>
|
|
193
|
-
{:else}
|
|
194
|
-
<div ws-x="[col span 3] [p.l 4px]">
|
|
195
|
-
No data to show
|
|
196
|
-
</div>
|
|
197
|
-
{/if}
|
|
198
|
-
<slot name="action" />
|
|
199
|
-
</Grid>
|
|
200
|
-
</Paper>
|
|
149
|
+
<Grid cols="1fr" rows="1fr min-content" pos="relative" {...rest} gap="0px">
|
|
150
|
+
<div ws-x="[over auto]" bind:this={container}>
|
|
151
|
+
<table use:wsx={tableWSX}>
|
|
152
|
+
<thead>
|
|
153
|
+
{@render header()}
|
|
154
|
+
</thead>
|
|
155
|
+
<tbody use:wsx={tbodyWSX}>
|
|
156
|
+
{#each displayedRows as dataRow}
|
|
157
|
+
{#if dataRow === nullRow}
|
|
158
|
+
<tr>
|
|
159
|
+
<td ws-x="[col 1 / -1]"></td>
|
|
160
|
+
</tr>
|
|
161
|
+
{:else if dataRow === emptyRow}
|
|
162
|
+
<tr></tr>
|
|
163
|
+
{:else}
|
|
164
|
+
{@render row(dataRow)}
|
|
165
|
+
{/if}
|
|
166
|
+
{/each}
|
|
167
|
+
</tbody>
|
|
168
|
+
</table>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<div use:wsx={footerWSX}>
|
|
172
|
+
Showing: {show.start} - {show.end} of {show.total}
|
|
173
|
+
</div>
|
|
174
|
+
</Grid>
|
|
@@ -2,27 +2,28 @@
|
|
|
2
2
|
import Button from "../control/button.svelte"
|
|
3
3
|
import Modal from "../layout/modal.svelte"
|
|
4
4
|
import { handler$ } from "../handler$.js"
|
|
5
|
+
import { splitProps } from "../props.js"
|
|
5
6
|
|
|
6
7
|
const {
|
|
7
|
-
component,
|
|
8
|
-
props,
|
|
9
|
-
this:Wrapper = Modal,
|
|
10
|
-
"w!props":wrapperProps = {},
|
|
11
8
|
children,
|
|
9
|
+
modal,
|
|
12
10
|
onentry,
|
|
11
|
+
onopen,
|
|
13
12
|
...rest
|
|
14
13
|
} = $props()
|
|
15
14
|
|
|
15
|
+
const prop = splitProps(rest, "m!")
|
|
16
|
+
|
|
16
17
|
let element = null
|
|
17
|
-
const open =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
)
|
|
18
|
+
const open = async (props) => {
|
|
19
|
+
onopen?.()
|
|
20
|
+
const result = await element.show()
|
|
21
|
+
onentry?.(result)
|
|
22
|
+
}
|
|
24
23
|
</script>
|
|
25
24
|
|
|
26
|
-
<Button {...rest} onclick={open
|
|
25
|
+
<Button {...prop.rest} onclick={open} {children} />
|
|
27
26
|
|
|
28
|
-
<
|
|
27
|
+
<Modal bind:this={element} {...prop["m!"]}>
|
|
28
|
+
{@render modal()}
|
|
29
|
+
</Modal>
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
color = "@default",
|
|
6
6
|
data = [],
|
|
7
7
|
fillHeader = false,
|
|
8
|
+
stickyHeader = false,
|
|
9
|
+
cols = "1fr",
|
|
8
10
|
header,
|
|
9
11
|
row,
|
|
10
12
|
emptyRow,
|
|
@@ -13,7 +15,9 @@
|
|
|
13
15
|
|
|
14
16
|
const wind = $derived({
|
|
15
17
|
"$color": color,
|
|
16
|
-
"$header
|
|
18
|
+
"$fill-header": fillHeader,
|
|
19
|
+
"$sticky-header": stickyHeader,
|
|
20
|
+
"gr.cols": cols,
|
|
17
21
|
...rest,
|
|
18
22
|
})
|
|
19
23
|
</script>
|
package/src/dialogs/alert.svelte
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
import Icon from "../info/icon.svelte"
|
|
5
5
|
import Text from "../text.svelte"
|
|
6
6
|
import Titlebar from "../info/titlebar.svelte"
|
|
7
|
+
import { modalContext } from "../layout/modal.svelte"
|
|
7
8
|
|
|
8
9
|
const {
|
|
9
|
-
|
|
10
|
-
color = "@primary",
|
|
10
|
+
color = "@default",
|
|
11
11
|
icon,
|
|
12
12
|
message,
|
|
13
13
|
okText = "OK",
|
|
14
|
-
titleText = "Alert",
|
|
15
|
-
...rest
|
|
14
|
+
title: titleText = "Alert",
|
|
16
15
|
} = $props()
|
|
16
|
+
const { close } = modalContext()
|
|
17
17
|
</script>
|
|
18
18
|
|
|
19
19
|
<Dialog card {color}>
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
</Text>
|
|
35
35
|
|
|
36
36
|
{#snippet footer()}
|
|
37
|
-
<Button onclick={close} {color} ground>
|
|
37
|
+
<Button onclick={() => close(true)} {color} ground>
|
|
38
38
|
{okText}
|
|
39
39
|
</Button>
|
|
40
40
|
{/snippet}
|
|
@@ -5,19 +5,20 @@
|
|
|
5
5
|
import Icon from "../info/icon.svelte"
|
|
6
6
|
import Text from "../text.svelte"
|
|
7
7
|
import Titlebar from "../info/titlebar.svelte"
|
|
8
|
+
import { modalContext } from "../layout/modal.svelte"
|
|
8
9
|
|
|
9
10
|
import { handler$ } from "../handler$.js"
|
|
10
11
|
|
|
11
12
|
const {
|
|
12
|
-
|
|
13
|
-
titleText = "Confirm",
|
|
13
|
+
title: titleText = "Confirm",
|
|
14
14
|
icon,
|
|
15
15
|
message,
|
|
16
16
|
okText = "OK",
|
|
17
17
|
cancelText = "Cancel",
|
|
18
|
-
color = "@
|
|
18
|
+
color = "@default",
|
|
19
19
|
} = $props()
|
|
20
20
|
|
|
21
|
+
const { close } = modalContext()
|
|
21
22
|
const cls = handler$(close)
|
|
22
23
|
</script>
|
|
23
24
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from "../control/button.svelte"
|
|
3
|
+
import Dialog from "../layout/dialog.svelte"
|
|
4
|
+
import Grid from "../layout/grid.svelte"
|
|
5
|
+
import Icon from "../info/icon.svelte"
|
|
6
|
+
import Input from "../control/input.svelte"
|
|
7
|
+
import Text from "../text.svelte"
|
|
8
|
+
import Titlebar from "../info/titlebar.svelte"
|
|
9
|
+
import { modalContext } from "../layout/modal.svelte"
|
|
10
|
+
|
|
11
|
+
import { handler$ } from "../handler$.js"
|
|
12
|
+
import { frameDelay } from "../internals.js"
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
title: titleText = "Confirm",
|
|
16
|
+
icon,
|
|
17
|
+
message,
|
|
18
|
+
okText = "OK",
|
|
19
|
+
cancelText = "Cancel",
|
|
20
|
+
color = "@default",
|
|
21
|
+
value = $bindable(""),
|
|
22
|
+
initial = ""
|
|
23
|
+
} = $props()
|
|
24
|
+
|
|
25
|
+
const { close } = modalContext()
|
|
26
|
+
const cls = handler$(close)
|
|
27
|
+
let input = $state(null)
|
|
28
|
+
|
|
29
|
+
const done = (evt) => {
|
|
30
|
+
evt.preventDefault()
|
|
31
|
+
evt.stopPropagation()
|
|
32
|
+
close(true)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// the first 1-2 frames it's in the DOM it's not visible, focus didn't work
|
|
36
|
+
frameDelay(3, () => input.focus())
|
|
37
|
+
value = initial
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<Dialog card {color}>
|
|
41
|
+
{#snippet header()}
|
|
42
|
+
<Titlebar {color}>
|
|
43
|
+
{#snippet title()}
|
|
44
|
+
<Text title>
|
|
45
|
+
<Icon name={icon}>
|
|
46
|
+
{titleText}
|
|
47
|
+
</Icon>
|
|
48
|
+
</Text>
|
|
49
|
+
{/snippet}
|
|
50
|
+
</Titlebar>
|
|
51
|
+
{/snippet}
|
|
52
|
+
|
|
53
|
+
<form onsubmit={done} ws-x="[grid]">
|
|
54
|
+
<Input bind:value {color} bind:this={input} label={message} />
|
|
55
|
+
</form>
|
|
56
|
+
|
|
57
|
+
{#snippet footer()}
|
|
58
|
+
<Grid cols="1fr 1fr" p="0px">
|
|
59
|
+
<Button onclick={cls(false)} color="@danger" ground>
|
|
60
|
+
{cancelText}
|
|
61
|
+
</Button>
|
|
62
|
+
<Button onclick={cls(true)} color="@secondary" ground>
|
|
63
|
+
{okText}
|
|
64
|
+
</Button>
|
|
65
|
+
</Grid>
|
|
66
|
+
{/snippet}
|
|
67
|
+
</Dialog>
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { readable } from "svelte/store"
|
|
2
2
|
|
|
3
|
-
// export const hash = $state(location.hash.slice(1))
|
|
4
|
-
// window.addEventListener(
|
|
5
|
-
// "popstate",
|
|
6
|
-
// () => hashValue = location.hash.slice(1)
|
|
7
|
-
// )
|
|
8
|
-
// $effect(
|
|
9
|
-
// () => location.hash = hash
|
|
10
|
-
// )
|
|
11
|
-
|
|
12
3
|
export const hash = readable(
|
|
13
4
|
location.hash.slice(1),
|
|
14
5
|
(set) => {
|
package/src/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export { default as Dialog } from "./layout/dialog.svelte"
|
|
|
27
27
|
export { default as Drawer } from "./layout/drawer.svelte"
|
|
28
28
|
export { default as Flex } from "./layout/flex.svelte"
|
|
29
29
|
export { default as Grid } from "./layout/grid.svelte"
|
|
30
|
-
export { default as Modal } from "./layout/modal.svelte"
|
|
30
|
+
export { default as Modal, modalAnimTime, modalContext } from "./layout/modal.svelte"
|
|
31
31
|
export { default as Paper } from "./layout/paper.svelte"
|
|
32
32
|
export { default as Screen } from "./layout/screen.svelte"
|
|
33
33
|
|
|
@@ -38,14 +38,14 @@ export { default as HexagonSpinner } from "./spinner/hexagon-spinner.svelte"
|
|
|
38
38
|
|
|
39
39
|
export { default as Alert } from "./dialogs/alert.svelte"
|
|
40
40
|
export { default as Confirm } from "./dialogs/confirm.svelte"
|
|
41
|
+
export { default as Prompt } from "./dialogs/prompt.svelte"
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
export { default as DataTable } from "./composed/data-table.svelte"
|
|
43
44
|
// export { default as TH } from "./composed/data-table/th.svelte"
|
|
44
45
|
export { default as EntryButton } from "./composed/entry-button.svelte"
|
|
45
46
|
// export { default as Form } from "./composed/form.svelte"
|
|
46
47
|
|
|
47
48
|
export { default as AsyncButton } from "./async/button.svelte"
|
|
48
|
-
// export { default as LoadZone } from "./async/load-zone.svelte"
|
|
49
49
|
export { default as Suspend } from "./async/suspend.svelte"
|
|
50
50
|
|
|
51
51
|
export { default as Route } from "./routing/route.svelte"
|
|
@@ -53,7 +53,7 @@ export { default as Title } from "./routing/title.svelte"
|
|
|
53
53
|
|
|
54
54
|
export { default as wsx } from "./wsx.js"
|
|
55
55
|
|
|
56
|
-
export { hash } from "./hash.
|
|
56
|
+
export { hash } from "./hash.js"
|
|
57
57
|
|
|
58
58
|
export {
|
|
59
59
|
route,
|
package/src/internals.js
ADDED
package/src/layout/dialog.svelte
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
21
21
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
22
|
+
<!-- svelte-ignore a11y_interactive_supports_focus -->
|
|
22
23
|
<wind-wrapper transition:trick ws-x="@@dialog [grid]" {onclick} role="dialog">
|
|
23
24
|
<Paper {...props} />
|
|
24
25
|
</wind-wrapper>
|
package/src/layout/drawer.svelte
CHANGED
|
@@ -31,26 +31,18 @@
|
|
|
31
31
|
</script>
|
|
32
32
|
|
|
33
33
|
<script>
|
|
34
|
-
import { getContext } from "svelte"
|
|
35
|
-
|
|
36
34
|
import wsx from "../wsx.js"
|
|
37
35
|
|
|
38
36
|
import Paper from "./paper.svelte"
|
|
39
|
-
import {
|
|
37
|
+
import { modalAnimTime } from "./modal.svelte"
|
|
40
38
|
|
|
41
39
|
const {
|
|
42
40
|
height,
|
|
43
41
|
type = "menu",
|
|
44
|
-
children,
|
|
45
|
-
header,
|
|
46
|
-
footer,
|
|
47
|
-
content,
|
|
48
42
|
...rest
|
|
49
43
|
} = $props()
|
|
50
|
-
// export let height
|
|
51
|
-
// export let type = "menu"
|
|
52
44
|
|
|
53
|
-
const animTime =
|
|
45
|
+
const animTime = modalAnimTime()
|
|
54
46
|
|
|
55
47
|
// When Svelte removes things from the DOM they are removed immediately
|
|
56
48
|
// unless Svelte has a transition running. Adding this prevents the drawer
|
|
@@ -74,5 +66,5 @@
|
|
|
74
66
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
75
67
|
<wind-drawer-container use:wsx={container} {onclick} role="menubar"
|
|
76
68
|
transition:trick>
|
|
77
|
-
<Paper r="0px" {...rest}
|
|
69
|
+
<Paper r="0px" {...rest} />
|
|
78
70
|
</wind-drawer-container>
|
package/src/layout/modal.svelte
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
<script module>
|
|
2
|
+
import { getContext } from "svelte"
|
|
3
|
+
|
|
2
4
|
let topClose = null
|
|
3
|
-
|
|
5
|
+
const modalAnimTimeSymbol = Symbol("modal animation time")
|
|
6
|
+
const modalContextSymbol = Symbol("modal context")
|
|
7
|
+
|
|
8
|
+
export const modalAnimTime = () => getContext(modalAnimTimeSymbol)
|
|
9
|
+
export const modalContext = () => getContext(modalContextSymbol)
|
|
4
10
|
</script>
|
|
5
11
|
|
|
6
12
|
<script>
|
|
7
|
-
import {
|
|
13
|
+
import { setContext } from "svelte"
|
|
8
14
|
import { writable } from "svelte/store"
|
|
9
15
|
|
|
10
16
|
import wsx from "../wsx.js"
|
|
17
|
+
import { frameDelay } from "../internals.js"
|
|
11
18
|
|
|
12
19
|
const {
|
|
13
|
-
|
|
20
|
+
children,
|
|
21
|
+
cancelable = false,
|
|
14
22
|
animTime = "200ms"
|
|
15
23
|
} = $props()
|
|
16
24
|
|
|
17
|
-
let modalProps = $state(null)
|
|
18
25
|
let resolver = $state(null)
|
|
19
|
-
let
|
|
26
|
+
let shown = $state(false)
|
|
20
27
|
|
|
21
28
|
const close = (value) => {
|
|
22
29
|
resolver(value)
|
|
23
30
|
resolver = null
|
|
24
|
-
|
|
25
|
-
Component = null
|
|
26
|
-
// visible.checked = false
|
|
31
|
+
shown = false
|
|
27
32
|
if (topClose !== close) {
|
|
28
33
|
return
|
|
29
34
|
}
|
|
@@ -32,39 +37,35 @@
|
|
|
32
37
|
const closeToTop = (value) => {
|
|
33
38
|
topClose(value)
|
|
34
39
|
}
|
|
35
|
-
const cancel = () =>
|
|
40
|
+
const cancel = () => {
|
|
41
|
+
if (cancelable === false) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
close(null)
|
|
45
|
+
}
|
|
36
46
|
|
|
37
47
|
export const show = (props) => new Promise(
|
|
38
|
-
|
|
39
|
-
modalProps = props ?? {}
|
|
48
|
+
(resolve) => {
|
|
40
49
|
topClose = topClose ?? close
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
setTimeout(
|
|
44
|
-
() => resolver = resolve,
|
|
45
|
-
0
|
|
46
|
-
)
|
|
50
|
+
resolver = resolve
|
|
51
|
+
frameDelay(1, () => shown = true)
|
|
47
52
|
}
|
|
48
53
|
)
|
|
49
54
|
|
|
50
|
-
// let visible = null
|
|
51
55
|
const animationTime = writable(animTime)
|
|
52
56
|
const wind = $derived({
|
|
53
57
|
"@anim-time": $animationTime,
|
|
54
|
-
$show:
|
|
58
|
+
$show: shown === true,
|
|
55
59
|
})
|
|
56
|
-
|
|
57
|
-
setContext(
|
|
60
|
+
setContext(modalAnimTimeSymbol, animationTime)
|
|
61
|
+
setContext(modalContextSymbol, { close, closeToTop })
|
|
58
62
|
</script>
|
|
59
63
|
|
|
60
64
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
61
65
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
66
|
+
<!-- svelte-ignore a11y_interactive_supports_focus -->
|
|
62
67
|
<ws-modal onclick={cancel} role="dialog" use:wsx={wind}>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{...modalProps}
|
|
67
|
-
{close}
|
|
68
|
-
{closeToTop}
|
|
69
|
-
/>
|
|
68
|
+
{#if resolver !== null}
|
|
69
|
+
{@render children()}
|
|
70
|
+
{/if}
|
|
70
71
|
</ws-modal>
|
package/src/layout/paper.svelte
CHANGED
|
@@ -16,17 +16,6 @@
|
|
|
16
16
|
...rest
|
|
17
17
|
} = $props()
|
|
18
18
|
|
|
19
|
-
// $: props = Object.entries($$restProps).reduce(
|
|
20
|
-
// (p, [key, value]) => {
|
|
21
|
-
// const [target, name] =
|
|
22
|
-
// (key.startsWith("l!") === true)
|
|
23
|
-
// ? [ p.layout, key.slice(2) ]
|
|
24
|
-
// : [ p.paper, key ]
|
|
25
|
-
// target[name] = value
|
|
26
|
-
// return p
|
|
27
|
-
// },
|
|
28
|
-
// { layout: {}, paper: {} }
|
|
29
|
-
// )
|
|
30
19
|
const props = $derived(
|
|
31
20
|
splitProps(rest, "l!")
|
|
32
21
|
)
|
package/src/props.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
export const filterProps = (props, filter) => Object.entries(props).reduce(
|
|
2
|
-
(p, [name, value]) => {
|
|
3
|
-
if (name.startsWith(filter) === true) {
|
|
4
|
-
p[name.slice(filter.length)] = value
|
|
5
|
-
}
|
|
6
|
-
return p
|
|
7
|
-
},
|
|
8
|
-
{}
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
export const splitProps = (props, ...splits) => Object.entries(props).reduce(
|
|
12
|
-
(groups, [name, value]) => {
|
|
13
|
-
for (const split of splits) {
|
|
14
|
-
if (name.startsWith(split) === true) {
|
|
15
|
-
groups[split] = groups[split] ?? {}
|
|
16
|
-
groups[split][name.slice(split.length)] = value
|
|
17
|
-
return groups
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
groups.rest[name] = value
|
|
21
|
-
return groups
|
|
22
|
-
},
|
|
23
|
-
{ rest: {} }
|
|
24
|
-
)
|
|
1
|
+
export const filterProps = (props, filter) => Object.entries(props).reduce(
|
|
2
|
+
(p, [name, value]) => {
|
|
3
|
+
if (name.startsWith(filter) === true) {
|
|
4
|
+
p[name.slice(filter.length)] = value
|
|
5
|
+
}
|
|
6
|
+
return p
|
|
7
|
+
},
|
|
8
|
+
{}
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
export const splitProps = (props, ...splits) => Object.entries(props).reduce(
|
|
12
|
+
(groups, [name, value]) => {
|
|
13
|
+
for (const split of splits) {
|
|
14
|
+
if (name.startsWith(split) === true) {
|
|
15
|
+
groups[split] = groups[split] ?? {}
|
|
16
|
+
groups[split][name.slice(split.length)] = value
|
|
17
|
+
return groups
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
groups.rest[name] = value
|
|
21
|
+
return groups
|
|
22
|
+
},
|
|
23
|
+
{ rest: {} }
|
|
24
|
+
)
|
package/src/routing/route.svelte
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { onMount, getContext } from "svelte"
|
|
2
2
|
import { writable, derived } from "svelte/store"
|
|
3
3
|
|
|
4
|
-
import { hash } from "../hash.
|
|
4
|
+
import { hash } from "../hash.js"
|
|
5
5
|
|
|
6
6
|
export const route = derived(
|
|
7
7
|
hash,
|
|
@@ -15,12 +15,6 @@ export const route = derived(
|
|
|
15
15
|
route.set = (path) => {
|
|
16
16
|
hash.set(path)
|
|
17
17
|
}
|
|
18
|
-
// export const route = $derived(
|
|
19
|
-
// hash.startsWith("/") === false ? `/${hash}` : hash
|
|
20
|
-
// )
|
|
21
|
-
// $effect(
|
|
22
|
-
// () => hash = route
|
|
23
|
-
// )
|
|
24
18
|
|
|
25
19
|
export const ctx = {
|
|
26
20
|
router: Symbol("Router Context"),
|
package/src/wind.js
ADDED
package/src/wsx.js
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<svelte:options immutable />
|
|
2
|
-
|
|
3
|
-
<script>
|
|
4
|
-
import Spinner from "../spinner/hexagon-spinner.svelte"
|
|
5
|
-
export let source = null
|
|
6
|
-
export let message = "Loading"
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
{#if source !== null}
|
|
10
|
-
{#await source}
|
|
11
|
-
<slot name="loading">
|
|
12
|
-
<ws-flex ws-x="[fl-center]">
|
|
13
|
-
<span>{message}</span>
|
|
14
|
-
<Spinner size="100px" />
|
|
15
|
-
</ws-flex>
|
|
16
|
-
</slot>
|
|
17
|
-
{:then result}
|
|
18
|
-
<slot {result} />
|
|
19
|
-
{:catch error}
|
|
20
|
-
<slot name="error" {error} />
|
|
21
|
-
{/await}
|
|
22
|
-
{/if}
|