@poveste/app 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundled/app.css
CHANGED
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
/* Cells are placed with `order`, so without this Tab and a screen reader walk
|
|
125
125
|
them in slot order — the order they were recycled in, not the screen's.
|
|
126
126
|
Chromium only for now; elsewhere the rule is ignored. */
|
|
127
|
-
.poveste-story-variant-grid-cells[data-v-
|
|
127
|
+
.poveste-story-variant-grid-cells[data-v-5f7bc1e1] {
|
|
128
128
|
reading-flow: grid-order;
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
|
|
|
2
2
|
import StoryVariantGrid_vue_vue_type_script_setup_true_lang_default from "./StoryVariantGrid.vue_vue_type_script_setup_true_lang.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/app/components/story/StoryVariantGrid.vue
|
|
5
|
-
var StoryVariantGrid_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGrid_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var StoryVariantGrid_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGrid_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-5f7bc1e1"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { StoryVariantGrid_default as default };
|
package/dist/bundled/components/story/StoryVariantGrid.vue_vue_type_script_setup_true_lang.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useStoryStore } from "../../stores/story.js";
|
|
2
2
|
import { assignSlots, trimSlots } from "../../util/grid-slots.js";
|
|
3
3
|
import StoryVariantGridItem_default from "./StoryVariantGridItem.js";
|
|
4
|
-
import { useResizeObserver } from "@poveste/vendors/vue-use";
|
|
4
|
+
import { useDebounceFn, useResizeObserver } from "@poveste/vendors/vue-use";
|
|
5
5
|
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, defineComponent, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, watch } from "@poveste/vendors/vue";
|
|
6
6
|
//#region src/app/components/story/StoryVariantGrid.vue?vue&type=script&setup=true&lang.ts
|
|
7
7
|
var _hoisted_1 = { class: "poveste-story-variant-grid flex flex-col items-stretch h-full __poveste-pane-shadow-from-right" };
|
|
@@ -9,6 +9,8 @@ var _hoisted_2 = { class: "flex w-0 flex-1 mx-4" };
|
|
|
9
9
|
var gap = 16;
|
|
10
10
|
var overscanRows = 2;
|
|
11
11
|
var initialCount = 10;
|
|
12
|
+
var FAST_PX_PER_MS = 8;
|
|
13
|
+
var FAST_REFRESH_MS = 150;
|
|
12
14
|
var TRIM_DELAY = 2e3;
|
|
13
15
|
var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
14
16
|
__name: "StoryVariantGrid",
|
|
@@ -35,6 +37,23 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
35
37
|
scrollTop.value = el.value.scrollTop;
|
|
36
38
|
viewportHeight.value = el.value.clientHeight;
|
|
37
39
|
}
|
|
40
|
+
let lastScrollTop = 0;
|
|
41
|
+
let lastScrollTime = 0;
|
|
42
|
+
let lastWindowUpdate = 0;
|
|
43
|
+
const settleWindow = useDebounceFn(updateWindow, 120);
|
|
44
|
+
function onScroll() {
|
|
45
|
+
const now = performance.now();
|
|
46
|
+
const top = el.value?.scrollTop ?? 0;
|
|
47
|
+
const dt = now - lastScrollTime;
|
|
48
|
+
const velocity = dt > 0 ? Math.abs(top - lastScrollTop) / dt : 0;
|
|
49
|
+
lastScrollTop = top;
|
|
50
|
+
lastScrollTime = now;
|
|
51
|
+
if (velocity <= FAST_PX_PER_MS || now - lastWindowUpdate >= FAST_REFRESH_MS) {
|
|
52
|
+
updateWindow();
|
|
53
|
+
lastWindowUpdate = now;
|
|
54
|
+
}
|
|
55
|
+
settleWindow();
|
|
56
|
+
}
|
|
38
57
|
function onItemResize(_w, h) {
|
|
39
58
|
if (maxItemHeight.value < h) {
|
|
40
59
|
maxItemHeight.value = h;
|
|
@@ -91,6 +110,7 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
91
110
|
}, { immediate: true });
|
|
92
111
|
onBeforeUnmount(() => {
|
|
93
112
|
clearTimeout(trimTimer);
|
|
113
|
+
settleWindow.cancel();
|
|
94
114
|
});
|
|
95
115
|
const totalHeight = computed(() => measured.value ? rowCount.value * rowHeight.value - gap : void 0);
|
|
96
116
|
const offsetY = computed(() => measured.value ? startIndex.value / columnCount.value * rowHeight.value : 0);
|
|
@@ -111,7 +131,7 @@ var StoryVariantGrid_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
|
|
|
111
131
|
ref_key: "el",
|
|
112
132
|
ref: el,
|
|
113
133
|
class: "overflow-y-auto flex flex-1",
|
|
114
|
-
onScroll: _cache[0] || (_cache[0] = ($event) =>
|
|
134
|
+
onScroll: _cache[0] || (_cache[0] = ($event) => onScroll())
|
|
115
135
|
}, [createElementVNode("div", _hoisted_2, [createElementVNode("div", {
|
|
116
136
|
class: "m-auto",
|
|
117
137
|
style: normalizeStyle({ minHeight: totalHeight.value != null ? `${totalHeight.value}px` : void 0 })
|
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poveste/app",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "Pre-bundled UI for Poveste",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
|
+
"homepage": "https://poveste.dev",
|
|
10
11
|
"repository": {
|
|
11
12
|
"url": "https://github.com/poveste-dev/poveste.git",
|
|
12
13
|
"type": "git",
|
|
13
14
|
"directory": "packages/poveste-app"
|
|
14
15
|
},
|
|
16
|
+
"bugs": "https://github.com/poveste-dev/poveste/issues",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"poveste",
|
|
19
|
+
"ui"
|
|
20
|
+
],
|
|
15
21
|
"publishConfig": {
|
|
16
22
|
"access": "public"
|
|
17
23
|
},
|
|
@@ -27,13 +33,16 @@
|
|
|
27
33
|
"dist",
|
|
28
34
|
"src"
|
|
29
35
|
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
38
|
+
},
|
|
30
39
|
"dependencies": {
|
|
31
40
|
"@fontsource/noto-sans-display": "^5.3.0",
|
|
32
41
|
"fuse.js": "^7.0.0",
|
|
33
42
|
"shiki": "^3.0.0",
|
|
34
|
-
"@poveste/controls": "^0.
|
|
35
|
-
"@poveste/
|
|
36
|
-
"@poveste/
|
|
43
|
+
"@poveste/controls": "^0.7.0",
|
|
44
|
+
"@poveste/vendors": "^0.7.0",
|
|
45
|
+
"@poveste/shared": "^0.7.0"
|
|
37
46
|
},
|
|
38
47
|
"devDependencies": {
|
|
39
48
|
"@iconify-json/carbon": "^1.2.25",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { Slot } from '../../util/grid-slots'
|
|
3
|
-
import { useResizeObserver } from '@vueuse/core'
|
|
3
|
+
import { useDebounceFn, useResizeObserver } from '@vueuse/core'
|
|
4
4
|
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
5
5
|
import { useStoryStore } from '../../stores/story'
|
|
6
6
|
import { assignSlots, trimSlots } from '../../util/grid-slots'
|
|
@@ -55,6 +55,43 @@ function updateWindow() {
|
|
|
55
55
|
viewportHeight.value = el.value.clientHeight
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// A window shift retargets a row of sandbox iframes, and each retarget re-renders
|
|
59
|
+
// a story — fine while reading, ruinous while flicking a 1000-cell grid, which
|
|
60
|
+
// would render every row it flies past (#283). So the window follows a slow
|
|
61
|
+
// scroll promptly but skips most events during a fast flick. It is not frozen
|
|
62
|
+
// solid though: a bounded refresh keeps it tracking the scroller so a sustained
|
|
63
|
+
// fast drag still shows cells instead of a blank band, and the final window
|
|
64
|
+
// lands on settle. Resize/mount call `updateWindow` directly — not the churn path.
|
|
65
|
+
//
|
|
66
|
+
// The threshold sits above an ordinary mouse-wheel notch (a few px/ms) so plain
|
|
67
|
+
// reading takes the prompt path; only a genuine fling defers.
|
|
68
|
+
const FAST_PX_PER_MS = 8
|
|
69
|
+
// Cap on how long the window may lag the scroller during a fast flick: at most
|
|
70
|
+
// one retarget per this interval, versus one per row on the prompt path.
|
|
71
|
+
const FAST_REFRESH_MS = 150
|
|
72
|
+
let lastScrollTop = 0
|
|
73
|
+
let lastScrollTime = 0
|
|
74
|
+
let lastWindowUpdate = 0
|
|
75
|
+
|
|
76
|
+
// Lands the final window shortly after scrolling stops, whatever the speed was —
|
|
77
|
+
// this is what fills the tail of a fast scroll back in.
|
|
78
|
+
const settleWindow = useDebounceFn(updateWindow, 120)
|
|
79
|
+
|
|
80
|
+
function onScroll() {
|
|
81
|
+
const now = performance.now()
|
|
82
|
+
const top = el.value?.scrollTop ?? 0
|
|
83
|
+
const dt = now - lastScrollTime
|
|
84
|
+
const velocity = dt > 0 ? Math.abs(top - lastScrollTop) / dt : 0
|
|
85
|
+
lastScrollTop = top
|
|
86
|
+
lastScrollTime = now
|
|
87
|
+
|
|
88
|
+
if (velocity <= FAST_PX_PER_MS || now - lastWindowUpdate >= FAST_REFRESH_MS) {
|
|
89
|
+
updateWindow()
|
|
90
|
+
lastWindowUpdate = now
|
|
91
|
+
}
|
|
92
|
+
settleWindow()
|
|
93
|
+
}
|
|
94
|
+
|
|
58
95
|
// The reported width is ignored: `columnCount` is what CSS lays out, so it is
|
|
59
96
|
// the authority on how many items sit in a row.
|
|
60
97
|
function onItemResize(_w: number, h: number) {
|
|
@@ -153,6 +190,8 @@ watch(visibleVariants, (visible) => {
|
|
|
153
190
|
|
|
154
191
|
onBeforeUnmount(() => {
|
|
155
192
|
clearTimeout(trimTimer)
|
|
193
|
+
// Drop any settle still pending, so it cannot fire updateWindow after teardown.
|
|
194
|
+
settleWindow.cancel()
|
|
156
195
|
})
|
|
157
196
|
|
|
158
197
|
// The spacer holds the full scroll extent; the grid is translated into place
|
|
@@ -185,7 +224,7 @@ watch(() => storyStore.currentVariant, (variant) => {
|
|
|
185
224
|
<div
|
|
186
225
|
ref="el"
|
|
187
226
|
class="overflow-y-auto flex flex-1"
|
|
188
|
-
@scroll="
|
|
227
|
+
@scroll="onScroll()"
|
|
189
228
|
>
|
|
190
229
|
<div class="flex w-0 flex-1 mx-4">
|
|
191
230
|
<div
|