@axel669/zephyr 0.5.5 → 1.0.0-beta.1
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 +48 -42
- package/readme.md +0 -44
- package/src/changed.svelte.js +23 -0
- package/src/component/adorn.svelte +9 -0
- package/src/component/alert.svelte +32 -0
- package/src/component/application.svelte +17 -0
- package/src/component/async-button.svelte +53 -0
- package/src/component/avatar.svelte +15 -0
- package/src/component/badge.svelte +7 -0
- package/src/component/button.svelte +7 -0
- package/src/component/chip.svelte +10 -0
- package/src/component/circle-spinner.svelte +6 -0
- package/src/component/confirm.svelte +40 -0
- package/src/component/control-label.svelte +41 -0
- package/src/component/data-table.svelte +227 -0
- package/src/component/details.svelte +22 -0
- package/src/component/dialog-element.svelte +36 -0
- package/src/component/dialog.svelte +43 -0
- package/src/component/drawer.svelte +20 -0
- package/src/component/flex.svelte +7 -0
- package/src/component/grid.svelte +7 -0
- package/src/component/hexagon-spinner.svelte +6 -0
- package/src/component/icon.svelte +7 -0
- package/src/component/link.svelte +11 -0
- package/src/component/modal.svelte +32 -0
- package/src/component/paper.svelte +33 -0
- package/src/component/popover.svelte +19 -0
- package/src/component/progress.svelte +6 -0
- package/src/component/prompt.svelte +58 -0
- package/src/{routing → component}/routing.svelte.js +4 -6
- package/src/component/screen.svelte +30 -0
- package/src/component/select.svelte +40 -0
- package/src/{async → component}/suspend.svelte +14 -8
- package/src/component/table.svelte +49 -0
- package/src/component/tabs.svelte +2 -0
- package/src/component/text.svelte +26 -0
- package/src/component/titlebar.svelte +23 -0
- package/src/component/toast.svelte +7 -0
- package/src/component/toaster.svelte +60 -0
- package/src/component/toggle-label.svelte +11 -0
- package/src/component/tooltip.svelte +11 -0
- package/src/main.js +40 -0
- package/src/ws.js +10 -0
- package/src/async/button.svelte +0 -41
- package/src/changed.js +0 -10
- package/src/composed/data-table/th.svelte +0 -61
- package/src/composed/data-table.svelte +0 -174
- package/src/composed/entry-button.svelte +0 -29
- package/src/composed/form.svelte +0 -60
- package/src/composed/table-functions.js +0 -15
- package/src/control/button.svelte +0 -39
- package/src/control/input.svelte +0 -103
- package/src/control/label.svelte +0 -49
- package/src/control/link.svelte +0 -47
- package/src/control/radio-group.svelte +0 -24
- package/src/control/select.svelte +0 -69
- package/src/control/tabs.svelte +0 -35
- package/src/control/toggle.svelte +0 -60
- package/src/custom-macros.js +0 -9
- package/src/data-display/avatar.svelte +0 -29
- package/src/data-display/badge.svelte +0 -16
- package/src/data-display/chip.svelte +0 -38
- package/src/data-display/details.svelte +0 -33
- package/src/data-display/popover.svelte +0 -28
- package/src/data-display/progress.svelte +0 -25
- package/src/data-display/table.svelte +0 -50
- package/src/data-display/tooltip.svelte +0 -19
- package/src/dialogs/alert.svelte +0 -41
- package/src/dialogs/confirm.svelte +0 -52
- package/src/dialogs/prompt.svelte +0 -67
- package/src/info/element-toaster.svelte +0 -110
- package/src/info/icon.svelte +0 -9
- package/src/info/titlebar.svelte +0 -40
- package/src/info/toast.svelte +0 -35
- package/src/info/toaster/message.svelte +0 -42
- package/src/info/toaster.svelte +0 -72
- package/src/layout/dialog.svelte +0 -25
- package/src/layout/drawer.svelte +0 -70
- package/src/layout/flex.svelte +0 -24
- package/src/layout/grid.svelte +0 -32
- package/src/layout/modal.svelte +0 -71
- package/src/layout/paper.svelte +0 -54
- package/src/layout/screen.svelte +0 -38
- package/src/spinner/circle-spinner.svelte +0 -18
- package/src/spinner/hexagon-spinner.svelte +0 -18
- package/src/text.svelte +0 -16
- package/src/wsx.js +0 -29
- /package/src/{routing → component}/route.svelte +0 -0
- /package/src/{routing → component}/title.svelte +0 -0
package/package.json
CHANGED
|
@@ -1,42 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@axel669/zephyr",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "src/
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"site/start": "wrangler
|
|
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.
|
|
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
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"rollup
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
}
|
|
42
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@axel669/zephyr",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/main.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"site/start": "wrangler dev",
|
|
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": "1.0.0-beta.1",
|
|
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
|
+
"fs-jetpack": "^5.1.0",
|
|
27
|
+
"markdown-it": "^14.1.1",
|
|
28
|
+
"marked": "^12.0.2",
|
|
29
|
+
"prism-svelte": "^0.5.0",
|
|
30
|
+
"prismjs": "^1.29.0",
|
|
31
|
+
"rollup": "^3.20.2",
|
|
32
|
+
"rollup-plugin-delete": "^2.0.0",
|
|
33
|
+
"rollup-plugin-svelte": "^7.2.2",
|
|
34
|
+
"yaml": "^2.8.3"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"src/"
|
|
38
|
+
],
|
|
39
|
+
"exports": {
|
|
40
|
+
".": "./src/main.js"
|
|
41
|
+
},
|
|
42
|
+
"imports": {
|
|
43
|
+
"#lib": "./src/main.js",
|
|
44
|
+
"#comp/*": "./docsite/comp/*.svelte",
|
|
45
|
+
"#state/*": "./docsite/state/*.js",
|
|
46
|
+
"#README": "./readme.md"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/readme.md
CHANGED
|
@@ -17,50 +17,6 @@ Zephyr can be installed through npm (or the variants like yarn, pnpm, etc).
|
|
|
17
17
|
npm install @axel669/zephyr
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
## Components
|
|
21
|
-
Components can be imported individually from the library for tree-shaking, or
|
|
22
|
-
the entire lib can imported at once, but I dunno how big that bundle will be.
|
|
23
|
-
Components can also take any windstorm macro as a prop, including custom macros,
|
|
24
|
-
using the same rules as the `wsx` covered in
|
|
25
|
-
[Functions](./docsite/docs/functions.md).
|
|
26
|
-
|
|
27
|
-
### Theming
|
|
28
|
-
Windstorm expects a theme to be defined on an ancestor of the html elements
|
|
29
|
-
that use it, and Zephyr does not automatically set the theme because it can
|
|
30
|
-
used anywhere in the page. This means the wsx action (or setting the ws-x
|
|
31
|
-
attribute directly) will be needed for components to look right. Any valid
|
|
32
|
-
Windstorm theme is usable, including custom ones.
|
|
33
|
-
|
|
34
|
-
### Example
|
|
35
|
-
```svelte
|
|
36
|
-
<script>
|
|
37
|
-
// individual import for tree shaking
|
|
38
|
-
import {
|
|
39
|
-
Button,
|
|
40
|
-
wsx
|
|
41
|
-
} from "@axel669/zephyr"
|
|
42
|
-
|
|
43
|
-
// bring the whole thing to keep it simple
|
|
44
|
-
import * as Wind from "@axel669/zephyr"
|
|
45
|
-
|
|
46
|
-
const theme = "dark"
|
|
47
|
-
const handler = () => {
|
|
48
|
-
console.log("button clicked!")
|
|
49
|
-
}
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<!-- the wsx action can be used to setup the ws-x needed for the body -->
|
|
53
|
-
<svelte:body use:wsx={{"@theme": theme, "@app": true}} />
|
|
54
|
-
|
|
55
|
-
<Button on:click={handler}>
|
|
56
|
-
I'm a button!
|
|
57
|
-
</Button>
|
|
58
|
-
|
|
59
|
-
<Wind.Button on:click={handler}>
|
|
60
|
-
I'm also button!
|
|
61
|
-
</Wind.Button>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
20
|
## Svelte Config
|
|
65
21
|
Zephyr does not output any css of its own, so no configuration is required to
|
|
66
22
|
make it styled as expected. For people using Svelte 4+ you will need to make
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
// }
|
|
11
|
+
|
|
12
|
+
export const track = (...args) => {
|
|
13
|
+
let called = false
|
|
14
|
+
const f = args[args.length - 1]
|
|
15
|
+
const params = args.slice(0, -1)
|
|
16
|
+
$effect(() => {
|
|
17
|
+
if (called === false) {
|
|
18
|
+
called = true
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
f(...params)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from "./button.svelte"
|
|
3
|
+
import Paper from "./paper.svelte"
|
|
4
|
+
import Text from "./text.svelte"
|
|
5
|
+
import Titlebar from "./titlebar.svelte"
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
message,
|
|
9
|
+
close,
|
|
10
|
+
color = "@primary",
|
|
11
|
+
} = $props()
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Paper ws="@color: {color}; variant.outline;">
|
|
15
|
+
{#snippet header()}
|
|
16
|
+
<Titlebar ws="@color: {color};">
|
|
17
|
+
<Text header>
|
|
18
|
+
Alert
|
|
19
|
+
</Text>
|
|
20
|
+
</Titlebar>
|
|
21
|
+
{/snippet}
|
|
22
|
+
|
|
23
|
+
<Text ws="p: 8px;">
|
|
24
|
+
{message}
|
|
25
|
+
</Text>
|
|
26
|
+
|
|
27
|
+
{#snippet footer()}
|
|
28
|
+
<Button ws="@color: @success;" onclick={() => close(true)}>
|
|
29
|
+
OK
|
|
30
|
+
</Button>
|
|
31
|
+
{/snippet}
|
|
32
|
+
</Paper>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Dialog from "./dialog.svelte"
|
|
3
|
+
import Toaster from "./toaster.svelte"
|
|
4
|
+
import { wsAttr } from "../ws.js"
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
baseline = "",
|
|
8
|
+
theme = "tron",
|
|
9
|
+
children,
|
|
10
|
+
} = $props()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<svelte:body use:wsAttr={`#theme.${theme}; ${baseline}`} />
|
|
14
|
+
|
|
15
|
+
<Toaster />
|
|
16
|
+
<Dialog />
|
|
17
|
+
{@render children?.()}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { ws } from "../ws.js"
|
|
3
|
+
|
|
4
|
+
ws.component("ze-async-button")`
|
|
5
|
+
disp: inline-grid;
|
|
6
|
+
pos.rel;
|
|
7
|
+
`
|
|
8
|
+
|
|
9
|
+
ws.macro("async.button.spinner")`
|
|
10
|
+
@size: 100%;
|
|
11
|
+
pos.abs;
|
|
12
|
+
x: 50%;
|
|
13
|
+
y: 0px;
|
|
14
|
+
tf: translateX(-50%);
|
|
15
|
+
h: 100%;
|
|
16
|
+
`
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import Button from "./button.svelte"
|
|
21
|
+
import CircleSpinner from "./circle-spinner.svelte"
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
onclick,
|
|
25
|
+
onresolve,
|
|
26
|
+
hideSpinner = false,
|
|
27
|
+
children,
|
|
28
|
+
disabled,
|
|
29
|
+
spinnerWS = "",
|
|
30
|
+
...props
|
|
31
|
+
} = $props()
|
|
32
|
+
|
|
33
|
+
let waiting = $state(false)
|
|
34
|
+
const handler = async (e) => {
|
|
35
|
+
waiting = true
|
|
36
|
+
const value = await onclick?.(e)
|
|
37
|
+
waiting = false
|
|
38
|
+
onresolve?.(value)
|
|
39
|
+
}
|
|
40
|
+
const dis = $derived(
|
|
41
|
+
disabled === true
|
|
42
|
+
|| waiting === true
|
|
43
|
+
)
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<ze-async-button>
|
|
47
|
+
<Button {...props} onclick={handler} disabled={dis}>
|
|
48
|
+
{@render children?.()}
|
|
49
|
+
</Button>
|
|
50
|
+
{#if waiting === true && hideSpinner === false}
|
|
51
|
+
<CircleSpinner ws="async.button.spinner; {spinnerWS}" />
|
|
52
|
+
{/if}
|
|
53
|
+
</ze-async-button>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
const { ws, image, type = "image/png", text, children, ...rest } = $props()
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<ws-avatar data-ws={ws} {...rest}>
|
|
6
|
+
{#if children !== undefined}
|
|
7
|
+
{@render children()}
|
|
8
|
+
{:else if text !== undefined}
|
|
9
|
+
{text}
|
|
10
|
+
{:else}
|
|
11
|
+
<!-- svelte-ignore a11y_missing_attribute -->
|
|
12
|
+
<!-- svelte-ignore element_invalid_self_closing_tag -->
|
|
13
|
+
<object data={image} {type} />
|
|
14
|
+
{/if}
|
|
15
|
+
</ws-avatar>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from "./button.svelte"
|
|
3
|
+
import Grid from "./grid.svelte"
|
|
4
|
+
import Paper from "./paper.svelte"
|
|
5
|
+
import Text from "./text.svelte"
|
|
6
|
+
import Titlebar from "./titlebar.svelte"
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
message,
|
|
10
|
+
close,
|
|
11
|
+
color = "@primary",
|
|
12
|
+
okText = "OK",
|
|
13
|
+
cancelText = "Cancel",
|
|
14
|
+
} = $props()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<Paper ws="@color: {color}; variant.outline;">
|
|
18
|
+
{#snippet header()}
|
|
19
|
+
<Titlebar ws="@color: {color};">
|
|
20
|
+
<Text header>
|
|
21
|
+
Confirm
|
|
22
|
+
</Text>
|
|
23
|
+
</Titlebar>
|
|
24
|
+
{/snippet}
|
|
25
|
+
|
|
26
|
+
<Text ws="p: 8px;">
|
|
27
|
+
{message}
|
|
28
|
+
</Text>
|
|
29
|
+
|
|
30
|
+
{#snippet footer()}
|
|
31
|
+
<Grid ws="gr.cols: 1fr 1fr; p: 0px;">
|
|
32
|
+
<Button ws="@color: @error;" onclick={() => close(false)}>
|
|
33
|
+
{cancelText}
|
|
34
|
+
</Button>
|
|
35
|
+
<Button ws="@color: @success;" onclick={() => close(true)}>
|
|
36
|
+
{okText}
|
|
37
|
+
</Button>
|
|
38
|
+
</Grid>
|
|
39
|
+
{/snippet}
|
|
40
|
+
</Paper>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
const {
|
|
3
|
+
ws,
|
|
4
|
+
labelWS,
|
|
5
|
+
label,
|
|
6
|
+
children,
|
|
7
|
+
start,
|
|
8
|
+
end,
|
|
9
|
+
extra,
|
|
10
|
+
...rest
|
|
11
|
+
} = $props()
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<label control data-ws={ws ?? ""} {...rest}>
|
|
15
|
+
{#if label}
|
|
16
|
+
<ws-text label-text data-ws={labelWS}>
|
|
17
|
+
{#if typeof label !== "function"}
|
|
18
|
+
{label}
|
|
19
|
+
{:else}
|
|
20
|
+
{@render label()}
|
|
21
|
+
{/if}
|
|
22
|
+
</ws-text>
|
|
23
|
+
{/if}
|
|
24
|
+
{@render children()}
|
|
25
|
+
|
|
26
|
+
{#if start}
|
|
27
|
+
<ze-input-start data-ws="area: start; grid;">
|
|
28
|
+
{@render start()}
|
|
29
|
+
</ze-input-start>
|
|
30
|
+
{/if}
|
|
31
|
+
{#if end}
|
|
32
|
+
<ze-input-end data-ws="area: end; grid;">
|
|
33
|
+
{@render end()}
|
|
34
|
+
</ze-input-end>
|
|
35
|
+
{/if}
|
|
36
|
+
{#if extra}
|
|
37
|
+
<ze-input-extra data-ws="area: extra; grid;">
|
|
38
|
+
{@render extra()}
|
|
39
|
+
</ze-input-extra>
|
|
40
|
+
{/if}
|
|
41
|
+
</label>
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { ws as wind } from "../ws.js"
|
|
3
|
+
|
|
4
|
+
wind.component("ze-data-table")`
|
|
5
|
+
pos.rel;
|
|
6
|
+
grid;
|
|
7
|
+
gr.cols: 1fr;
|
|
8
|
+
gr.rows: 1fr min-content;
|
|
9
|
+
p: 0px;
|
|
10
|
+
h: 100%;
|
|
11
|
+
w: 100%;
|
|
12
|
+
h.max: 100%;
|
|
13
|
+
w.max: 100%;
|
|
14
|
+
`
|
|
15
|
+
wind.component("ze-data-scroller")`
|
|
16
|
+
pos.rel;
|
|
17
|
+
over: auto;
|
|
18
|
+
! &::before {
|
|
19
|
+
*content: "";
|
|
20
|
+
pos.abs;
|
|
21
|
+
w: 1px;
|
|
22
|
+
h: @h;
|
|
23
|
+
z: -1;
|
|
24
|
+
}
|
|
25
|
+
`
|
|
26
|
+
wind.component("ze-fake-scroll")`
|
|
27
|
+
disp: block;
|
|
28
|
+
w: 100%;
|
|
29
|
+
h: @h;
|
|
30
|
+
pos.stick;
|
|
31
|
+
y: 0px;
|
|
32
|
+
over: hidden;
|
|
33
|
+
`
|
|
34
|
+
wind.component("ze-data-footer")`
|
|
35
|
+
pos: rel;
|
|
36
|
+
grid;
|
|
37
|
+
`
|
|
38
|
+
|
|
39
|
+
const itemRange = (info) => {
|
|
40
|
+
const {
|
|
41
|
+
scrollPos,
|
|
42
|
+
scrollMax,
|
|
43
|
+
rowSize,
|
|
44
|
+
length,
|
|
45
|
+
containerHeight,
|
|
46
|
+
} = info
|
|
47
|
+
if (scrollMax === null) {
|
|
48
|
+
return [0, 0]
|
|
49
|
+
}
|
|
50
|
+
const displayed = Math.ceil(containerHeight / rowSize) - 1
|
|
51
|
+
const itemPos = Math.floor(
|
|
52
|
+
(scrollPos / scrollMax) * (length - displayed)
|
|
53
|
+
)
|
|
54
|
+
return [
|
|
55
|
+
itemPos - 1,
|
|
56
|
+
itemPos + displayed + 1,
|
|
57
|
+
displayed + 2,
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
const emptyRow = Symbol("empty row")
|
|
61
|
+
const nullRow = Symbol("null row")
|
|
62
|
+
|
|
63
|
+
const sliceData = (data, range) => {
|
|
64
|
+
const displayed = data.slice(
|
|
65
|
+
Math.max(range[0], 0),
|
|
66
|
+
range[1]
|
|
67
|
+
)
|
|
68
|
+
if (range[0] === -1) {
|
|
69
|
+
return [emptyRow, ...displayed]
|
|
70
|
+
}
|
|
71
|
+
if (displayed.length < range[2]) {
|
|
72
|
+
return [
|
|
73
|
+
...displayed,
|
|
74
|
+
...Array.from(
|
|
75
|
+
{ length: range[2] - displayed.length },
|
|
76
|
+
() => nullRow
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
return displayed
|
|
81
|
+
}
|
|
82
|
+
</script>
|
|
83
|
+
<script>
|
|
84
|
+
import { onMount } from "svelte"
|
|
85
|
+
import { on } from "svelte/events"
|
|
86
|
+
|
|
87
|
+
const {
|
|
88
|
+
rowSize = 30,
|
|
89
|
+
headerSize = rowSize,
|
|
90
|
+
header = Header,
|
|
91
|
+
row = Row,
|
|
92
|
+
ws = "",
|
|
93
|
+
data,
|
|
94
|
+
footer = Footer,
|
|
95
|
+
} = $props()
|
|
96
|
+
|
|
97
|
+
const keys = $derived(
|
|
98
|
+
Object.keys(data?.[0] ?? {})
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
const itemsHeight = $derived(
|
|
102
|
+
rowSize * data.length
|
|
103
|
+
)
|
|
104
|
+
const tableHeight = $derived(itemsHeight + headerSize)
|
|
105
|
+
|
|
106
|
+
let scrollPos = $state(0)
|
|
107
|
+
let scrollMax = $state(null)
|
|
108
|
+
let containerHeight = $state(null)
|
|
109
|
+
const scrollHandler = (evt) => {
|
|
110
|
+
scrollPos = container.scrollTop
|
|
111
|
+
}
|
|
112
|
+
const range = $derived(
|
|
113
|
+
itemRange({
|
|
114
|
+
scrollPos,
|
|
115
|
+
scrollMax,
|
|
116
|
+
containerHeight,
|
|
117
|
+
rowSize,
|
|
118
|
+
length: data.length,
|
|
119
|
+
})
|
|
120
|
+
)
|
|
121
|
+
let container = $state(null)
|
|
122
|
+
|
|
123
|
+
$inspect(scrollMax, containerHeight)
|
|
124
|
+
|
|
125
|
+
onMount(() => {
|
|
126
|
+
containerHeight = container.clientHeight
|
|
127
|
+
scrollMax = container.scrollHeight - containerHeight
|
|
128
|
+
on(container, "scroll", scrollHandler, { passive: true })
|
|
129
|
+
const observer = new ResizeObserver(
|
|
130
|
+
() => {
|
|
131
|
+
containerHeight = container.clientHeight
|
|
132
|
+
scrollMax = container.scrollHeight - containerHeight
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
observer.observe(container)
|
|
136
|
+
return () => observer.unobserve(container)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const displayed = $derived(range[2])
|
|
140
|
+
const displayedRows = $derived(
|
|
141
|
+
sliceData(data, range)
|
|
142
|
+
)
|
|
143
|
+
const show = $derived({
|
|
144
|
+
start: Math.max(1, range[0] + 2),
|
|
145
|
+
end: Math.min(data.length, range[1] - 1),
|
|
146
|
+
total: data.length,
|
|
147
|
+
})
|
|
148
|
+
const correction = $derived(
|
|
149
|
+
(data.length - displayed) * rowSize
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
const itemOffset = $derived(
|
|
153
|
+
range[0] * rowSize - scrollPos
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
const containerWS = $derived(
|
|
157
|
+
wind.x({
|
|
158
|
+
"! & :where(thead, tbody)": {
|
|
159
|
+
w: "100%",
|
|
160
|
+
},
|
|
161
|
+
"! & thead > tr": {
|
|
162
|
+
h: "@header",
|
|
163
|
+
z: "+5",
|
|
164
|
+
"pos.rel": true,
|
|
165
|
+
},
|
|
166
|
+
"! & tbody > tr": {
|
|
167
|
+
h: "@row",
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
)
|
|
171
|
+
</script>
|
|
172
|
+
|
|
173
|
+
{#snippet Header(keys)}
|
|
174
|
+
<tr>
|
|
175
|
+
{#each keys as key}
|
|
176
|
+
<th>{key}</th>
|
|
177
|
+
{/each}
|
|
178
|
+
</tr>
|
|
179
|
+
{/snippet}
|
|
180
|
+
{#snippet Row(item, keys)}
|
|
181
|
+
<tr>
|
|
182
|
+
{#each keys as key}
|
|
183
|
+
<td>{item[key]}</td>
|
|
184
|
+
{/each}
|
|
185
|
+
</tr>
|
|
186
|
+
{/snippet}
|
|
187
|
+
{#snippet Footer(show, displayed)}
|
|
188
|
+
<div data-ws="flex; fl.cn; h.min: 32px;">
|
|
189
|
+
<div>
|
|
190
|
+
Showing: {show.start} - {show.end} of {show.total}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
{/snippet}
|
|
194
|
+
|
|
195
|
+
<ze-data-table data-ws={containerWS}>
|
|
196
|
+
<ze-data-scroller
|
|
197
|
+
bind:this={container}
|
|
198
|
+
data-ws="@h: {tableHeight}px; @header: {headerSize}px; @row: {rowSize}px;"
|
|
199
|
+
>
|
|
200
|
+
<ze-fake-scroll data-ws="@h: {containerHeight}px;">
|
|
201
|
+
<table data-ws="w: 100%; {ws}">
|
|
202
|
+
<thead>
|
|
203
|
+
{#if data?.length > 0}
|
|
204
|
+
{@render header(keys)}
|
|
205
|
+
{:else}
|
|
206
|
+
<tr>
|
|
207
|
+
<td>N/A</td>
|
|
208
|
+
</tr>
|
|
209
|
+
{/if}
|
|
210
|
+
</thead>
|
|
211
|
+
<tbody data-ws="tf: translateY({itemOffset}px);">
|
|
212
|
+
{#each displayedRows as item}
|
|
213
|
+
{@render row(item, keys)}
|
|
214
|
+
{:else}
|
|
215
|
+
<tr>
|
|
216
|
+
<td>No Items</td>
|
|
217
|
+
</tr>
|
|
218
|
+
{/each}
|
|
219
|
+
</tbody>
|
|
220
|
+
</table>
|
|
221
|
+
</ze-fake-scroll>
|
|
222
|
+
</ze-data-scroller>
|
|
223
|
+
|
|
224
|
+
<ze-data-footer>
|
|
225
|
+
{@render footer(show, displayedRows)}
|
|
226
|
+
</ze-data-footer>
|
|
227
|
+
</ze-data-table>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
let {
|
|
3
|
+
open = $bindable(false),
|
|
4
|
+
ws,
|
|
5
|
+
summaryWS,
|
|
6
|
+
children,
|
|
7
|
+
label = "",
|
|
8
|
+
summary,
|
|
9
|
+
...rest
|
|
10
|
+
} = $props()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<details data-ws={ws ?? ""} bind:open {...rest}>
|
|
14
|
+
<summary data-ws={summaryWS}>
|
|
15
|
+
{#if summary !== undefined}
|
|
16
|
+
{@render summary()}
|
|
17
|
+
{:else}
|
|
18
|
+
{label}
|
|
19
|
+
{/if}
|
|
20
|
+
</summary>
|
|
21
|
+
{@render children()}
|
|
22
|
+
</details>
|